Signed zeroes and complex literals
IEEE-754 floats have the concept of a “signed zero”; 0.0
has a different bit representation to -0.0
. In most cases, -0.0
behaves the same way as 0.0
, and it compares equal in arithmetic operations. It becomes more obviously distinct in floating-point operations that involve some form of limiting behaviour. For example, x / 0.0
and x / -0.0
are opposite-signed infinities.
Along with the other IEEE-754 special values, like quiet/signalling NaN and infinities, these sorts of behaviours prevent compilers from making certain mathematical rewrites that would appear to be completely sound in regular arithmetic. a = b
; all finite IEEE-754 floats satisfy x - x = 0.0
, therefore a - b
and b - a
are both 0.0
, and negating one to make -0.0
makes it distinct.
In most uses, this is largely a curiosity and has little impact. It can be useful in general when the only information needed from the result of a long calculation is its sign. If the result were to underflow, beyond even the subnormal floats, the resulting sign of the zero would still be able to indicate the correct direction. The signed zero, then, can be thought of as representing the behaviour in the limit.
Where it becomes far more than a curiosity, with major impactful results, is when the signed zero becomes involved in a calculation with a discontinuity at zero. For real numbers, the most obvious of these is atan2(y, x)
, which is the floating-point version of -0.0
is then interpreted as atan2(0.0, 0.0)
and atan2(0.0, -0.0)
. Treating these as being calculated within atan2(0.0, 0.0)
would be a zero rotation, while atan2(0.0, -0.0)
approximates