Почему следующий код:
from decimal import Decimal
result = Decimal('0') * Decimal('0.8881783462119193534061639577')
print(result)
вернуть 0E-28 ?
Я проследил это до следующего кода в модуле :
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
Код, по-видимому, следует Спецификации десятичной арифметики , которая явно не предлагает, что делать, когда мы умножаем на ноль, ссылаясь на «специальные числа» из другого стандарта, который также не указывает, что мы делаем, когда умножаем целое число на ноль :) Итак, десятичная библиотека делает то, что указано явно:
Вопрос: зачем возвращать коэффициент и показатель степени (т.е. 0E-28), если один из операндов нулевой? Мы уже знаем, что это за коэффициент, когда вызываем функцию умножения. Почему бы просто не вернуть ноль?
Рэймонд Хеттингер дал исчерпывающее объяснение на cpython github:
В Арифметические операции раздел правил арифметических операций говорит нам:
Нули в конце не удаляются после операций.
Есть тестовые примеры, охватывающие умножение на ноль. Вот некоторые из multiple.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
А это из примеров:
mulx053 multiply 0.9 -0 -> -0.0
В разделе «Сводка арифметики» мотивация объясняется на высоком уровне:
Арифметика была разработана как десятичная расширенная арифметика с плавающей запятой, непосредственно реализующая правила, которым людей учат в школа. До заданной рабочей точности точные неокругленные результаты по возможности (например, 0,9 ÷ 10 дает 0,09, а не 0,089999996), а конечные нули правильно сохраняются в большинстве операций (1,23 + 1,27 дает 2,50, а не 2,5). Где результаты превышает рабочую точность, применяются правила с плавающей запятой.
Подробнее в разделе FAQ Почему важны нули в конце дробной части?.