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?
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.