2

How to test if two floats are identical until a specific digit?

I tried,

aa1 = 0.043403
aa2 = 0.043392
print(int(aa1*1000) == int(aa2*1000))
>> True

I want to follow this way, but my data include NAN value, it cannot convert it to intro anyhow. I also tried math.isclose but it's tricky.

For example, I wanted to keep until 3 digits and applied the math.isclose

aa3 = 0.013041
aa4 = 0.012545
aa6 = 0.012945

print(math.isclose(aa3, aa4, abs_tol = 0.0001))
>>Flase
print(math.isclose(aa3, aa5, abs_tol = 0.0001))
>>True

But I want to get False for both cases.

Any simple idea??

Dong-gyun Kim
  • 411
  • 5
  • 23
  • Do you want to test the rounded values of the numbers up to 3 digits or just a cut after 3 digits? – Jonas Jun 30 '20 at 12:01
  • I just want to ignore it after 3. – Dong-gyun Kim Jun 30 '20 at 12:05
  • Do you really care about digit? Else "rel_tol" is close enough, but for decimal digits, you need to convert to decimal, so you should convert to string and compare strings [take care about lenght, dot, exponent,..] – Giacomo Catenazzi Jun 30 '20 at 12:30
  • @GiacomoCatenazzi Yes. I need specific Digit criteria – Dong-gyun Kim Jun 30 '20 at 12:32
  • 1
    Judging from your comments to the other answers I think you have a fundamental misunderstanding of python floating point types. While not mandated, you'll find that every implementation of python uses a IEEE 754 binary floating point type. Those types do not have base 10 digits, they have base 2 digits. Thus there is no such value as .1 in one of these floating point types. Your comment below "... 0.0014, 0.001399, threshold = 0.00001. Should be False..." is problematic because neither one of those values exists in a floating point type. Suggest you consider the `decimal` module. – President James K. Polk Jun 30 '20 at 13:18
  • @PresidentJamesK.Polk I totally didn't know there is a concept behind the Python float. I will figure it out later – Dong-gyun Kim Jun 30 '20 at 13:23

3 Answers3

3

Create a function which takes 2 numbers, a and b, and it has a preset threshold value. If the difference between a and b is less than the treshold, return True.

def isSame(a, b):
    return abs(a - b) < treshold

Where treshold can be a float. 0.0001 will ignore after the 3rd digit. Or cut the number as a string after 3 digits, and convert it back to float.

Edit, cut off method:

def isSame(a, b, digit):
    return float(str(a)[0:digit+2]) == float(str(b)[0:digit+2])

We ignore every number after the 3rd digit, in case your digit = 3.

nagyl
  • 1,644
  • 1
  • 7
  • 18
2

You can do it easily using assertAlmostEqual Below is the code

import unittest

unittest.TestCase.assertAlmostEqual(value1,valu2,decimalUpto)

In your case it can be like

unittest.TestCase.assertAlmostEqual(aa1 ,aa2 ,3)

Good Luck

Imran
  • 775
  • 7
  • 19
  • It brings an error AttributeError: 'float' object has no attribute '_formatMessage' – Dong-gyun Kim Jun 30 '20 at 12:08
  • You have to use it in class .. There are many examples [here](https://programtalk.com/python-examples/unittest.TestCase.assertAlmostEqual/) Have a look on them – Imran Jun 30 '20 at 12:18
0

rel_tol should be enough:

import math

def check(a, b):
    print(math.isclose(a, b, rel_tol=0.001), abs(a/b - 1.) < 0.001)

check(aa1, aa2)
check(aa3, aa4)
check(aa3, aa6)

gives the expected

True True
False False
False False

Note: the second calculation do not handle two equal zeros: easy to add. Not sure if underflow will affect it.

Giacomo Catenazzi
  • 8,519
  • 2
  • 24
  • 32