使用 Numba 的 @jit 导致数学与 Python 中使用的 Numpy 的 float32 不一致

Using Numba's @jit causing math inconsistencies with Numpy's float32 being used in Python

当使用 Numba 的 @jit 和 Numpy 的 float32 数据类型时,我得到了?截断?问题。这主要是噪音,因为它远远超出了我关心的小数位数 - 大约第 7 或第 8 位 - 但知道发生了什么以及我是否可以修复它仍然是件好事。

顺便说一下,我必须使用 float32 数据类型来节省内存!

这是我用作测试的代码:

import numpy as np
from test_numba import test_numba

np.random.seed(seed=1774);
number = 150;
inArray = np.round(np.float32((np.random.rand(number)-.5)*2),4); #set up a float32 with 4 decimal places
numbaGet = test_numba(inArray); #run it through
print("Get:\t"+str(numbaGet)+" Type: "+str(type(numbaGet)));
print("Want:\t"+str(np.mean(inArray))+" Type: "+str(type(np.mean(inArray)))); #compare to expected

结合以下功能

import numpy as np
from numba import jit #, float32

@jit(nopython=True) #nopython=True, nogil=True, parallel=True, cache=True , nogil=True, parallel=True #float32(float32),
def test_numba(inArray):

    #outArray = np.float32(np.mean(inArray)); #forcing float32 did not change it
    outArray = np.mean(inArray);

    return outArray;

这个输出是:

Get:    0.0982406809926033 Type: <class 'float'>
Want:   0.09824067 Type: <class 'numpy.float32'>

这似乎表明 Numba 正在使它成为 Python float class(据我所知,float64)并进行数学运算,然后以某种方式进行精度下降。

如果我切换到 float64,差异会大大减少。

Get:    0.09824066666666667 Type: <class 'float'>
Want:   0.09824066666666668 Type: <class 'numpy.float64'>

不确定我做错了什么。同样,在我的情况下,这是一个可以忽略的问题(从小数点后 4 位开始),但仍然想知道为什么!

原因是,numba 不使用 np.mean,而是用 by/rolls 代替 its own version:

def array_mean_impl(arr):
    # Can't use the naive `arr.sum() / arr.size`, as it would return
    # a wrong result on integer sum overflow.
    c = zero
    for v in np.nditer(arr):
        c += v.item()
    return c / arr.size

前段时间我给了 an answer to a very similar question 关于 numpy.meanpandas.mean(使用 bottleneck)之间的区别。所以那里所说的一切也适用于这里,请查看它以获取更多详细信息,简而言之:

  • numba 使用的朴素求和误差为 O(n),其中 n 是求和数。
  • Numpy 使用类似于 pairwise-summation 的方法,它更精确,错误 O(log(n))
  • float32 的差异很明显,但 float64 的差异不太明显,尽管仍然存在相同的问题。