The IEEE 754 binary floating point arithmetic standard has the concept of both a positive zero and a negative zero.

Strangely at first glance, the IEEE 754 standard does define a way to specify a value which is exactly zero1. I say "at first glance" because it should be clear to anyone that the likelihood of an arbitrary floating point calculation yielding a value which is actually supposed to be exactly zero is vanishingly small. Instead, the IEEE 754 standard defines the notion of positive and negative zeros because they allow the programmer to distinguish between results which are very very small and yet negative and results which are very very small and yet positive.

A negative zero results from:

  • an operation which generates a negative value which is too close to zero to be represented in the floating point precision being used.

    For example, both -10-200 * 10-200 and -10-200 / 10200 result in negative zero.

  • the division of a positive finite value by -infinity or the division of a negative finite value by +infinity2.

    For example, 1.0 / ( -10200 * 10200 ) will result in negative zero.

  • the multiplication of a positive finite value by negative zero or the multiplication of any negative finite value by positive zero.

    For example, 1.0 * ( 10-200 * -10-200 ) will result in negative zero.

All other operations which yield a zero result yield a positive zero.

With two exceptions that we'll get to shortly, a negative zero cannot be distinguished from a positive zero. For example, if x is negative zero (or positive zero) then the following will print out "they are the same":

if ( x == 0.0 ) then
    print "they are the same"
else
    print "they are different"
fi
Two IEEE 754 operations can be used to distinguish between a positive zero and a negative zero:
  1. dividing a positive finite value by negative zero results in -infinity (as does dividing a negative finite value by positive zero). Conversely, dividing a positive finite value by positive zero results in +infinity (as does dividing a negative finite value by negative zero).

    For example, if x is negative zero then the following will print out "x is negative":

    if ( 1.0 / x < 0 ) then
        print "x is negative"
    else
        print "x is positive (or we got a NaN)"
    fi
    
  2. the IEEE 754 CopySign function can be used to extract the sign of an IEEE 754 floating point value. This value can then be tested to determine if the original value was positive or negative.

    For example, if x is negative zero then the following will print "x is negative" (CopySign returns the value of the first operand but with the sign of the second operand):

    y = CopySign(1.0,x)
    if ( y < 0 ) then
        print "x is negative"
    else
        print "x is positive"
    fi
    

Negative zeros can "create the opportunity for an educational experience" when they are printed as they are often printed as "-0" or "-0.0" (the "educational experience" is the time and effort that you spend learning why you're getting these strange values).

A single precision negative zero is represented in memory as the bit pattern 0x80000000 whereas a single precision positive zero is represented as 0x00000000. A double precision negative zero is represented as 0x8000000000000000 whereas a double precision positive zero is represented as 0x0000000000000000. Testing IEEE 754 values for zero by using non-IEEE 754 operations (e.g. checking if a memory location is all zeros using integer operations) can provide yet another "opportunity for an educational experience".


References

  • Lecture Notes on the Status of IEEE Standard 754 for Binary Floating-Point Arithmetic by Professor W. Kahan, 1996 (available on the 'net at http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF (last accessed 2003/03/02))

  • Personal experience

1One might expect that if the programmer writes 0.0 in their source code then that would be encoded as exactly zero but in actuality it is encoded as a positive zero. Just to make things even more fun, if the programmer writes -0.0 in their source code then that value is almost certainly also encoded as a positive zero. The bottom line is that if you want an IEEE 754 value which is negative zero then use one of the techniques described above.
2IEEE 754 also has the concept of infinity values. Please see my NaN writeup for a short sidebar discussion of IEEE 754 infinities.