85

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.

5
  • 7
    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. May 1, 2015 at 4:10
  • 2
    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, 2015 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, 2015 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, 2015 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, 2015 at 17:38

6 Answers 6

102

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".

10
  • Do you have any ideas on whether the sign of underflow might be especially important in imaginary/complex number calculations?
    – jpmc26
    May 5, 2015 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. Jun 12, 2016 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, 2016 at 17:47
  • 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, 2016 at 17:22
  • 2
    Bad example. -1 / 1000000000000000000.0 is actually = -1.E-18. This example shows underflow to -0: double a = -1.0E-50; float b = a; // b underflows to -0.0
    – A Fog
    Jun 27, 2019 at 19:09
12

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.

4
  • 12
    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, 2015 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. May 31, 2018 at 10:54
  • x + 0.0 === x === x - 0.0 and x^0.0 === 1.0 === x^-0.0 for all values of x, I think. The sign of zero only matters for multiplication and division and that makes sense if you consider them to be positive and negative infinitesimals.
    – cmc
    Mar 22, 2020 at 16:42
  • x + 0 === x does not hold for x=-0 because -0+0 is positive, not negative zero.
    – SWeko
    May 29, 2020 at 18:34
7

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
1
  • 8
    Yes, but why is this important? Can you provide a practical, real-world example where the difference matters?
    – Philipp
    May 1, 2015 at 15:27
6

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.

2

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.

3
  • 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, 2015 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, 2016 at 3:05
  • 5
    @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, 2016 at 3:11
1

One place negative zero is useful is when using hh:mm:ss or Degree:mm:ss to describe a position for instance on the Earth's surface or the Sky. The Hours / Degrees, minutes & seconds are normally held as 3 separate numbers. Degrees to the west of the meridian are normally negative so you may have -5:20:30. The mm & ss are implied to be in the negative (west direction) even though they are signed as positive. The calculation to decimal degrees takes this into account. The problem comes with 00:mm:ss W. If there is no negative zero in the number system used the calculation used for -1 degrees and above will fail. There are work arounds but they require that the problem is recognised and the E or W is saved as a 4th number and used in the calculation, in the case of it being west to negate the result.

hh represents hours, mm minutes and ss seconds as part of an angle

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