Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Less than or equal to operator for numpy floating points?

I realize the np.islcose() function can be used to safely check floating point numbers for equality. What's tripping me up at the moment, though, is that I get varied results from using the standard <= operator. For example:

add_to = 0.05
value64 = np.float64(0.3) + add_to*4
value32 = np.float32(0.3) + add_to*4
threshold = 0.5
print('is close?')
print(np.isclose(value64, threshold))
print(np.isclose(value32, threshold))
print('is less than or equals to?')
print(value64 <= threshold)
print(value32 <= threshold)

Gives me

is close?
True
True
is less than or equals to?
True
False

Does anyone have a sensible workaround for this? I thought one option might be overload the python comparison operators for numpy floating points, and (within that function) round both floats up to, say, their 8th decimal place. But this is in a context where speed is somewhat important, and that feels a bit cumbersome.

Thanks in advance for any help!

like image 863
Chris J Harris Avatar asked Dec 17 '22 17:12

Chris J Harris


2 Answers

You can define functions that combine < and > with isclose.

def approx_lte(x, y):
    return x <= y or np.isclose(x, y)
def approx_gte(x, y):
    return x => y or np.isclose(x, y)

These are analogous to <= and >=, except they also use np.isclose() to test for equality.

like image 168
Barmar Avatar answered Dec 20 '22 06:12

Barmar


According to this Difference between Python float and numpy float32, there is a difference between how python sees np.float32 and np.float64. If you actually check the intermediate values of value64 and value32, you'll see:

value32 = 0.5000000119209289
value64 = 0.5

which explains why print(value32 <= threshold) evaluates to false. Due to binary errors I doubt rounding to the eighth decimal place would be safe, as with value32 you will have 0.50000001.

You should also consider that the time it takes to round a number is absolutely tiny, and still has to be used in the case of

np.float64(0.1) + np.float64(0.2)

as this evaluates to 0.30000000000000004, and so you would have errors when using a >= or <=. This error also occurs if you use the decimal library. In short, there are some numbers that you can't really avoid having some kind of error on. The only way I know of to circumvent this is to round.

I tried testing a bunch of combinations with rounding and without, and it was so quick I wasn't able to record the time differences over 10000 iterations, so unless you're trading stocks or training a neural network for weeks I don't think rounding a number is something you need to be worried about.

If you're worried about the arbitrary nature of where to round a number to, I would search for a string of 0's longer then 4 following a significant figure, then cut it off there.

like image 38
Recessive Avatar answered Dec 20 '22 06:12

Recessive