very strange results of numpy.astype with numba

Viewed 164

WHY? very strange... In python, if we test np.astype() with numba, the following will print some results as

x:     [-6. -5. -4. -3. -2. -1.  0.  1.  2.  3.  4.  5.]
x-int: [-6 -5 -4 -3 -2 -1  0  1  2  3  4  5]

@numba.njit
def tt():
    nn = 3
    x = np.linspace(0, 4*nn-1, 4*nn)-2*nn
    print(x)
    print(x.astype(np.int32))

BUT, if I change the line of x to be x = np.linspace(0, 8*nn-1, 8*nn)-4*nn, the result will be strange as

x: [-12. -11. -10.  -9.  -8.  -7.  -6.  -5.  -4.  -3.  -2.  -1.   0.   1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.]
x-int: [-12 -11 -10  -9  -8  -7  -6  -5  -4  -3  -2  -1   0   0   2   3   4   5   6   7   8   9  10  11]

There are two 0 in x-int? why?

1 Answers

tl;dr: This is a reported bug of Numba.

The issue come from a slightly inaccuracy in the Numba linspace function related to floating-point rounding. Here is an example to highlight the issue:

def tt_classic():
    nn = 3
    return np.linspace(0, 8*nn-1, 8*nn)-4*nn

@numba.njit
def tt_numba():
    nn = 3
    return np.linspace(0, 8*nn-1, 8*nn)-4*nn

print(tt_classic()[13])
print(tt_numba()[13])

Here is the result:

1.0
0.9999999999999982

As you can see, the Numba implementation does not return a exact value. While this problem cannot be avoided for big values, it can be considered as a bug for such small value since they can be represented exactly (without any loss of precision) on any IEEE-754 platform.

As a result, the cast will then truncate the floating point number 0.9999999999999982 to 0 (and not to the nearest integer). If you want a safe conversion (ie. workaround), you can explicitly tell Numpy/Numba to do it. Here is an example:

@numba.njit
def tt():
    nn = 3
    x = np.linspace(0, 4*nn-1, 4*nn)-2*nn
    np.round(x, 0, x)
    print(x)
    print(x.astype(np.int32))

This bug as been reported on the Numba bug tracker here. You may also be interested in this related Numba issue.

Related