Ref: https://gcc.gnu.org/onlinedocs/libquadmath/Code:jake@Jake-VM:~$ cat > test.c #include <stdio.h> #include <quadmath.h> int main(void) { __float128 x = M_PIq; char buf[64]; quadmath_snprintf(buf, sizeof(buf), "%Qg", x); puts(buf); return 0; } jake@Jake-VM:~$ gcc test.c -lquadmath jake@Jake-VM:~$ ./a.out 3.14159 jake@Jake-VM:~$
First off, sorry for the late reply. I was (and still am) on vacation.
Anyway, Epy, the code you have suggested works up until a certain point but after that, it starts printing wrong numbers. For the number 23230948.23452345345, it will print up to almost the last digit correctly, about the 16 or 17th digit, and then it will print incorrect numbers, thereby making the value wrong and unreliable. The source code is below as well as the output.
Code:#include <quadmath.h> #include <stdlib.h> #include <stdio.h> int main() { __float128 x = 23230948.23452345345; char sigdig[64]; quadmath_snprintf(sigdig, sizeof sigdig, "%.35Qf", x); printf("%s\n", sigdig); return 0; }
What's interesting is that if I try to print the same number under double, it prints just about all of the digits, and after the 17th digit, it stops printing regardless. Below is the source code for that, as well as the output:
Code:#include <quadmath.h> #include <stdlib.h> #include <stdio.h> int main() { __float128 x = 23230948.23452345345; double z = 23230948.23452345345; char sigdig[64]; quadmath_snprintf(sigdig, sizeof sigdig, "%.35Qf", x); printf("%s\n%.35f\n", sigdig, z); return 0; }
I think my takeaway is that minGW64 just can't handle long double, only up to double, 8 bytes (64 bits). Is there another compiler you can suggest that I could use with Code::Blocks that is made for Windows? Thanks for your help.
> it will print up to almost the last digit correctly, about the 16 or 17th digit,
You're mis-understanding how floating point numbers actually work.
Floating point isn't infinitely precise. The number of significant digits (those that are considered accurate) is tied to the number of bits stored in the mantissa of the floating point representation.
What Every Computer Scientist Should Know About Floating-Point Arithmetic
> __float128 x = 23230948.23452345345;
Your constant gets evaluated as a double (with 16 bits of precision) before being promoted to a __float128 (with whatever - 30-something bits of precision).
The result is, your x still only has 16 digits of precision.
You need to add an appropriate suffix to tell the compiler to evaluate the constant as a __float128 constant from the beginning.
Say perhaps
__float128 x = 23230948.23452345345q;
https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
If at first you don't succeed, try writing your phone number on the exam paper.
Actually, I do understand how the mantissa, sign bit, and exponent bits work in a floating point. However, I did forget the q because with normal floats (up until 64 bits), I never have to add the f at the end of the constant - it need only be in decimal format with a period and at least one zero or another digit after the decimal point.You're mis-understanding how floating point numbers actually work.
However, even after adding the q, it is still printing some garbage after all the zeros. Please see the attachment below:
You may understand what makes up a floating point, but as Salem said, you're misunderstanding how they work.
Only certain numbers are perfectly representable, all others get approximated. Copied from one of my own Fortran files:
You're showing much more than 33 digits, so what you're seeing is the rounding error in trying to represent your literal as a quad.Code:! float == 32 bits == 6 digits of precision ! double == 64 bits == 15 digits of precision ! long double == 80 bits == 18 digits of precision ! __float128 == 128 bits == 33 digits of precision
You can try to print the long double in hex to see if the computer is printing it out how you expect. floating point - Convert ieee 754 float to hex with c - printf - Stack Overflow may give you some ideas.
Also, some online calculators may help you see how that long value you entered should get represented in IEEE 754 format. http://cboard.cprogramming.com/cplusplus-programming/ This is one but not for 128, but it would be a good exercise to tinker with it.
Aah! I did know about the 6 digits of precision of float and the 15 digits of double, but I did not know about the 33 digits of precision of __float128. I guess because it's not as well documented yet because most people who write C programs don't use nearly that many digits of precision and therefore don't care to find out. I just wanted this to be clear. It is now and it has been resolved. Thanks for all of your help. Your time is much appreciated.
Just as a final tidbit on this subject, after a bit of testing, I found that __float128 is printing 34 digits accurately, double is printing 17 digits accurately, and float is printing 7 digits accurately.
Also, float seems to handle the numbers with or without the f at the end of the number but double prints junk if I place an f after the number. Below is the source code for finding the limits of the C data types on my computer and compiler. Hope these posts help other people as well.
Code:#include <quadmath.h> #include <stdlib.h> #include <stdio.h> int main() { __float128 a = 0.2345234534512079875620048770134538q; char sigdig[64]; double b = 0.23452345345120798; float c = 0.2345234f; quadmath_snprintf(sigdig, sizeof sigdig, "%.34Qf", a); printf("%s\n%.17f\n%.7f\n\n", sigdig, b, c); return 0; }