9

I have to compare two numbers. One of them comes from regulat python code and comes other from numpy. Debugger shows they have same value '29.0', but type of first is float and type of second is float64, so a == b and a - b == 0 is False. How can I deal with it? Is there any way to force a regular python variable to be float64 or numpy use float by default?

Update: In the end of all these values comes from the same file where 29.0 is written, so I don't think there are differences in numeric values.

Daniel
  • 19,179
  • 7
  • 60
  • 74
xander27
  • 3,014
  • 8
  • 30
  • 42
  • 2
    Typically comparing any two floats with `a == b` or `a - b == 0` is a bad idea due to precision errors. Try doing something like `abs(a - b) < 1e-8` or something. – wflynny Aug 07 '13 at 15:08
  • 1
    floating-point representation and arithmetics are not exact ( mantisse and truncature pb). Set an epsilon of maximum difference (typically 10e-10). – lucasg Aug 07 '13 at 15:09
  • While in general these comments semm to be right, I cannot imagine a precision error in the value `29.0` if it comes from a file whic probably is in ASCII format. 29.0 can be represented exactly. – glglgl Aug 07 '13 at 15:16
  • @glglgl Not necessarily. In binary a number is represented as c × 2ⁿ. If c=29 and n=0, then, yes, it can be represented exactly; but in some float representations, c≤0.5, in which case it might not be represented exactly. On my system it happens that float(29.0)==float64(29.0), but this can't be guaranteed. – Antonis Christofides Aug 07 '13 at 15:43
  • @glglgl Besides, the OP said that the debugger says that the value is 29.0; he doesn't say where the value came from. It can easily be a calculated value, and for all we know it might be 29.00000000000001. – Antonis Christofides Aug 07 '13 at 15:45
  • Ah, I'm wrong; he does say it comes from a file; but again, as I explain, you should never bet too much on such things. – Antonis Christofides Aug 07 '13 at 15:55
  • @AntonisChristofides Even then, you have a finite number of digits in an integer number. So no matter if 29 = 1.8125 * 2^4 (1.1101 in binary), .90625 * 2^5 (0.11101b), .453125 * 2^6 (0.011101b), the binary representation is finite. But you are right - if it is 29.000000001, we are lost. And if it comes from a binary file, we are lost as well... – glglgl Aug 07 '13 at 17:49
  • @glglgl I disagree of course, you are wrong when you say I'm right. As you pointed out, I'm wrong about the assumption that 29.0 might not be represented exactly. So, the 29.0 is read from a file (this involves calculations such as 2×10²+9×10) and then it is converted to `float64`. It would be interesting to know why a bit could be lost in all that, but I'm not an expert enough to know. – Antonis Christofides Aug 08 '13 at 07:56
  • @AntonisChristofides What I mean is: if the file is binary AND the value saved there is - maybe as a result of a calculation - NOT exactly 29.0, we indeed may be wrong. But if it is an ASCII file, it should be ok, though. But nevertheless, it is bad to make such comparisons, because the value won't always be 29.0, but maybe 30.4 - and then we are definitely lost. – glglgl Aug 08 '13 at 08:05

2 Answers2

24

You should not compare floats with equality, in any programming language, because you can never know that they are exactly equal. Instead, you should test whether their difference is smaller than a tolerance:

if abs(a - b) < 1e-10

So this problem doesn't have to do with the difference between float and float64 (Python converts them automatically), but with the fundamental problem of comparing floats for equality.

See also What's wrong with using == to compare floats in Java?

Community
  • 1
  • 1
Antonis Christofides
  • 6,990
  • 2
  • 39
  • 57
12

If you are using numpy, the best way to do what Antonis has suggested is to use the function np.allclose(a, b). You can also specify the tolerance (1e-10 from above).

spencerlyon2
  • 9,476
  • 4
  • 30
  • 39