2017-09-02 62 views
1

给定两个矩形的相对的角(x1, y1)(x2, y2)和两个半径r1r2,发现点的那个位于由半径限定的圆之间的比率r1r2到矩形中的点的总数。用法使得函数给出错误的结果

简单NumPy的方法:

def func_1(x1,y1,x2,y2,r1,r2,n): 
    x11,y11 = np.meshgrid(np.linspace(x1,x2,n),np.linspace(y1,y2,n)) 
    z1 = np.sqrt(x11**2+y11**2) 
    a = np.where((z1>(r1)) & (z1<(r2))) 
    fill_factor = len(a[0])/(n*n) 
    return fill_factor 

下一个我试图从numba的jit装饰,以优化该功能。当我使用:

nopython = True 

该功能更快,并提供正确的输出。但是,当我还补充说:

parallel = True 

该功能更快,但会给出错误的结果。 我知道这与我的z矩阵有关,因为它没有被正确更新。

@jit(nopython=True,parallel=True) 
def func_2(x1,y1,x2,y2,r1,r2,n): 
    x_ = np.linspace(x1,x2,n) 
    y_ = np.linspace(y1,y2,n) 
    z1 = np.zeros((n,n)) 
    for i in range(n): 
     for j in range(n): 
      z1[i][j] = np.sqrt((x_[i]*x_[i]+y_[j]*y_[j])) 
    a = np.where((z1>(r1)) & (z1<(r2))) 
    fill_factor = len(a[0])/(n*n) 
    return fill_factor 

测试值:

x1 = 1.0 
x2 = -1.0 
y1 = 1.0 
y2 = -1.0 
r1 = 0.5 
r2 = 0.75 
n = 25000 

附加信息:Python版本:3.6.1,Numba版本:0.34.0 + 5.g1762237,NumPy的版本:1.13.1

回答

0

问题与parallel=True是它是一个黑盒子。 Numba甚至不保证它会实际上并行任何东西。它使用启发式方法来确定它是否可并行化,并且可以并行执行哪些操作。这些可能会失败,并且在您的示例中它们确实失败,就像在my experiments with parallel and numba中一样。这使parallel不值得信赖,我会建议使用它!

在更新的版本(0.34)prange被添加,你可以有更多的运气。它不能在这种情况下应用,因为prange作品像range,这就是从np.linspace不同...

刚一说明:您可以避免构建z,完全在做你的函数的np.where,你可能只是做检查明确:

import numpy as np 
import numba as nb 

@nb.njit # equivalent to "jit(nopython=True)". 
def func_2(x1,y1,x2,y2,r1,r2,n): 
    x_ = np.linspace(x1,x2,n) 
    y_ = np.linspace(y1,y2,n) 
    cnts = 0 
    for i in range(n): 
     for j in range(n): 
      z = np.sqrt(x_[i] * x_[i] + y_[j] * y_[j]) 
      if r1 < z < r2: 
       cnts += 1 
    fill_factor = cnts/(n*n) 
    return fill_factor 

这也应该提供一些加速相比,你的功能,甚至比使用parallel=True(如果它会正常工作)更多。

+0

谢谢! 我想补充的另一件事是,不必采取z的平方根,而是可以直接比较方块(正如顾问指出的那样)。 除此之外,我试着看看代码中可能出现了什么问题,我想可能是因为竞争条件的发展,而不应该像以前指出的那样盲目地使用并行选项。 – Sajid

+0

是的,我也认为它是某种竞争条件,但我检查了生成的LLVM代码,我不知道如何。竞争条件需要在'np.where'内发生(因为在你的'z'中没有后续写入同一个数组的位置),但它有多么不祥,这可能导致竞争条件。但是我对平方根很好奇:计算平方根实际上更快,而不是两次乘法和一次加法? – MSeifert