2014-09-18 63 views
0

我想在np.float32和内建的Python int和float之间执行二元运算(如加法和乘法),并获得一个np.float32作为返回类型。但是,它会自动上传到np.float64。Numpy标量上的二元运算自动上移到float64

示例代码:

>>> a = np.float32(5) 
>>> a.dtype 
dtype('float32') 
>>> b = a + 2 
>>> b.dtype 
dtype('float64') 

如果我这样做与np.float128,B也成为np.float128。这很好,因为它保留了精度。然而,在我的例子中,不需要向np.float64上传转换来保持精度,但它仍然会发生。如果我将2.0(Python浮点数(64位))添加到2而不是2,那么投射会有意义。但即使在这里,我也不想要它。

所以我的问题是:如何修改将二进制运算符应用于np.float32和内置Python int/float时执行的转换?或者,在所有计算中使单精度成为标准而不是双精度,也算作解决方案,因为我从不需要双精度。其他人已经提出了这个要求,似乎没有找到解决方案。

我知道numpy数组和dtypes。在这里我得到了想要的行为,因为数组总是保留它的dtype。然而,当我对一个数组的单个元素进行操作时,我得到了不需要的行为。 我对解决方案有一个模糊的想法,涉及到np.ndarray(或np.float32)的子类化以及__array_priority__的值的更改。到目前为止,我还没有得到它的工作。

为什么我在意?我正在尝试使用Numba编写一个n体代码。这就是为什么我不能简单地对整个阵列进行操作。将所有np.float64更改为np.float32使得加速大约为2倍,这很重要。 np.float64-casting行为可以完全破坏这个速度,因为我的np.float32数组上的所有操作都是以64位精度完成的,然后降频至32位精度。

回答

1

我不确定NumPy的行为,或者你是如何尝试使用Numba,但明确Numba类型可能会有所帮助。例如,如果你做这样的事情:

@jit 
def foo(a): 
    return a[0] + 2; 

a = np.array([3.3], dtype='f4') 
foo(a) 

在[0]提升为增加操作前float64(FLOAT32的值,如果你不介意潜入LLVM IR,你可以看到这通过使用numba命令运行代码并使用--dump-llvm或--dump-optimized标志:numba --dump-optimized numba_test.py)来执行自己的代码。但是,通过指定函数签名,包括返回类型FLOAT32:

@jit('f4(f4[:]')) 
def foo(a): 
    return a[0] + 2; 

中的值A [0]不晋升为float64,虽然结果被转换为float64所以它可以被转换为一个当Python函数返回到Python土地时,Python浮动对象。

如果你可以事先分配一个数组来保存结果,你可以做这样的事情:

@jit 
def foo(): 
    a = np.arange(1000000, dtype='f4') 
    result = np.zeros(1000000, dtype='f4') 
    for i in range(a.size): 
     result[0] = a[0] + 2 

即使你正在做自己的循环,编译代码的性能应该是相当一个NumPy ufunc,并且不会发生转换为float64(再次,这可以通过查看Numba生成的llvm IR来验证)。