2013-09-23 27 views
48

在我的領域中,對一些數字進行平方處理,將它們一起操作並取結果的平方根很常見。例如,這是在畢達哥拉斯定理和RMS計算中完成的。Python中的指數運算 - 我應該更喜歡**運算符而不是math.pow和math.sqrt嗎?

在numpy的,我也做了以下內容:

result = numpy.sqrt(numpy.sum(numpy.pow(some_vector, 2))) 

而且在純Python像這樣的預期:

result = math.sqrt(math.pow(A, 2) + math.pow(B,2)) # example with two dimensions. 

不過,我一直在使用這種純Python形式,因爲我發現它更小巧,獨立於進口,看似等價:

result = (A**2 + B**2)**0.5 # two dimensions 
result = (A**2 + B**2 + C**2 + D**2)**0.5 

我聽說過有些人認爲**運營商是一種破解,並通過0.5冪指數來平分數字是不太可讀的。但是我想問的是:

「是否有任何計算理由比第三個選擇前兩個選擇?」

感謝您的閱讀!

+1

這可能是一個相關的線程 - http://stackoverflow.com/questions/327002/which-is-faster-in-python-x-5-or-math-sqrtx –

+1

我傾向於認爲math.sqrt()比()** 0.5。 –

+1

@Maxime更具可讀性,我會更進一步,只需在數學導入sqrt中使用'sqrt'。 –

回答

43

math.sqrt是平方根的C實現,因此不同於使用**運算符,該運算符實現了Python的內置pow函數。因此,使用math.sqrt實際上給出了與使用**算子不同的答案,並且確實存在計算原因,以便比內置模塊實現numpymath模塊實現更好。具體而言,sqrt函數可能以最有效的方式實現,而**可操作於大量基數和指數,並且可能對於平方根的特定情況未被優化。另一方面,內置的pow函數處理一些額外的情況,如「複數,無限整數和模冪運算」。

See this Stack Overflow question for more information on the difference between ** and math.sqrt.

在這方面更「Python化」,我想我們需要討論這個詞的本身的定義。從the official Python glossary中可以看出,如果Pythonic「緊密地遵循Python語言最常見的成語,而不是使用其他語言通用的概念來實現代碼,那麼它就說Pythonic是一段代碼或想法。「在我能想到的每一種其他語言中,都有一些基本平方根函數的數學模塊,但是有一些語言缺少像**這樣的電力操作符,例如C++,所以**可能更多Pythonic,但是它是否客觀上更好取決於用例

+0

'operator.pow'在哪裏混合? –

+0

優秀的答案,尤其是對於那些可能是高度「自發性」的線索,專注於OP,以及基本的Python租戶。榮譽。 – GrayedFox

+0

但是,如果輸入是整數,**或內建的pow函數可能更適合計算:「與內建的**運算符不同,math.pow()將它的參數轉換爲float類型。內置的pow()函數用於計算精確的整數冪。「 - Python文檔:數學庫https://docs.python.org/2/library/math.html#power-and-logarithmic-functions – hyperGeoMetric

12

即使在基地Python中,你可以做的計算以普通形式

result = sum(x**2 for x in some_vector) ** 0.5 

x ** 2肯定不是一個黑客和執行的計算是相同的(我與CPython的源代碼檢查)。我實際上發現它更易讀(和可讀性計數)。

使用代替x ** 0.5取平方根並不做同樣的計算作爲math.sqrt因爲前者(可能)使用對數被計算,而後者(可能)使用數學處理器的特定數字指令。

我經常使用x ** 0.5只是因爲我不想爲此添加math。然而,我希望平方根的具體指令能夠比使用對數的多步操作更好(更準確)。

+2

顯然[既不是更準確](http://stackoverflow.com/a/842358/199360) - 但[sqrt更快](http://stackoverflow.com/a/327011/199360)。 – adib

+0

爲什麼Python解釋器不能識別x ** 0.5作爲特例?畢竟0.5是一個常數。 – user3150208