Reputation: 213
Hello I'm learning Objective C and I was doing the classic Calculator example.
Problem is that I'm getting a negative zero when I multiply zero by any negative number, and I put the result into a (double) type!
To see what was going on, I played with the debugger and this is what I got:
(gdb) print -2*0
$1 = 0(gdb) print (double) -2 * 0
$2 = -0
In the second case when I cast it to a double type, it turns into negative zero! How can I fix that in my application? I need to work with doubles. How can I fix the result so I get a zero when the result should be zero?
Upvotes: 21
Views: 25841
Reputation: 1901
GCC was seemingly optimizing out the simple fix of negzero += 0.0
as noted above until I realized that -fno-signed-zeros
was in place. Duh.
But in the process I did find that this will fix a signed zero, even when -fno-signed-zeros
is set:
if (negzero > -DBL_MIN && negzero < DBL_MIN && signbit(negzero))
negzero = 0.0;
or as a macro:
#define NO_NEG_ZERO(a) ( (a) > -DBL_MIN && (a) < DBL_MIN && signbit(a) ? 0.0 : (a) )
negzero = NO_NEG_ZERO(negzero)
Note that the comparitor is < and > (not <= or >=) so a
really is zero! (OR it is a subnormal number...but nevermind the guy behind the curtain.)
Maybe this answer is slightly less correct in the sense that a value of between DBL_MIN
and -DBL_MIN
will be converted to 0.0
, in which case this isn't the way if you need to support subnormal numbers.
If you do need subnormal numbers (!) then perhaps your the kind of person who plays with -fno-signed-zeros
, too.
The lesson here for me and subnormal-numbers-guy is this: if you play outside of spec then expect out-of-spec results ;)
(Sorry, that was not PC. It could be subnormal-numbers-person...but I digress.)
Upvotes: 1
Reputation: 1
In my code (on C MPI intel compiler) -0.0
and +0.0
are not the same.
As an example:
d = -0.0
if (d < 0.0)
do something...
and it is doing this "something".
also adding -0.0 + 0.0 = -0.0...
Upvotes: 0
Reputation: 153338
How can I fix that in my application?
Code really is not broken, so nothing needs to be "fixed". @kennytm
How can I fix the result so I get a zero when the result should be zero?
To easily get rid of the -
when the result is -0.0
, add 0.0
. Code following standard (IEC 60559 floating-point) rules will produce drop the -
sign.
double nzero = -0.0;
printf("%f\n", nzero);
printf("%f\n", nzero + 0.0);
printf("%f\n", fabs(nzero)); // This has a side effect of changing all negative values
// pedantic code using <math.h>
if (signbit(nzero)) nzero = 0.0; // This has a side effect of changing all negative values
printf("%f\n", nzero);
Usual output.
-0.000000
0.000000
0.000000
0.000000
Yet for general double x
that may have any value, hard to beat the following. @Richard J. Ross III @chqrlie The x + 0.0
approach has an advantage in that likely does not introduce a branch, yet the following is clear.
if (x == 0.0) x = 0.0;
Note: fmax(-0.0, 0.0)
may produce -0.0.
Upvotes: 4
Reputation: 144695
There is a misunderstanding here about operator precedence:
(double) -2 * 0
is parsed as
((double)(-(2))) * 0
which is essentially the same as (-2.0) * 0.0
.
The C Standard informative Annex J lists as Unspecifier behavior Whether certain operators can generate negative zeros and whether a negative zero becomes a normal zero when stored in an object (6.2.6.2).
Conversely, (double)(-2 * 0)
should generate a positive zero 0.0
on most current platforms as the multiplication is performed using integer arithmetic. The C Standard does have support for architectures that distinguish positive and negative zero integers, but these are vanishingly rare nowadays.
If you want to force zeros to be positive, this simple fix should work:
if (d == 0) {
d = 0;
}
You could make the intent clearer with this:
if (d == -0.0) {
d = +0.0;
}
But the test will succeed also if d
is a positive zero.
Chux has a simpler solution for IEC 60559 complying environments:
d = d + 0.0; // turn -0.0 to +0.0
Upvotes: 8
Reputation: 20421
http://en.wikipedia.org/wiki/Signed_zero
The number 0 is usually encoded as +0, but can be represented by either +0 or −0
It shouldn't impact on calculations or UI output.
Upvotes: 4
Reputation: 55533
I did a simple test:
double d = (double) -2.0 * 0;
if (d < 0)
printf("d is less than zero\n");
if (d == 0)
printf("d is equal to zero\n");
if (d > 0)
printf("d is greater than zero\n");
printf("d is: %lf\n", d);
It outputs:
d is equal to zero
d is: -0.000000
So, to fix this, you can add a simple if-check to your application:
if (d == 0) d = 0;
Upvotes: 19