13

We are finding in Python some occasional errors in our coordinate transforms and other similar computations that produce a result of -0.0. What purpose does this serve in Python? So far it creates a zero testing error (that is, -0.0 does not equal 0.0; does it equal +0.0?).

The easy test is at the prompt:

>>> -1*0.0
Anton Menshov
  • 8,672
  • 7
  • 38
  • 94
Chris Ison
  • 231
  • 2
  • 4
  • 9
    There's not enough context here to provide a firm answer. The OP should read up on signed zeros in IEEE floating point. However, -0.0 is equal to +0.0 in IEEE floating point, so there's something else going on if "-0.0 does not equal 0.0" in some context. – Brian Borchers Aug 02 '21 at 19:44
  • 5
    it has nothing to do with Python. Python uses IEEE-754 so all the floating-point rules in python is defined by the IEEE-754 standard and any languages that use IEEE-754 will have the same behavior – phuclv Aug 03 '21 at 03:44
  • 4
    If in programming, you ever find yourself testing for exact equality between floating point numbers, then you are most probably wrong. – Glen Yates Aug 04 '21 at 15:17

1 Answers1

24

Floating point numbers (according to the standard1 nearly all programming languages use) are stored with a certain number of bits in the mantissa, in the exponent, and with a sign bit. As such, floating point numbers can make a difference between zero and minus zero. In almost all applications, that doesn't make a difference. For example, on the Python prompt, you get

>>> 0.0
0.0
>>> -1*0.0
-0.0
>>> -1*0.0 == 0.0
True

so the two compare equal.

Why are numbers not normalized so that there is only one zero? Because sometimes you want to know whether a number may have been obtained by underflow. For example:

>>> 1e-300/1e300
0.0
>>> -1e-300/1e300
-0.0

(This is because there are only so many bits in the exponent, and the smallest by magnitude number that can be stored is approximately 1e-308, so the result of the computations above is rounded down to zero.)

Of course, a completely different possibility is that you really have numbers different from zero but very small and that for whatever reason you have set up your system in such a way that everything that is smaller than a certain value is printed as zero. In those cases, even if variables a and b are shown as zero (possibly with a sign), they are not in fact zero and consequently don't compare equal.


1 For your information and further research, the standard is IEEE 754.

zdimension
  • 103
  • 1
Wolfgang Bangerth
  • 55,373
  • 59
  • 119
  • How could that be tested? Set x=-1e-300/1e300; x==0.0 and x==-0.0 both return true; x<0 and x>0 are both false (Python 3.9.6). – Dave the Sax Aug 03 '21 at 08:32
  • 1.0/0.0 = +Inf, while 1.0/-0.0=-Inf, so there is definitely a difference between positive and negative zero. – Simon Richter Aug 03 '21 at 09:25
  • 9
    Division by zero raises an exception in Python, but you can use is_negative = math.copysign(1.0, x) < 0, which will be True for x = -0.0 and False for x = 0.0 – Jasmijn Aug 03 '21 at 10:15
  • @Dave the Sax. You can try something like str(-0.0)[0] == "-" – Thomas Baruchel Aug 03 '21 at 13:00
  • 4
    @ThomasBaruchel You can, but you probably shouldn't because there are cleaner methods. Like the one Jasmijn provided. – GammaGames Aug 03 '21 at 15:27
  • 9
    Might be worth directly mentioning IEEE 754 in the answer instead of leaving it unsaid what the standard used by almost all languages is, otherwise this is an excellent answer. – Austin Hemmelgarn Aug 03 '21 at 15:58
  • 1
    @AustinHemmelgarn That's right -- IEEE 754 is the normative source. – Wolfgang Bangerth Aug 03 '21 at 16:59
  • 2
    I'm pretty sure that the final paragraph is what's actually going on in OP's cases, displaying as negative zero due to rounding but not actually equal to zero (either positive or negative). – Ben Voigt Aug 03 '21 at 22:12
  • @Jasmijn: Integer division by zero raises an exception in Python. Floating point division just gives you an infinity (or NaN if the numerator is also zero). – Kevin Aug 04 '21 at 18:16
  • 1
    @Kevin Try it. You'll get ZeroDivisionError: float division by zero. – Jasmijn Aug 05 '21 at 10:00