negative zeroes in program output?

E

Elliot Marks

Under what circumstances would a C program, containing nothing
that is not standard C, prefix a zero result of a calculation
with doubles with a minus sign? I have written a program that
does operations on matrices. Some, but not all, of the zeroes in
the result matrices are displayed by printf as -0.0. (I know that
floating point arithmetic algorithms use positive and negative
zero but this is the first time I've seen negative zeroes in
program output.)
 
M

Mark McIntyre

Under what circumstances would a C program, containing nothing
that is not standard C, prefix a zero result of a calculation
with doubles with a minus sign? I have written a program that
does operations on matrices. Some, but not all, of the zeroes in
the result matrices are displayed by printf as -0.0.

Floating point is not exact. What mathematically might be zero is quite
likely to be 0 +/- some small amount. Your printf format string will then
round it and display as -0.0
 
E

E. Robert Tisdale

Mark said:
Floating point is not exact. What mathematically might be zero
is quite likely to be 0 +/- some small amount.
Your printf format string will then round it and display as -0.0
No.

> cat main.c
#include <stdio.h>

int main(int argc, char* argv[]) {
double x = -0.0;
double y = +0.0;
fprintf(stdout, "%lf = x\n", x);
fprintf(stdout, "%lf = y\n", y);
if (x == y)
fprintf(stdout, "They are equal!\n");
return 0;
}
> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main
-0.000000 = x
0.000000 = y
They are equal!

A floating-point number has two representations for zero --
one positive and the other negative.
 
E

Elliot Marks

Mark said:
Floating point is not exact. What mathematically might be zero is quite
likely to be 0 +/- some small amount. Your printf format string will then
round it and display as -0.0
I cancelled the original post because this behaviour went away
after using a different compiler. Your answer makes good sense
though.

Thanks,
Elliot
 
P

pete

E. Robert Tisdale said:

That's what I was thinking.
double x = -0.0;
double y = +0.0;
fprintf(stdout, "%lf = x\n", x);
fprintf(stdout, "%lf = y\n", y);
if (x == y)
fprintf(stdout, "They are equal!\n");
-0.000000 = x
0.000000 = y
They are equal!

A floating-point number has two representations for zero --
one positive and the other negative.

It's allowed to have two, but floating point representation
is implementation defined.

The '-' character output of your program
is also implementation defined, even on implementations that
have two representations for zero --
one positive and the other negative.
 
K

Keith Thompson

E. Robert Tisdale said:
Mark said:
Floating point is not exact. What mathematically might be zero
is quite likely to be 0 +/- some small amount. Your printf format
string will then round it and display as -0.0
No.

Yes.
cat main.c
#include <stdio.h>

int main(int argc, char* argv[]) {
double x = -0.0;
double y = +0.0;
fprintf(stdout, "%lf = x\n", x);
fprintf(stdout, "%lf = y\n", y);
if (x == y)
fprintf(stdout, "They are equal!\n");
return 0;
}
gcc -Wall -std=c99 -pedantic -o main main.c
./main
-0.000000 = x
0.000000 = y
They are equal!

Why do you use fprintf(stdout, ...) rather than printf(...)?

The correct format for type double is "%f". The "%lf" format is not
defined by the standard, so your first two fprintf calls invoke
undefined behavior.
A floating-point number has two representations for zero --
one positive and the other negative.

That's true for many (most?) existing floating-point representations,
but I don't think the C standard says anything about it. An
implementation for which the above program prints

0.000000 = x
0.000000 = y
They are equal!

would be conforming as far as I know.

But the following program:

#include <stdio.h>
int main(void)
{
double x = -1e-20;
double y = +1e-20;
printf("x = %lf\n", x);
printf("y = %lf\n", y);
printf(x == y ? "They're equal\n" : "They're not equal\n");
return 0;
}

produces the following output (in at least one implementation):

x = -0.000000
y = 0.000000
They're not equal
 
P

pete

Keith said:
The correct format for type double is "%f".
Yes.

The "%lf" format is not defined by the standard,
so your first two fprintf calls invoke
undefined behavior.

Undefined in C89
Defined in C99


C89 last public draft:
4.9.6 Formatted input/output functions
4.9.6.1 The fprintf function

an optional l (ell) specifying that a following d , i , o ,
u , x , or X conversion specifier applies to a long int or unsigned
long int argument; an optional l specifying that a following n
conversion specifier applies to a pointer to a long int argument; or
an optional L specifying that a following e , E , f , g , or G
conversion specifier applies to a long double argument.
If an h , l ,
or L appears with any other conversion specifier, the behavior is
undefined.

N869
7.19.6.1 The fprintf function

l (ell) ... or has no effect on a following a,
A, e, E, f, F, g, or G conversion
specifier.
 
J

Joe Wright

Keith Thompson wrote:

[ snip ]
That's true for many (most?) existing floating-point representations,
but I don't think the C standard says anything about it. An
implementation for which the above program prints

0.000000 = x
0.000000 = y
They are equal!

would be conforming as far as I know.

But the following program:

#include <stdio.h>
int main(void)
{
double x = -1e-20;
double y = +1e-20;
printf("x = %lf\n", x);
printf("y = %lf\n", y);
printf(x == y ? "They're equal\n" : "They're not equal\n");
return 0;
}

produces the following output (in at least one implementation):

x = -0.000000
y = 0.000000
They're not equal

That program, on my implementation (gcc 3.1) looks like..

C:\work\c\clc>kt
x = 0.000000
y = 0.000000
They're not equal

Negative zero is weird.

Also on my implementation, "%f" suffices for both double and long
double. "%lf" is allowed by C99 and accepted quietly by gcc but is
not defined.
 
K

Keith Thompson

pete said:
Keith said:
The correct format for type double is "%f".
Yes.

The "%lf" format is not defined by the standard,
so your first two fprintf calls invoke
undefined behavior.

Undefined in C89
Defined in C99 [snip]
N869
7.19.6.1 The fprintf function

l (ell) ... or has no effect on a following a,
A, e, E, f, F, g, or G conversion
specifier.

You're right, I missed that. (It's also in the final C99 standard.)
 
D

Dan Pop

In said:
pete said:
Keith said:
The correct format for type double is "%f".
Yes.

The "%lf" format is not defined by the standard,
so your first two fprintf calls invoke
undefined behavior.

Undefined in C89
Defined in C99 [snip]
N869
7.19.6.1 The fprintf function

l (ell) ... or has no effect on a following a,
A, e, E, f, F, g, or G conversion
specifier.

You're right, I missed that. (It's also in the final C99 standard.)

Official reason: to improve symmetry between scanf and printf.
Unofficial reason: far too much broken code used %lf in printf and
practically all implementors ignored the l in this context:

fangorn:~/tmp 573> gcc -Wall test.c
fangorn:~/tmp 574> gcc -pedantic -Wall test.c
test.c: In function `main':
test.c:5: warning: ISO C90 does not support the `%lf' printf format

Dan
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top