Search code examples
pythonpython-3.xnumpynumba

very strange results of numpy.astype with numba


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?


Solution

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