为什么 Python 小数和不可交换(当我改变顺序时结果不同)

Why Python Decimal sum is not commutative (different result when I change the order)

我对字符串使用 Decimal 以避免典型问题

我有两个字典,它们具有相同的键和值,但键的顺序不同。 这些字典的值之和应该为零。但是,当我按一定顺序对它们求和时,它不是零。

这些是我的字典和我为确保值相同而进行的比较:

a = {'key_A': Decimal('0'),
    'key_B': Decimal('-1002708'),
    'key_C': Decimal('3965.5752'),
    'key_D': Decimal('991393.8'),
    'key_E': Decimal('-991393.8'),
    'key_F': Decimal('1173.30984201680672268907563'),
    'key_G': Decimal('-7348.6248'),
    'key_H': Decimal('6175.31495798319327731092437'),
    'key_I': Decimal('-741'),
    'key_J': Decimal('0'),
    'key_K': Decimal('4641'),
    'key_U': Decimal('-3900'),
    'key_L': Decimal('1038000'),
    'key_M': Decimal('0'),
    'key_N': Decimal('0'),
    'key_O': Decimal('0'),
    'key_P': Decimal('-3965.5752'),
    'key_Q': Decimal('0'),
    'key_R': Decimal('0'),
    'key_S': Decimal('-15570'),
    'key_T': Decimal('-19722')}

b = {'key_C': Decimal('3965.5752'),
    'key_D': Decimal('991393.8'),
    'key_B': Decimal('-1002708'),
    'key_K': Decimal('4641'),
    'key_U': Decimal('-3900'),
    'key_J': Decimal('0'),
    'key_A': Decimal('0'),
    'key_G': Decimal('-7348.6248'),
    'key_H': Decimal('6175.31495798319327731092437'),
    'key_I': Decimal('-741'),
    'key_R': Decimal('0'),
    'key_N': Decimal('0'),
    'key_T': Decimal('-19722'),
    'key_P': Decimal('-3965.5752'),
    'key_M': Decimal('0'),
    'key_L': Decimal('1038000'),
    'key_F': Decimal('1173.30984201680672268907563'),
    'key_O': Decimal('0'),
    'key_Q': Decimal('0'),
    'key_E': Decimal('-991393.8'),
    'key_S': Decimal('-15570')}

print(sorted(list(a.keys()))==sorted(list(b.keys()))) # "True" so the keys are the same

print(len(a), len(b)) # "21 21" the length are the same


keys = sorted(list(a.keys()))
for k in keys:
 assert a[k]==b[k] # never throws exception so the values are the same

sum_d = lambda d: sum(d[key] for key in d) # a function that sums all the values in a dictionary

问题来了:

print(sum_d(a), sum_d(b)) # "4E-22 0E-21" EVEN WHEN THE VALUES ARE THE SAME THE SUMS ARE NOT WTF

这是它变得更奇怪的时候 我想确定这是因为顺序,所以我颠倒了顺序

a_new = {key:a[key] for key in b.keys()}
b_new = {key:b[key] for key in a.keys()}
  
print(sum_d(a_new), sum_d(b_new)) # "0E-21 4E-22" THE VALUES INVERTED SO IT IS BECAUSE OF THE ORDER

所以我的问题只是..... 为什么... 为什么python 总和不可交换?

您在 b 中有两个“key_H”键。

去掉b中的'key_H': Decimal('6175.31495798319327731092437'),行后,求和结果是一样的

一般来说,浮点运算是不可交换的。 Decimal class 是浮点数。

Decimal 算术运算的默认精度为 28 位。您可以通过更改上下文来更改此设置。例如,使用以下代码将精度提高到 40 位:

import decimal
decimal.getcontext().prec = 40

如果你想为不精确的算术抛出异常,你可以显式配置它。您可以显式设置上下文,例如:

decimal.setcontext(decimal.Context(
    traps=[decimal.Inexact],
))