Why does the following code:
from decimal import Decimal
result = Decimal('0') * Decimal('0.8881783462119193534061639577')
print(result)
return 0E-28 ?
I've traced it to the following code in the module:
if not self or not other:
ans = _dec_from_triple(resultsign, '0', resultexp)
# Fixing in case the exponent is out of bounds
ans = ans._fix(context)
return ans
The code appears to follow Decimal Arithmetic Specification, which doesn't explicitly suggest what to do when we multiply by zero, referring to 'special numbers' from another standard, which also doesn't specify what we do when we multiply an integer by zero :) So the decimal library does the thing that is explicitly specified:
Question: what is the need to return the coefficient and exponent (i.e, 0E-28) if one of the operands is a zero? We already know what that coefficient is when calling the multiplication function. Why not just return zero?
Raymond Hettinger has given a comprehensive explanation at cpython github:
In Arithmetic Operations, the section on Arithmetic operations rules tells us:
Trailing zeros are not removed after operations.
There are test cases covering multiplication by zero. Here are some from multiply.decTest:
-- zeros, etc.
mulx021 multiply 0 0 -> 0
mulx022 multiply 0 -0 -> -0
mulx023 multiply -0 0 -> -0
mulx024 multiply -0 -0 -> 0
mulx025 multiply -0.0 -0.0 -> 0.00
mulx026 multiply -0.0 -0.0 -> 0.00
mulx027 multiply -0.0 -0.0 -> 0.00
mulx028 multiply -0.0 -0.0 -> 0.00
mulx030 multiply 5.00 1E-3 -> 0.00500
mulx031 multiply 00.00 0.000 -> 0.00000
mulx032 multiply 00.00 0E-3 -> 0.00000 -- rhs is 0
mulx033 multiply 0E-3 00.00 -> 0.00000 -- lhs is 0
mulx034 multiply -5.00 1E-3 -> -0.00500
mulx035 multiply -00.00 0.000 -> -0.00000
mulx036 multiply -00.00 0E-3 -> -0.00000 -- rhs is 0
mulx037 multiply -0E-3 00.00 -> -0.00000 -- lhs is 0
mulx038 multiply 5.00 -1E-3 -> -0.00500
mulx039 multiply 00.00 -0.000 -> -0.00000
mulx040 multiply 00.00 -0E-3 -> -0.00000 -- rhs is 0
mulx041 multiply 0E-3 -00.00 -> -0.00000 -- lhs is 0
mulx042 multiply -5.00 -1E-3 -> 0.00500
mulx043 multiply -00.00 -0.000 -> 0.00000
mulx044 multiply -00.00 -0E-3 -> 0.00000 -- rhs is 0
mulx045 multiply -0E-3 -00.00 -> 0.00000 -- lhs is 0
And this from the examples:
mulx053 multiply 0.9 -0 -> -0.0
In the Summary of Arithmetic section, the motivation is explained at a high level:
The arithmetic was designed as a decimal extended floating-point arithmetic, directly implementing the rules that people are taught at school. Up to a given working precision, exact unrounded results are given when possible (for instance, 0.9 ÷ 10 gives 0.09, not 0.089999996), and trailing zeros are correctly preserved in most operations (1.23 + 1.27 gives 2.50, not 2.5). Where results would exceed the working precision, floating-point rules apply.
More detail in given in the FAQ section Why are trailing fractional zeros important?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With