young_leamer
young_leamer

Reputation: 43

Python "decimal" package gives wrong results

I tried to compute the following by setting getcontext().prec = 800.

>>> from decimal import *
>>> getcontext().prec = 800
>>> Decimal(22.0) / Decimal ( 10.0) - Decimal ( 0.2 )
Decimal('1.999999999999999988897769753748434595763683319091796875')
>>> 

But the expected result is 2. Where am I doing wrong?

Upvotes: 3

Views: 1496

Answers (4)

Joni
Joni

Reputation: 111389

Pass strings to the Decimal constructor instead of floats: Decimal('0.2') gives the result you expect, Decimal(0.2) doesn't.

This is because:

If value is a float, the binary floating point value is losslessly converted to its exact decimal equivalent. This conversion can often require 53 or more digits of precision. For example, Decimal(float('1.1')) converts to Decimal('1.100000000000000088817841970012523233890533447265625').

https://docs.python.org/3/library/decimal.html#decimal.Decimal

Upvotes: 3

Dennis Sparrow
Dennis Sparrow

Reputation: 978

When you construct a Decimal from a floating-point number, you get the exact value of the floating-point number, which may not precisely match the decimal value because that's how floating-point numbers work.

If you want to do precise decimal arithmetic, construct your Decimal objects from strings instead of floating-point numbers:

>>> Decimal('22.0') / Decimal('10.0') - Decimal('0.2')
Decimal('2.0')

Upvotes: 5

bfris
bfris

Reputation: 5835

It seems that you have to give numbers as a string to prevent them from being evaluated as floating point.

from decimal import *
getcontext().prec = 800
print(Decimal(0.2))
print(Decimal('0.2'))
print(Decimal('22.0') / Decimal ('10.0') - Decimal ('0.2' ))

which gives

0.200000000000000011102230246251565404236316680908203125
0.2
2.0

Upvotes: 1

Guilherme Martin
Guilherme Martin

Reputation: 847

The prec attribute defines how many numbers after the decimal point will round your number. For example, if you expect 2.00, its value should be 3. Or if you want to round the number so that it has no decimal places you can use 1 as a parameter.

from decimal import *

getcontext().prec = 1
print(Decimal(22.0) / Decimal ( 10.0) - Decimal ( 0.2 ))
>> 2

Upvotes: 0

Related Questions