PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Wednesday, August 10, 2022

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

 August 10, 2022     decimal, floating-point, precision, python, python-3.x     No comments   

Issue

I am using Decimal with strings to avoid the typical problem

I have two dictionaries that have the same keys and values but with the keys in a different order. The sum of the values of these dictionaries should be zero. However, it is not zero when I sum them in a certain order.

These are my dictionaries and the comparisons I made to make sure the values are the same:

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

HERE IS THE PROBLEM:

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

HERE IS WHEN IT GETS EVEN WEIRDER I wanted to make sure this was because of the order, so I inverted the order

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

So my question is just..... WHY... why python sum is not commutative?


Solution

In general, floating-point arithmetic is not commutative. The Decimal class is floating-point.

The default precision for arithmetic operations with Decimal is 28 digits. You can change this by altering the context. For example, increase the precision to 40 digits with the following code:

import decimal
decimal.getcontext().prec = 40

If you want to raise an exception for inexact arithmetic, you can configure this explicitly. You might set up the context explicitly, for example:

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


Answered By - Dietrich Epp
Answer Checked By - Robin (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing