# Thread: 128 bit (long double) printf not working

1. ## 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;
}

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

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?

2. 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. I don't know if the compiler can infer it by itself, but you should use "3.1415L".

Also, this:
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).

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

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

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.

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.

7. If you are a programming enthusiasts you could write one yourself that handles whatever the amount of digits you like.

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

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?

11. 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. you probably need to say something along the lines of

Code:
#define __USE_MINGW_ANSI_STDIO 1

13. Originally Posted by AamirYousafi
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'"

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

14. Originally Posted by Epy

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. Originally Posted by Elkvis
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.