Неправильное округление десятичных дробей до первых 2 цифр суммы в python 3.7 и Django
Пусть будет 3 поля Django:
INPUT = models.DecimalField(max_digits=20, decimal_places=3, default=0)
RESULT = models.DecimalField(max_digits=20, decimal_places=3, default=0)
RATE = models.DecimalField(max_digits=12, decimal_places=5, default=1)
RATE
всегда Decimal('1.00000')
.
Я хочу иметь RESULT = INPUT * RATE
и так как источник либо из базы данных, либо из API, я использую:
RESULT = Decimal(INPUT) * Decimal(RATE)
Я не знаю почему, но в некоторых случаях (≈ 2%) я заканчиваю с цифрами, которые вы видите в следующей таблице. Существует округление до первых двух цифр.
Вы знаете, что может вызвать это? Я не вижу ничего в коде, что могло бы это сделать, и я не знаю. Оба столбца должны быть равны.
RESULT INPUT
610.000 609.000
3700.000 3743.520
1200.000 1159.000
570.000 573.300
61.000 61.470
1300.000 1321.550
44.000 43.730
130.000 125.770
18.000 18.500
100.000 99.590
41.000 40.650
95.000 94.880
19.000 18.710
36.000 35.640
120.000 118.800
12.000 12.290
11.000 11.260
1.000 1.030
160.000 155.970
190.000 186.850
51.000 50.770
130.000 128.150
12.000 12.290
11.000 11.260
25.000 24.940
24.000 23.640
Похоже, что причиной является точность десятичного контекста:
getcontext().prec = 2
Где-то в коде он был установлен и никогда не сбрасывался. Вот что происходит, когда точность равна 2:
>>> import decimal
>>> decimal.getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[InvalidOperation, Inexact, FloatOperation, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])
>>> decimal.getcontext().prec = 2
>>> decimal.getcontext()
Context(prec=2, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[InvalidOperation, Inexact, FloatOperation, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])
>>> Decimal(3.21)
Decimal('3.20999999999999996447286321199499070644378662109375')
>>> Decimal(3.21) * Decimal(1)
Decimal('3.2')
>>> Decimal(58341)
Decimal('58341')
>>> Decimal(58341) * Decimal(1)
Decimal('5.8E+4')