3

I was running a small python test I wrote against some data and got some weird results. Boiled it down to this:

priceDiff = 219.92 - 219.52
if(priceDiff >= .40):
   print "YES"
else:
   print "NO"

The result is "NO"

Why is 0.40 not >= .40?

Alex
  • 9,313
  • 1
  • 39
  • 44
yellowandy
  • 89
  • 1
  • 1
  • 7
  • 1
    Try `print(219.92 - 219.52)`. You will be surprised. – DYZ Jan 17 '17 at 07:06
  • I tried float.hex(priceDiff) and float.hex(.40), yes I'm surprised although i suppose I should be. Been a while since I've had to wrangle floating point numbers but I just assumed this would work (since I was just comparing data that contained prices) – yellowandy Jan 17 '17 at 07:12
  • You don't have to go that far. `priceDiff` is 0.39999999999997726, which is less than .4. – DYZ Jan 17 '17 at 07:13
  • 3
    Possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Stephen Rauch Jan 17 '17 at 07:15
  • "Never test floating-point numbers for equality". In this case one option might be to code a little bit of wriggle-room, setting the boundary at a value that has less significance and might be "impossible", such as `priceDiff >= 0.3995` (or `0.39999995`). For complete predictability and accuracy, use Decimal not float. – nigel222 Jan 17 '17 at 09:11
  • When working with prices it is advised to use integer number of cents internally, to prevent these kind of problems. – Rob Jan 17 '17 at 09:43

2 Answers2

4

Python offers controlled environment to work with floats in the form of "Decimal". It provides multiple options to control/tweak the rounding with amount of rounding along with different strategies.(https://docs.python.org/3.5/library/decimal.html#rounding-modes).

from decimal import Decimal, ROUND_HALF_EVEN
a = Decimal(219.92).quantize(Decimal('.01'), rounding=ROUND_HALF_EVEN)
b = Decimal(219.52).quantize(Decimal('.01'), rounding=ROUND_HALF_EVEN)
priceDiff = a - b
cmp = Decimal(0.40).quantize(Decimal('.01'), rounding=ROUND_HALF_EVEN)

if priceDiff.compare(cmp) >= 0:
    print "YES"
else:
    print "NO"

print(d)
print(d2)
print(priceDiff)
print(cmp)

IMHO this is better interms of readability and implementaion of calculations that are precision sensitive w.r.t application. Hope this helps

Anuragh27crony
  • 2,957
  • 1
  • 19
  • 29
3

From Documentation

Representation error refers to the fact that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many others) often won’t display the exact decimal number you expect:

0.1 + 0.2
0.30000000000000004
GAVD
  • 1,977
  • 3
  • 22
  • 40