printf on doubles

A

Allin Cottrell

Code fragment:

#include <stdio.h>

int main (void)
{
double a = 1.0;
double b = 0.9999999999999999;

printf("%#12.5g\n", a);
printf("%#12.5g\n", b);

return 0;
}

I would expect the above to produce

1.0000
1.0000

but here it produces

1.0000
1.00000

Is this in conformity with the C standard? "Here" is linux, glibc
2.4, but I've seen the same thing on win32.

Allin Cottrell
 
U

user923005

Code fragment:

#include <stdio.h>

int main (void)
{
double a = 1.0;
double b = 0.9999999999999999;

printf("%#12.5g\n", a);
printf("%#12.5g\n", b);

return 0;

}

I would expect the above to produce

1.0000
1.0000

but here it produces

1.0000
1.00000

Is this in conformity with the C standard? "Here" is linux, glibc
2.4, but I've seen the same thing on win32.

Here is what the standard says about the g format specifier:
"g,G A double argument representing a floating-point number is
converted in style f or e (or in style F or E in the case of a G
conversion specifier), with the precision specifying the number of
significant digits. If the precision is zero, it is taken as 1. The
style used depends on the value converted; style e (or E) is used only
if the exponent resulting from such a conversion is less than −4 or
greater than or equal to the precision. Trailing zeros are removed
from the fractional portion of the result unless the # flag is
specified; a decimal-point character appears only if it is followed by
a digit. A double argument representing an infinity or NaN is
converted in the style of an f or F conversion specifier."

And here is the definition for the width and precision"
"* An optional minimum field width. If the converted value has fewer
characters than the field width, it is padded with spaces (by default)
on the left (or right, if the left adjustment flag, described later,
has been given) to the field width. The field width takes the form of
an asterisk * (described later) or a decimal integer.232)
* An optional precision that gives the minimum number of digits to
appear for the d, i, o, u, x, and X conversions, the number of digits
to appear after the decimal-point character for a, A, e, E, f, and F
conversions, the maximum number of significant digits for the g and G
conversions, or the maximum number of bytes to be written for s
conversions. The precision takes the form of a period (.) followed
either by an asterisk * (described later) or by an optional decimal
integer; if only the period is specified, the precision is taken as
zero. If a precision appears with any other conversion specifier, the
behavior is undefined."

I am not sure how the C compiler computes significant digits, but it
seems logical to me that both outputs should look the same. Probably,
can offer the best explanation.
 
A

Allin Cottrell

user923005 said:
Here is what the standard says about the g format specifier:
"g,G A double argument representing a floating-point number is
converted in style f or e (or in style F or E in the case of a G
conversion specifier), with the precision specifying the number of
significant digits... Trailing zeros are removed
from the fractional portion of the result unless the # flag is
specified; a decimal-point character appears only if it is followed by
a digit...

And here is the definition for the ... precision"
* An optional precision that gives the minimum number of digits to
appear for the d, i, o, u, x, and X conversions, the number of digits
to appear after the decimal-point character for a, A, e, E, f, and F
conversions, the maximum number of significant digits for the g and G
conversions...

Thanks. Now I'm not sure whether this is a bug in the C library
implementation, or a bug in the C standard.

Since I used the g format specifier I expect style f or e output,
and I expect that the given precision (namely, 5) should specify the
number of significant digits (from the first paragraph above).

However, the "loophole" (contradiction?) is that in the second
paragraph, the precision for an 'e' conversion is not the number of
significant digits, but the number of digits appearing after the
decimal point.

It would seem that a = 1.0 has been printed in style e with 5
significant digits, while b = 0.999... has been printed in
style f with 5 digits after the point. Is this supposed to be
permissible, based on the input?

Allin Cottrell
 
D

Douglas A. Gwyn

user923005 said:
I am not sure how the C compiler computes significant digits, but it
seems logical to me that both outputs should look the same.

The simple answer is, no, that is not conforming.
 
A

Allin Cottrell

Allin said:
It would seem that a = 1.0 has been printed in style e with 5
significant digits, while b = 0.999... has been printed in
style f with 5 digits after the point. Is this supposed to be
permissible, based on the input?

Sorry, this is confused. a = 1.0 is obviously not printed in
style e in the output I showed Both 1.0 and 0.999... are printed
in style f. But according to the standard the usual business
whereby the precision gives the number of digits after the decimal
point in style f, ought to be over-ridden by the fact that this
is a "pass-through" from the g format, in favor of the precision's
giving the number of significant digits. In which case the
representation of 0.999... as "1.00000" is plain wrong, no?

Allin Cottrell
 
U

user923005

Code fragment:

#include <stdio.h>

int main (void)
{
double a = 1.0;
double b = 0.9999999999999999;

printf("%#12.5g\n", a);
printf("%#12.5g\n", b);

return 0;

}

I would expect the above to produce

1.0000
1.0000

but here it produces

1.0000
1.00000

Is this in conformity with the C standard? "Here" is linux, glibc
2.4, but I've seen the same thing on win32.

Allin Cottrell

I get correct output on GCC with MINGW on Win32:

dcorbit@DCORBIT64 /c/tmp
$ gcc -W -Wall -ansi -pedantic broke.c

dcorbit@DCORBIT64 /c/tmp
$ ./a
1.0000
1.0000

dcorbit@DCORBIT64 /c/tmp
$ gcc --version
gcc.exe (GCC) 4.0.1 20050608 (prerelease)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There
is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

Also with MS VC++:
C:\tmp>vsvars32
Setting environment for using Microsoft Visual Studio 2005 x86 tools.

C:\tmp>cl /W4 /Ox broke.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

broke.c
Microsoft (R) Incremental Linker Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.

/out:broke.exe
broke.obj

C:\tmp>broke
1.0000
1.0000

You should send a bug report to the glibc folks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top