0

Decimal(0.001) * -1 is not the same as Decimal(-0.001).

Similarly, Decimal(0.001) * Decimal(-1) is not the same as Decimal(-0.001).

Am I mad? How is it failing at such a simple task?

  • 3
    `Decimal(0.001)` is not the same as `Decimal('0.001')`. – bereal May 10 '21 at 12:05
  • Note that ``Decimal('0.001') * -1`` is the same as ``Decimal('-0.001')``. Your issue is the floating point math *before* conversion to ``Decimal``. – MisterMiyagi May 10 '21 at 12:06
  • 2
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – MisterMiyagi May 10 '21 at 12:06
  • As per @MisterMiyagi's comment, if you print each of the values you'll see the problem. Printing things is a great first debugging step. – Kemp May 10 '21 at 12:07
  • So is `Decimal(0.001) * Decimal(-1)` the correct way to use the package? I.e. never use floats as a calculation, ever? – namesake May 10 '21 at 12:07
  • @namesake ``Decimal('0.001')`` is the correct way. Note the quotes. – MisterMiyagi May 10 '21 at 12:08
  • @namesake Just the opposite. Use quoted strings. Otherwise there's no point and you might as well use ordinary floats. The whole point of using the decimal package is to *avoid* floating point arithmetic. So use `Decimal('0.001')` to properly construct the value. – Tom Karzes May 10 '21 at 12:08
  • 1
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – AMC May 10 '21 at 14:48

1 Answers1

1

This is another variant of "Is floating point math broken".

When you do Decimal(0.001), you're turning a non-exact floating point value into a Decimal (that valiantly makes it exact):

>>> Decimal(0.001)
Decimal('0.001000000000000000020816681711721685132943093776702880859375')

When you use a string representation, you get the exact Decimal too.

>>> Decimal("0.001")
Decimal('0.001')

When you do math on a Decimal, the decimal context's precision value abides, which is why you see a truncation/rounding:

>>> Decimal(-0.001)
Decimal('-0.001000000000000000020816681711721685132943093776702880859375')
>>> Decimal(-0.001) * -1
Decimal('0.001000000000000000020816681712')
AKX
  • 152,115
  • 15
  • 115
  • 172