1

This I imagine is extremely simple - but why in the following are the two values for y not == 0? I thought the whole point of the decimal module was to get rid of the float dust ...The following is an extremely simplified version of a mathematical routine that passes numbers around as variables.

from decimal import * 
getcontext().prec = 2

q = Decimal(0.01)

x = Decimal(0.10) * Decimal(0.10)

y = Decimal(x) - Decimal(q)

print(x,y, Decimal(y))

'''
x== 0.010 
y== -2.1E-19 
Decimal(y) == -2.1E-19
'''

3 Answers 3

3

Try specifying the numbers as strings

>>> Decimal('0.10') * Decimal('0.10') - Decimal('0.0100')
>>> Decimal('0.000')
Sign up to request clarification or add additional context in comments.

1 Comment

Hey thanks, it's good to know Decimal like strings, I edited the question a bit in light of your response though
3

The float literal 0.10 is not precisely the mathematical number 0.10, using it to initialize Decimal doesn't avoid the float precision problem.

Instead, using strings to initialize Decimal can give you expected result:

x = Decimal('0.10') * Decimal('0.10')
y = Decimal(x) - Decimal('0.010')

2 Comments

Hey thanks, it's good to know Decimal like strings, I edited the question a bit in light of your response though
No need to cast x to Decimal, it is already. The usual arithmetic operators on Decimals produce a Decimal result.
2

This is a more detailed explanation of the point made in existing answers.

You really do need to get rid of the numeric literals such as 0.1 if you want exact decimal arithmetic. The numeric literals will typically be represented by IEEE 754 64-bit binary floating point numbers.

The closest such number to 0.1 is 0.1000000000000000055511151231257827021181583404541015625. Its square is 0.01000000000000000111022302462515657123851077828659396139564708135883709660962637144621112383902072906494140625, which is not the same as the closest to 0.01, 0.01000000000000000020816681711721685132943093776702880859375.

You can get a clearer view of what is going on by removing the prec =2 context, allowing more precise output:

from decimal import * 
q = Decimal(0.01)
x = Decimal(0.10) * Decimal(0.10)
y = Decimal(x) - Decimal(q)
print(q)
print(x)
print(y)

Output:

0.01000000000000000020816681711721685132943093776702880859375
0.01000000000000000111022302463
9.020562075127831486705690622E-19

If you had used string literals, as suggested by the other responses, the conversion to Decimal would have been done directly, without going through binary floating point. Both 0.1 and 0.01 are exactly representable in Decimal, so there would be no rounding error.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.