getcontext().prec работает не так, как ожидалось

#python #decimal #precision

#python #десятичный #точность

Вопрос:

 from decimal import *

getcontext().prec = 8
print(getcontext(),"n")

x_amount = Decimal(0.025)
y_amount = Decimal(0.005)

test3 = x_amount - y_amount

print("test3",test3)

  

Вывод:

Контекст (prec= 8, округление = ROUND_HALF_EVEN, Emin=-999999, Emax= 999999, заглавные буквы = 1, зажим = 0, флаги = [], ловушки = [НедейстВительная операция, DivisionByZero, переполнение]) 


тест3 0.020000000
 

Почему это возвращает значение ‘test3’ с точностью до 9 знаков после запятой, если точность установлена на 8 в соответствии с примером, упомянутым здесь?

И он изменится на 3 знака после запятой, если я заменю строки 6 и 7 в приведенном выше коде на:

 x_amount = Decimal('0.025')
y_amount = Decimal('0.005')
  

Я использую десятичные дроби в финансовом приложении и нахожу это очень запутанным в отношении преобразований, операций, определения, точности и т.д. Есть ли ссылка, на которую я могу сослаться, чтобы узнать подробности использования десятичных дробей в python?

Комментарии:

1. Не имеет прямого отношения к вашей проблеме, но использование float для инициализации Decimal всегда неверно. Никогда не инициализируйте a Decimal из a float ; это просто воспроизводит неточность float в Decimal . Передача a str — единственный безопасный способ сделать это. Когда я делаю это с str помощью и использую строки, которые являются более точными, чем prec , начальные значения более точны, но все математические операции обеспечивают ожидаемый уровень точности (например Decimal("0.025") Decimal("0.123456789") , gets Decimal('0.14845679') , который имеет ровно восемь мест точности.

2. В случае Decimal('0.025') - Decimal('0.005') нет необходимости добавлять до 8 нулей в конце, потому что вы получаете точный результат. Однако десятичное число, инициализированное с плавающей точкой 0.025 Decimal('0.0025000000000000000520417042793042128323577344417572021484375') , равно, поэтому результат обрезается. Однако это не объясняет, почему вы получаете 9 знаков после запятой вместо 8. Кажется, он начинает отсчет с первого ненулевого места, но это всего лишь предположение.

Ответ №1:

Ваш результат верен. prec указывает, сколько цифр нужно сохранить, начиная с самой значимой ненулевой цифры. Итак, в вашем результате:

 test3 0.020000000
         ^^^^^^^^
  

цифры, на которые указывают каретки, являются ожидаемыми восемью цифрами, охватываемыми точностью. Причина, по которой вы получаете их все, заключается в том, что использование float для инициализации Decimal всегда неверно. Никогда не инициализируйте a Decimal из a float ; это просто воспроизводит неточность float в Decimal (попробуйте print x_value и y_value увидите мусор). Передача a str — единственный безопасный способ сделать это.

Когда вы делаете это с str помощью, отдельные Decimal элементы «знают» последнюю цифру значимой точности, которой они обладают, и она доходит только до третьего знака после запятой, поэтому результат не включает точность за пределами этой точки. Если вы хотите prec , чтобы сработало ограничение, попробуйте инициализировать один из аргументов с большей точностью, чем prec , и результат будет округлен до prec .