Неправильное округление десятичных дробей до первых 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')

Вернуться на верх