64

I'm confused about why we care about different representations for positive and negative zero.

I vaguely recall reading claims that having a negative zero representation is extremely important in programming that involves complex numbers. I've never had the opportunity to write code involving complex numbers, so I'm a little baffled about why this would be the case.

Wikipedia's article on the concept isn't especially helpful; it only makes vague claims about signed zero making certain mathematical operations simpler in floating point, if I understand correctly. This answer lists a couple of functions that behave differently, and perhaps something could be inferred from the examples if you're familiar with how they might be used. (Although, the particular example of the complex square roots looks flat out wrong, since the two numbers are mathematically equivalent, unless I have a misunderstanding.) But I have been unable to find a clear statement of the kind of trouble you would get into if it wasn't there. The more mathematical resources I've been able to find state that there is no distinguishing between the two from a mathematical perspective, and the Wikipedia article seems to suggest that this is rarely seen outside of computing aside from describing limits.

So why is a negative zero valuable in computing? I'm sure I'm just missing something.

  • 6
    Negative zero can signal underflow in an IEEE floating point number, but beyond that, its use appears to be controversial and obscure. If I were to guess, I'd say that negative zero is represented in IEEE floating point because... well, you can. For an even more interesting ride, look up the information on floating point signaling NaN. – Robert Harvey May 1 '15 at 4:10
  • 1
    If the particular example is "1 / 0.0" / "1 / -0.0", 0 is a branch cut for 1/x and the limit depends on if you approach it from below or above. – Vatine May 1 '15 at 8:39
  • @Vatine No, the particular example is sqrt(-1+0i) = i and sqrt(-1-0i) = -i, although dressed up with proper syntax for some programming language, I believe. I'll edit to be more clear. – jpmc26 May 1 '15 at 8:41
  • 3
    I searched Programmers, Stack Overflow, Computer Science, Mathematics, and Engineering. The only question I could find was Uses for negative zero floating point value?. This cannot be only the second time this has come up! – user22815 May 1 '15 at 15:43
  • I'm really surprised that complex numbers haven't come up at all in the answers, especially given the square root example I pointed out. – jpmc26 May 2 '15 at 17:38
69

You need to keep in mind that in FPU arithmetics, 0 doesn't necessarily has to mean exactly zero, but also value too small to be represented using given datatype, e.g.

a = -1 / 1000000000000000000.0

a is too small to be represented correctly by float (32 bit), so it is "rounded" to -0.

Now, let's say our computation continues:

b = 1 / a

Because a is float, it will result in -infinity which is quite far from the correct answer of -1000000000000000000.0

Now let's compute b if there's no -0 (so a is rounded to +0):

b = 1 / +0
b = +infinity

The result is wrong again because of rounding, but now it is "more wrong" - not only numerically, but more importantly because of different sign (result of computation is +infinity, correct result is -1000000000000000000.0).

You could still say that it doesn't really matter as both are wrong. The important thing is that there are a lot of numerical applications where the most important result of the computation is the sign - e.g. when deciding whether to turn left or right at the crossroad using some machine learning algorithm, you can interpret positive value => turn left, negative value => turn right, actual "magnitude" of the value is just "confidence coefficient".

  • Do you have any ideas on whether the sign of underflow might be especially important in imaginary/complex number calculations? – jpmc26 May 5 '15 at 1:55
  • @qbd: Do you know what those numerical applications are? I would say that programs that triggers and uses +inf and -inf in normal operation are bugged. – Björn Lindqvist Jun 12 '16 at 15:30
  • @BjörnLindqvist If you want concrete, downloadable applications - then I don't know any. I don't think it's necessarily buggy - instead of float/double you could use something like BigDecimal with unlimited precision. But is it worth it when the program will give exactly the same results as the one with float/double, but with much worse performance? – qbd Jun 12 '16 at 17:47
  • You wrote "numerical applications where the most important result of the computation is the sign" I can believe that, but I can't believe there are any well-written applications that rely on -0 and on values being +inf and -inf. If your program causes floating point underflow, that is the bug and what happens afterwards is not so interesting, imho. We're still missing practical examples in which -0 is useful. – Björn Lindqvist Jun 12 '16 at 21:51
  • 1
    @BjörnLindqvist Large part of x265 is done in assembly, relying on its obscure details (which are dependent on the CPU architecture) few people know about in the name of performance. Is it wrong? Relying on the widely implemented 30 year old standard (which is here to stay) for one simple, well understood feature in the name of performance suddenly doesn't seem so bad. – qbd Jun 13 '16 at 17:22
8

First, how do you create a -0? There are two ways: (1) do a floating-point operation where the mathematical result is negative, but so close to zero that it gets rounded to zero and not to a non-zero number. That calculation will give a -0. (b) Certain operations involving zeroes: Multiply a positive zero by a negative number, or divide a positive zero by a negative number, or negate a positive zero.

Having a negative zero simplifies multiplication and division a little bit, the sign of x*y or x/y is always the sign of x, exclusive or the sign of y. Without negative zero, there would have to be some extra check to replace -0 with +0.

There are some very rare situations where it useful. You can check whether the result of a multiplication or division is mathematically greater than or less than zero, even if there is an underflow (as long as you know the result is not a mathematical zero). I cannot remember ever having written code where it makes a difference.

Optimising compilers hate -0. For example, you cannot replace x + 0.0 with x, because the result shouldn't be x if x is -0.0. You can't replace x * 0.0 with 0.0, because the result should be -0.0 if x < 0 or x is -0.0.

  • 7
    I wish IEEE-754 had included four zeroes: "exact", positive infinitesimal, negative infinitesimal, and unsigned (the latter being the difference between indistinguishable values). Doing that would have made a lot of floating-point axioms work--among them, x+0.0 equiv x-0.0 equiv x, x-y equiv x+(-1.0)*y, and 1.0/x equiv -1.0/(-1.0*x) [if x is positive zero, both would be pos-inf; if neg-zero, both neg-inf; if exact or unsigned, both NaN]. – supercat May 18 '15 at 20:39
  • I was able to get a negative zero by passing -5 and 5 into fmod(). It's quite annoying for my use case. – Aaron Franke May 31 '18 at 10:54
6

C# Double which conforms to IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

prints:

Infinity
-Infinity

actually to explain a little...

Double d = -0.0; 

This means something a lot closer to d= The Limit of x as x approaches 0- or The Limit of x as x approaches 0 from the negatives.


To address Philipp's comment...

Basically negative zero means underflow.

There's very little practical use for negative zero if any...

for example, this code (again C#):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

yields this result:

True
True
0

To explain informally, All of the special values an IEEE 754 floating point can have (positive infinity, negative infinity, NAN, -0.0) have no meaning in the practical sense. They can't represent any physical value, or any value that makes sense in "real world" calculation. What they mean is basically this:

  • positive infinity means a an overflow at the positive end a floating point can represent
  • negative infinity means a an overflow at the positive end a floating point can represent
  • negative zero means a an underflow and the operands had opposite signs
  • positive zero may mean a an underflow and the operands had the same sign
  • NAN means your calculation is complacently undefined, like sqrt(-7), or it doesnt have a limit like 0/0 or like PositiveInfinity/PositiveInfinity
  • 7
    Yes, but why is this important? Can you provide a practical, real-world example where the difference matters? – Philipp May 1 '15 at 15:27
5

The question about how this relates to complex-number calculations really gets at the heart of why both +0 and -0 exist in floating-point. If you study Complex Analysis at all, you rapidly discover that continuous functions from Complex to Complex usually cannot be treated as 'single-valued' unless one adopts the 'polite fiction' that the outputs form what is known as a 'Riemann surface'. For example, the complex logarithm assigns each input infinitely many outputs; when you 'connect them up' to form a continuous output, you end up with all of the real-parts forming an 'infinite corkscrew' surface around the origin. A continuous curve that crosses the real axis 'downward from the positive-imaginary side' and another curve that 'wraps around the pole' and crosses the real axis 'upward from the negative-imaginary side' will take different values on the real axis because they pass over different 'sheets' of the Riemann surface.

Now apply that to a numerical program that calculates using complex floating-point. The action taken after a given calculation may be very different depending on which 'sheet' the program is currently 'on', and the sign of the last calculated result probably tells you which 'sheet'. Now suppose that result was zero? Remember, here 'zero' really means 'too small to represent correctly'. But if the calculation could arrange to -preserve the sign- (i.e remember which 'sheet') when the result is zero, then the code can check the sign and perform the right action even in this situation.

1

The reason is simpler than usual

Of course there is a lot of hacks which are looking really nice and they are useful (like rounding to -0.0 or +0.0 but assume we have a representation of signed int with a minus/plus sign at the beginning (i know that is resolved by U2 binary code in integers usually but assume a less complex representation of double):

0 111 = 7
^ sign

What if there is negative number?

1 111 = -7

Okay, that simple. So let's represent 0:

0 000 = 0

That's fine too. But what about 1 000? Is it has to be a forbidden number? Better no.

So let's assume there is two types of zero:

0 000 = +0
1 000 = -0

Well, that will simplify our calculations and fortuately give a some rounding up additional features. So the +0 and -0 are coming from just binary representation issues.

  • 6
    If I'm reading this correctly, you're essentially just saying people defining or implementing the standards didn't want to go to the trouble of forbidding it. I don't think this reasoning holds up to the fact that 2's complement uses the "negative zero" representation for an entirely different number and has no representation of negative zero. See the Wikipedia article I linked. – jpmc26 May 1 '15 at 16:19
  • 1
    @jpmc26 I think there actually is some truth to that, in that not forbidding it means not requiring implementations to have a special case. As it is, every number has a sign bit and can be negated by toggling the sign bit. Even NaNs are signed, and implementations can (but aren't required to) choose an appropriate sign when producing a NaN. If negative zero didn't exist, every calculation that resulted in 0 would need to do extra work to fix up the sign bit, etc. – hobbs May 5 '16 at 3:05
  • 4
    @jpmc26 (i.e. in every other multiplication of two numbers, the sign of the result is the xor of the sign of the multiplicands, and the magnitude is the product of the two magnitudes. In real life this works for -1 * 0 = -0. But if zero with the sign bit flipped was some special nonzero value, every product that could produce 0 would have to check and make sure it doesn't produce that special value by mistake.) – hobbs May 5 '16 at 3:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.