Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare Two Dictionaries - Floating Point

Tags:

python

I am trying to solve this for sometime, tried searching internet and refering some books, yet have not be able to find a solution.

There is one solution proposed here but not sure if there is any other simpler approach. Refer: Comparing Python dicts with floating point values included

Hope you can give some pointers.

Background: Have dict_A which comes with a {key:{key:{key:[value]}}} relationship. This dict_A will go through an iterative process to optimise its value based on several constraints and an optimization objective. Will stop the optimizing process only when the final optimized dict i.e dict_B2 is equal with the dict optimized one cycle before i.e dict_B1. This gives an impression the dict would not be able to be optimized further and this is used to break the iterative cycle.

Question: As the dicts value contain float number, some stored values get changed, perhaps because dictionary stores value in binary format. Do refer to example below, the variation of the first float value in the dictionary.

dict_B1 = {0: {36: {3: [-1], 12: [0.074506333542951425]}}, 1: {36: {2: [-1], 16: [0.048116666666666676], 17: [-1]}}, 2: {}, 3: {36: {5: [-1], 6: [-1], 15: [0.061150932060349471]}}}
dict_B2 = {0: {36: {3: [-1], 12: [0.074506333542951439]}}, 1: {36: {2: [-1], 16: [0.048116666666666676], 17: [-1]}}, 2: {}, 3: {36: {5: [-1], 6: [-1], 15: [0.061150932060349471]}}}

If I use the below, the interative process goes infinite loop and does not break,

if (dict_B1==dict_B2):
   Exit

or,

if (cmp(dict_B1,dict_B2)):
   Exit

Is there any other way to compare the dictionaries say, compare with 15 floating point precision from the 18 floating point precision values ?

I tried storing lesser precision values floats in the dictionary. The problem still persist.

Hope you can assist to point me to the right direction.

Update 1: Jakub's Suggestion

Jakub's suggestion is good. I can create two intermediary lists i.e List_B1 and List_B2 to store the floats, these will be used for comparison and as a flag to decide when to break the iterative process.

The below is the code used to test the case. The second item in List_B2 is purposely altered so the value is way above the precision threshold.

def is_equal(floats_a, floats_b, precision=1e-15):
    return all((abs(a-b) < precision) for a, b in izip(floats_a, floats_b))

List_B1=[0.074506333542951425,0.048116666666666676,0.061150932060349471]
List_B2=[0.074506333542951439,9.048116666666666676,0.061150932060349471]

print "is_equal(List_B1,List_B2):",is_equal(List_B1,List_B2)

for a, b in izip(List_B1, List_B2):
    print a,b, (abs(a-b) < 1e-15)

Results:

is_equal(List_B1,List_B2): True

0.074506333543 0.074506333543 True
0.0481166666667 9.04811666667 False
0.0611509320603 0.0611509320603 True

Strangely is_equal function always returns TRUE which is not correct but when disected the code, it works correctly. Perhaps return all is doing an OR rather than an AND. Still troubleshooting this.

Do share if you have any hints. Will continue to work to solve this. Thanks to Jakub and Julien for all your guidance so far.

rgds Saravanan K

like image 747
Saravanan K Avatar asked Mar 16 '26 01:03

Saravanan K


1 Answers

When comparing floating points, always keep in mind that floats are not of infinite precision and accumulate errors. What you are really interested is if two floats are close enough, not if they are equal

If you want to test if two lists of floats are equal, I would do

def is_equal(floats_a, floats_b, precision=1e-15):
    return all((abs(a-b) < precision) for a, b in izip(floats_a, floats_b))
like image 111
Jakub M. Avatar answered Mar 18 '26 15:03

Jakub M.