ma7555
ma7555

Reputation: 410

Numpy array float precision is not deterministic

So when running the below snipet

import numpy as np

X = np.array([-0.20000008], dtype=np.float32)
np.floor((X + 1) / 0.04)
array([20.], dtype=float32)

The output is obviously wrong as the result should be below 20 and should floor to 19

I get that this is precision errors but running all below samples produce correct results although it should have similar precision

X = np.array([-0.20000008], dtype=np.float32).item()
np.floor((X + 1) / 0.04) # 19.0
X = np.float32(-0.20000008)
np.floor((X + 1) / 0.04) # 19.0
X = np.array([-0.20000008], dtype=np.float32)
np.floor(X / 0.04 + 1 / 0.04) # array([19.], dtype=float32)
np.floor(np.multiply((X + 1), 1/0.04)) # array([19.], dtype=float32)

If I cast it as float64 it works too but it is very expensive cast for my application. Any solutions while sticking to float32?

Upvotes: 2

Views: 806

Answers (1)

flawr
flawr

Reputation: 11628

Let's try to understand the first two of the three examples on the bottom first:

In the first example

np.array([-0.20000008], dtype=np.float32).item()

will produce a native python float() which is a 64 bit, so no surprizes here.

In the second example you have create a numpy 32-bit scalar (shape==(), type==np.float32) which will get treated more or less like other scalars: So as soon as you add an int (1), the result will be a 64 bit number.

The interesting case now is actually your initial piece of code and the third example: In both cases you now have an array (shape==(1,), type=np.ndarray). In the case of operations with an array and a scalar, the type of the array will be preserved. So now we actually just have the issue that the distributive law does not hold for floating point numbers. Here you're doing computations that rely on the least significant bits of floating point numbers.

Upvotes: 3

Related Questions