tenfour
tenfour

Reputation: 36896

Does float have a negative zero? (-0f)

IEEE floating point numbers have a bit assigned to indicate the sign, which means you can technically have different binary representations of zero (+0 and -0). Is there an arithmetic operation I could do for example in C which result in a negative zero floating point value?

This question is inspired by another which called into question whether you can safely compare 0.0f using ==, and I wondered further if there is are other ways to represent zero which would cause float1 == 0.0f to break for seemingly perfectly equal values.

[Edit] Please, do not comment about the safety of comparing floats for equality! I am not trying to add to that overflowing bucket of duplicate questions.

Upvotes: 50

Views: 28177

Answers (10)

Rosh Oxymoron
Rosh Oxymoron

Reputation: 21065

According to the standard, negative zero exists but it is equal to positive zero. For almost all purposes, the two behave the same way and many consider the existence of a negative to be an implementation detail. There are, however, some functions that behave quite differently, namely division and atan2:

#include <math.h>
#include <stdio.h>

int main() {
    double x = 0.0;
    double y = -0.0;
    printf("%.08f == %.08f: %d\n", x, y, x == y);
    printf("%.08f == %.08f: %d\n", 1 / x, 1 / y, 1 / x == 1 / y);
    printf("%.08f == %.08f: %d\n", atan2(x, y), atan2(y, y), atan2(x, y) == atan2(y, y));
}

The result from this code is:

0.00000000 == -0.00000000: 1
1.#INF0000 == -1.#INF0000: 0
3.14159265 == -3.14159265: 0

This would mean that code would correctly handle certain limits without a need for explicit handling. It's not certain that relying on this feature for values close to the limits is a good idea, since a simple calculation error can change the sign and make the value far from correct, but you can still take advantage of it if you avoid calculations that would change the sign.

Upvotes: 39

rowan194
rowan194

Reputation: 199

There are a couple of simple arithmetic operations that result in a negative zero answer (at least on the i386/x64/ARMv7/ARMv8 systems I tested it on) :

  • -1 * 0
  • 0 / -1

These caught me by surprise when I was writing an optimiser to simplify arithmetic expressions. Optimising "a = b * 0" to "a = 0" will result in the wrong answer (+0) if b happens to be negative (correct answer is -0).

Upvotes: 5

zviadm
zviadm

Reputation: 1055

this float1 == 0.0f is never really a safe comparison.

if you have something like

float x = 0.0f;
for (int i = 0; i < 10; i++) x += 0.1f;
x -= 1.0f;
assert (x == 0.0f);

it will fail even though it is seemingly supposed to be 0.

Upvotes: 0

pixelbeat
pixelbeat

Reputation: 31778

-lm has the signbit() function available to indicate if a value is negative (including -0)

Upvotes: 1

old_timer
old_timer

Reputation: 71586

Yes you can have a +0 and -0 and those are different bit patterns (should fail the equality test). You should never use == with float, certainly not IEEE float. < or > are fine. There are many other SO questions and discussions on this topic, so I wont get into it here.

Upvotes: 0

Martin Beckett
Martin Beckett

Reputation: 96167

Yes zero can be signed but the standard requires positive and negative zero to test as equal

Upvotes: 8

Stephen Canon
Stephen Canon

Reputation: 106297

Is there an arithmetic operation I could do for example in C which result in a negative zero floating point value?

Sure:

float negativeZero = -10.0e-30f * 10.0e-30f;

The mathematically precise result of the multiplication is not representable as a floating-point value, so it rounds to the closest representable value, which is -0.0f.

The semantics of negative zero are well defined by the IEEE-754 standard; the only real observable way in which its behavior differs from that of zero in arithmetic expression is that if you divide by it, you will get a different sign of infinity. For example:

1.f /  0.f --> +infinity
1.f / -0.f --> -infinity

Comparisons and addition and subtraction with -0.f give the same result as they would with +0.f (in the default rounding mode). Multiplication can preserve the sign of zero, but as noted, it generally isn't observable.

There are some math library functions whose behavior can vary depending on the sign of zero. For example:

copysignf(1.0f, 0.0f) -->  1.0f
copysignf(1.0f,-0.0f) --> -1.0f

This is more common in the complex functions:

csqrtf(-1.0f + 0.0f*i) --> 0.0f + 1.0f*i
csqrtf(-1.0f - 0.0f*i) --> 0.0f - 1.0f*i

In general, however, you shouldn't need to worry about negative zero.

Upvotes: 17

gordonk
gordonk

Reputation: 116

You should exercise caution when doing equality comparisons using floats. Remember, you're trying to represent a decimal value in a binary system.

Is it safe to check floating point values for equality to 0?

If you must compare floating point values I would suggest you use some kind of tolerance that is acceptable to you float1 <= toleranceVal && float1 >= toleranceVal2 or multiply by some factor of ten and cast as an integer. if (!(int)(float1 * 10000)) { .. some stuff .. }

Upvotes: 1

user541686
user541686

Reputation: 210755

Yes, float does have a negative zero, but no, you don't have to worry about this when comparing floating-point values.

Floating-point arithmetic is defined to work correctly on special cases.

Upvotes: 2

Jeremiah Willcock
Jeremiah Willcock

Reputation: 30999

Yes, floats have negative zero just like other IEEE floating point types such as double (on systems with IEEE floating point). There is an example here in Octave of how to create them; the same operations work in C. The == operator treats +0 and -0 the same, though, and so negative zeros do not break that type of comparison.

Upvotes: 1

Related Questions