2017-09-02 76 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