Thread: 128 bit (long double) printf not working

  1. #1
    Registered User
    Join Date
    Jun 2016
    Posts
    14

    128 bit (long double) printf not working

    I have run the following code to see what my computer's byte size is for each data type:

    Code:
    #include <stdio.h>
    #include <limits.h>
    
    int main()
    {
        printf("The size of char in bytes is: %llu.", sizeof(char));
        printf("\nThe size of short in bytes is: %llu.", sizeof(short));
        printf("\nThe size of int in bytes is: %llu.", sizeof(int));
        printf("\nThe size of long in bytes is: %llu.", sizeof(long));
        printf("\nThe size of long long in bytes is: %llu.", sizeof(long long));
        printf("\nThe size of float in bytes is: %llu.", sizeof(float));
        printf("\nThe size of double in bytes is: %llu.", sizeof(double));
        printf("\nThe size of long double in bytes is: %llu.", sizeof(long double));
        
        return 0;
    }
    128 bit (long double) printf not working-capture-png

    However, when I try to use printf for long double, it always prints the same junk exponent value regardless of what the variable is set to in the program.

    Code:
    #include <stdio.h>
    
    int main()
    {
        long double x = 3.1415;
    
        printf("%Lg", x);
        
        return 0;
    }
    128 bit (long double) printf not working-capture1-png


    I have read on the internet forums that this is either a printf limitation or a compiler issue or some combination of these. I am using a MinGW GCC 6.1.0 compiler on a 64-bit Windows PC.

    How do I fix this? Do I need to get a different compiler or is there another C function that can print this 16-bit (or 20-bit) long double properly?
    Attached Images Attached Images 128 bit (long double) printf not working-capture-png 
    Last edited by AamirYousafi; 06-28-2016 at 02:57 PM.

  2. #2
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    GCC's long double is 80-bit extended precision format, not 128-bit like you're looking for. Look up libquadmath and __float128, that's what GCC uses for true 128-bit FP math.

  3. #3
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    I don't know if the compiler can infer it by itself, but you should use "3.1415L".

    Also, this:
    Quote Originally Posted by klickverbot-stackoverflow
    If you are using MinGW, the problem is that by default, MinGW uses the I/O resp. formatting functions from the Microsoft C runtime, which doesn't support 80 bit floating point numbers (long double == double in Microsoft land).

    However, MinGW also comes with a set of alternative implementations that do properly support long doubles. To use them, prefix the function names with __mingw_ (e.g. __mingw_printf). Depending on the nature of your project, you might also want to globally #define printf __mingw_printf or use -D__USE_MINGW_ANSI_STDIO (which enables the MinGW versions of all the printf-family functions).
    Last edited by GReaper; 06-28-2016 at 05:16 PM.
    Devoted my life to programming...

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Code:
    #include <stdio.h>
    #include <limits.h>
    
    int main()
    {
        printf("The size of char in bytes is: %zu.", sizeof(char));
        printf("\nThe size of short in bytes is: %zu.", sizeof(short));
        printf("\nThe size of int in bytes is: %zu.", sizeof(int));
        printf("\nThe size of long in bytes is: %zu.", sizeof(long));
        printf("\nThe size of long long in bytes is: %zu.", sizeof(long long));
        printf("\nThe size of float in bytes is: %zu.", sizeof(float));
        printf("\nThe size of double in bytes is: %zu.", sizeof(double));
        printf("\nThe size of long double in bytes is: %zu\n\n", sizeof(long double));
    
        long double x = 3.1415L;
        printf("%Lg\n", x);
        
        return 0;
    }
    Produces the following output on my machine (Linux using gcc-6.1.0):
    Code:
    The size of char in bytes is: 1.
    The size of short in bytes is: 2.
    The size of int in bytes is: 4.
    The size of long in bytes is: 8.
    The size of long long in bytes is: 8.
    The size of float in bytes is: 4.
    The size of double in bytes is: 8.
    The size of long double in bytes is: 16
    
    3.1415
    I would guess that the problem is the result of a difference between the C-runtime and your compiler. Have you tried compiling and running the programs with Microsoft C instead?

    By the way you really should be using the "%zu" format specifier to print the values returned by sizeof(). A size_t, the value returned by sizeof() is an implementation defined unsigned value, not a signed value.


    Jim

  5. #5
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    Epy, after reading some about the header quadmath.h (https://gcc.gnu.org/onlinedocs/lib.pdf), and confirming that my compiler had this file in its libraries, I used the following source code but it gave me a compiler error "undefined reference to `quadmath_snprintf'":

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



    GReaper, yes, I have tried appending "L", to no avail. In general, my compiler can infer these as when I write floats, I don't need to append "f" but I do need to write 3 as 3.0 if it's simply a constant and not the value of a variable if I want the compiler to see that constant as a float and not an integer.

    As for the quote you included, it's confusing and it doesn't seem to work. How do I use the minGW family of printf functions? Is there a header that needs to be included? I've tried it as is, including the <stdio.h> header and it does nothing. And as for the "-D ..." line, it causes a compiler error "[Error] expected unqualified-id before '-' token".




    jimblumberg, yes, I suspected it was the compiler issue and that's why I was asking whether there was another compiler I could install / use with Dev-C++ editor / program that would compile the long double in 16 bytes (128 bit). In regards Microsoft C, well, I have the following taken from another forum's resources page (C/C++ Resources - C and C++ - Codecall):

    Compilers


    So, which of these is it? Which one can I use with Dev-C++? Some of these, probably the Microsoft C, will not be for integration with my existing IDE - i.e. they will have their own IDE for use with the compiler.

    The "%zu" prints "zu" on my computer. For printf, unsigned long long integers, which is what my compiler recognizes sizeof() to be, the correct specifier is "%llu", as per resources like cppreference.com and others.
    Last edited by AamirYousafi; 06-29-2016 at 03:34 AM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by AamirYousafi
    yes, I have tried appending "L", to no avail. In general, my compiler can infer these as when I write floats, I don't need to append "f" but I do need to write 3 as 3.0 if it's simply a constant and not the value of a variable if I want the compiler to see that constant as a float and not an integer.
    Yeah, you should not need the L suffix for the constant since the double constant should be converted to a long double value in the initialisation.

    Quote Originally Posted by AamirYousafi
    As for the quote you included, it's confusing and it doesn't seem to work. How do I use the minGW family of printf functions? Is there a header that needs to be included? I've tried it as is, including the <stdio.h> header and it does nothing. And as for the "-D ..." line, it causes a compiler error "[Error] expected unqualified-id before '-' token".
    The -D__USE_MINGW_ANSI_STDIO is a compiler option, not code. You can make it code if you want to, i.e., by placing this before #include <stdio.h>:
    Code:
    #define __USE_MINGW_ANSI_STDIO
    But it would be better to pass -D__USE_MINGW_ANSI_STDIO as an option to the compiler, e.g., by editing the project options in your IDE, or by changing the makefile or other build script, or simply by adding the option when compiling at the command line.

    Quote Originally Posted by AamirYousafi
    The "%zu" prints "zu" on my computer. For printf, unsigned long long integers, which is what my compiler recognizes sizeof() to be, the correct specifier is "%llu", as per resources like cppreference.com and others.
    Yes, if size_t is an alias for unsigned long long, then indeed %llu is a correct format specifier, but size_t could be an alias for unsigned long or unsigned int instead. The point is that if you are compiling with respect to C99 or later (which is required for unsigned long long and %llu to be standard), you should use %zu instead, which is correct for size_t regardless of what is the underlying unsigned integer type. Unfortunately, pre-C99, both %zu and unsigned long long do not exist or are non-standard, so your best bet would be casting to unsigned long and using %lu.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Banned
    Join Date
    Oct 2014
    Location
    Home
    Posts
    135
    If you are a programming enthusiasts you could write one yourself that handles whatever the amount of digits you like.

  8. #8
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    laserlight, my compiler has no such option, except to the tune of "Support all ANSI standard C programs", which I have enabled just now, with no change.

    And as far as adding the line before the stdio.h include, that causes compilation errors within the stdio.h file.

    Using the code below, printf is at least displaying long double now but the amount is still not correct. As far as the unsigned long long, it is displaying it perfectly, right to its 8 byte (64-bit) limit. (The %llu is correct because if I use %u or %lu, the compiler displays a warning and the output is wrong.)

    Code:
    #include <stdio.h>
    #define printf __mingw_printf
    
    int main()
    {
        long double x = 23230948.23452345345;
        unsigned long long y = 18446744073709551615;
        
        printf("%.27Lg\n%llu", x, y);
        
        return 0;
    }



    Tien Nguyen, I would love to but while I may be an enthusiast, I'm still a novice / amateur so I will have to look for the easier solution - i.e. using another compiler that I can configure with my IDE / editor or somehow making quadmath.h work through minGW.

    Thanks all for your help. I'm loving this forum so far.

  9. #9
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    What version of Dev-C++ are you using?

    Have you tried some of the other format specifiers?

    Ie all of the following: "%f, %lf, %llf, %Lf".


    Jim

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by AamirYousafi
    my compiler has no such option, except to the tune of "Support all ANSI standard C programs", which I have enabled just now, with no change.
    You probably meant IDE rather than compiler. Look for a section marked "preprocessor definitions", or something like that. It may be a blank textbox for you to enter -D__USE_MINGW_ANSI_STDIO itself. It is not likely to be a checkbox since the IDE cannot anticipate all possible macros that you might want to define in this way.

    Quote Originally Posted by AamirYousafi
    And as far as adding the line before the stdio.h include, that causes compilation errors within the stdio.h file.
    What exactly did you try and what error messages did you get?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    laserlight, the line added before stdio.h inclusion was:

    Code:
    #define __USE_MINGW_ANSI_STDIO
    A tab of stdio.h opens up and gives these errors:

    Line Col
    190 27 [Error] #if with no expression
    531 65 [Error] operator '||' has no right operand
    604 27 [Error] #if with no expression
    793 65 [Error] operator '||' has no right operand
    49 27 [Error] #if with no expression
    In function 'int vswprintf(wchar_t*, size_t, const wchar_t*, char*)':
    25 64 [Error] 'vsnwprintf' was not declared in this scope



    jim, yes I have and it won't do much differently than the specifiers I was using - i.e. long double is still printing the wrong value while unsigned long long is printing perfectly.

  12. #12
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    you probably need to say something along the lines of

    Code:
    #define __USE_MINGW_ANSI_STDIO 1
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  13. #13
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Quote Originally Posted by AamirYousafi View Post
    Epy, after reading some about the header quadmath.h (https://gcc.gnu.org/onlinedocs/lib.pdf), and confirming that my compiler had this file in its libraries, I used the following source code but it gave me a compiler error "undefined reference to `quadmath_snprintf'"
    libquadmath has to be linked separately from the cstdlib math library. Add "-lquadmath" (or -l"C:\path\to\libs\here" if it's not in your search path) to your command-line arguments.

    Also Dev-C++ is garbage and old, use Code::Blocks with MinGW or another standards-compliant compiler.

  14. #14
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    Quote Originally Posted by Epy View Post
    libquadmath has to be linked separately from the cstdlib math library. Add "-lquadmath" (or -l"C:\path\to\libs\here" if it's not in your search path) to your command-line arguments.

    Also Dev-C++ is garbage and old, use Code::Blocks with MinGW or another standards-compliant compiler.
    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;
    }

  15. #15
    Registered User
    Join Date
    Jun 2016
    Posts
    14
    Quote Originally Posted by Elkvis View Post
    you probably need to say something along the lines of

    Code:
    #define __USE_MINGW_ANSI_STDIO 1
    Elkvis, you're right - that line does in fact prevent compilation errors but long double is still screwed up because it's still printing the wrong value.

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