3

This is something you can try in the interpreter, can anyone explain me why? Note: This problem is different from Is floating point math broken? because my answers are not a little off, but way off and my question is about decimal, not about the built in float.

from decimal import getcontext, Decimal
a = Decimal(".110001"+"0"*17+"1"+"0"*95+"1"+"0"*599+"1"+"0"*4319+"1")
b = Decimal(".220002"+"0"*17+"2"+"0"*95+"2"+"0"*599+"2"+"0"*4319+"2")
b-a == a # Returns False while it should be True
b-a-a # Returns Decimal('-1.000000000000000000000000000E-120')
Laurens
  • 63
  • 3
  • 1
    Just to complete the picture: "[...] not a little off, but way off [...]". That's not true. `-1.000000000000000000000000000E-120` is very little. And presumably, overlooking the scientific notation is the very crux of the matter here. – pasbi Dec 02 '19 at 10:30
  • 1
    The linked duplicate is not a good one: it's primarily about errors resulting from floats being stored in binary internally (the What You See Is Not What You Get nature of binary floating-point when expressed in decimal), and it doesn't help with diagnosis or solution of this issue. – Mark Dickinson Dec 02 '19 at 20:47

1 Answers1

4

The default Decimal precision is 28 decimals, so you are loosing data, b - a is 0.1100010000000000000000010000. You can set it with getcontext().prec

a = Decimal(".110001" + "0" * 17 + "1" + "0" * 95 + "1" + "0" * 599 + "1" + "0" * 4319 + "1")
b = Decimal(".220002" + "0" * 17 + "2" + "0" * 95 + "2" + "0" * 599 + "2" + "0" * 4319 + "2")
getcontext().prec = max(len(str(a)), len(str(a)))
print(b-a == a) # True
Guy
  • 46,488
  • 10
  • 44
  • 88