Thread: 128 bit (long double) printf not working

  1. #16
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Quote Originally Posted by AamirYousafi View Post
    Epy, I'm using Code::Blocks now. Initially, it was giving the same error. Then, in its Compiler and Linker settings, I added the libquadmath.a file, within the 'lib' folder of minGW64. Now it's not giving any compiler errors but as soon as the program runs, it crashes / freezes and exits from DOS. The source code is the same as I shared before:

    Code:
    #include <quadmath.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    int main()
    {
        __float128 x = 3.1415Q;
        int precision = 35;
        char sigdig[128];
        
        quadmath_snprintf(sigdig, sizeof sigdig, "%Qg", precision, x);
        printf("%s\n", sigdig);
        
        return 0;
    }
    You have too many arguments to quadmath_snprintf for your format string.

  2. #17
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    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:~$
    Ref: https://gcc.gnu.org/onlinedocs/libquadmath/

  3. #18
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    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;
    }

    128 bit (long double) printf not working-capture-png

    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;
    }

    128 bit (long double) printf not working-capture2-png

    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.

  4. #19
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > 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.

  5. #20
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    You're mis-understanding how floating point numbers actually work.
    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.

    However, even after adding the q, it is still printing some garbage after all the zeros. Please see the attachment below:

    128 bit (long double) printf not working-capture-png

  6. #21
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Quote Originally Posted by AamirYousafi View Post
    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.

    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:

    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'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.

  7. #22
    Registered User
    Join Date
    Dec 2015
    Posts
    112
    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.

  8. #23
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    Quote Originally Posted by Epy View Post
    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:

    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'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.
    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.

  9. #24
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    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;
    }

  10. #25
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Quote Originally Posted by AamirYousafi View Post
    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.
    The amount of sig digs depends on the number itself, for example 32-bit corresponds to 6-9 sig digs. I have the numbers I have because they are the minimums, i.e. the maximum amount of digits you can truly count on.

  11. #26
    Registered User
    Join Date
    Dec 2015
    Posts
    112
    Quote Originally Posted by AamirYousafi View Post
    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;
    }
    After this comment, you really should play entering different values on one of those online calcualtors and see how the precision varies.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 06-07-2015, 03:28 PM
  2. 'long long' type and printf() (on AIX 5.3)
    By alex5161 in forum C Programming
    Replies: 5
    Last Post: 12-16-2011, 04:05 PM
  3. number bigger than long long double
    By suryak in forum C Programming
    Replies: 9
    Last Post: 08-18-2011, 02:02 PM
  4. Replies: 1
    Last Post: 04-23-2011, 08:40 PM
  5. printf not working with long type
    By that_guy1 in forum C Programming
    Replies: 2
    Last Post: 10-15-2005, 05:37 PM

Tags for this Thread