2017-05-31 55 views
2

例如,下面是用指针来返回一个简单的C函数值:如何调用使用指针在Numba返回值ctypes的功能@jit

void add(double x, double y, double *r) 
{ 
    *r = x + y; 
} 

我想打电话给每一个元素add()功能在两个数组中,并通过numba @jit函数收集结果。

第一编译的C代码:

!gcc -c -fpic func.c 
!gcc -shared -o func.so func.o 

而且通过ctypes的加载:

lib = ctypes.cdll.LoadLibrary("./func.so") 
add = lib.add 
add.argtypes = ctypes.c_double, ctypes.c_double, ctypes.c_void_p 
add.restype = None 

则numba函数:

from numba import jit, float64 

@jit(float64(float64[:], float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], &z[i]) # here I want to pass the address of z[i] 
    return z 

但是numba没有AddressOf运算或函数。

目前我正在使用以下方法。但是这种方法不能用于nopython模式,并且我不知道for循环中的代码是否具有python对象。

@jit(float64(float64[:], float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    tmp = ctypes.c_double(0.0) 
    addr = intp(ctypes.addressof(tmp)) 
    val = carray(ctypes.pointer(tmp), 1) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], addr) 
     z[i] = val[0] 
    return z 
+0

如何编写一个在整个数组上运行的C包装函数,所以你根本不需要Numba? –

+0

目前我正在使用cython来完成这项工作,但是我想切换到numba,并且坚持了这个问题。 – HYRY

+0

供参考:'add.argtypes = ctypes.c_double,ctypes.c_double,ctypes.POINTER(ctypes.c_double)'会更准确。传递参数是:'tmp = ctypes.c_double()'和'add(1.0,2.0,ctypes.byref(tmp))''。 'tmp.value'就是结果。 –

回答

3

我找不到传递准确的元素的引用的精确的方法,但以下似乎工作:

@nb.jit(nb.float64[:](nb.float64[:], nb.float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], z[i:].ctypes.data) # here I want to pass the address of z[i] 
    return z 

基本上,你可以使用z.ctypes.dataz数据指针,但这只是给你第一个元素。它感觉不错,但基本上我只是分片,所以我想要的内存地址是在片的开始。

我不确定是否有更好的选择。

+0

难道你不能说'z.ctypes.data + i'吗? –

+0

这确实有效,但是'z.ctypes.data + i * z.itemsize'。 – JoshAdel

+0

@eryksun你提出的建议似乎不适用于numba中的'nopython'模式 – JoshAdel