3

Why are these values different and how does it differ from each other?

>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')

>>> Decimal(0.1) + Decimal(0.1) + Decimal(0.1) - Decimal(0.3)
Decimal('2.775557561565156540423631668E-17')
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Jose Angel
  • 328
  • 2
  • 16
  • Because *a `float` is inherently imprecise*. That is *why `decimal.Decimal` exists in the first place* – juanpa.arrivillaga Apr 19 '19 at 01:21
  • 1
    (won't reopen without discussion) I disagree this is a duplicate. The question is why is the precision accurate when `Decimal()` takes in a string – TerryA Apr 19 '19 at 01:21
  • Have you tried to do `Decimal("0.1") == 0.1` and `Decimal(0.1) == 0.1`? – ggrelet Apr 19 '19 at 01:22
  • 1
    The precision is already lost when you represent a number with a floating point, and passing an imprecise number to the `Decimal` constructor will not recover the lost precision. – blhsing Apr 19 '19 at 01:23
  • 1
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Wai Ha Lee Apr 19 '19 at 01:44

2 Answers2

3

This is quoted from Decimal module source code which explains pretty good, if the input is float, the module internally calls the class method "Decimal.from_float()":

Note that Decimal.from_float(0.1) is not the same as Decimal('0.1'). Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is 0x1.999999999999ap-4. The exact equivalent of the value in decimal is 0.1000000000000000055511151231257827021181583404541015625.

Mahmoud Elshahat
  • 1,873
  • 10
  • 24
0

When you pass '0.1' as string, the decimal is converted to a float, without losing precision, but it loses precision when you pass the float directly as 0.1, as you can see below

>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal('0.1')
Decimal('0.1')

This then leads to all sort of wierd results

>>> Decimal(0.3) - Decimal(0.1) + Decimal(0.1) + Decimal(0.1)
Decimal('0.3999999999999999944488848768')
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40