2011-03-04 71 views
7

我正在研究擴展OpenCV,HALCON,...的n圖像處理庫。該庫必須使用.NET Framework 3.5,因爲我對.NET的使用經驗有限,所以我想問一些關於性能的問題。Math.Pow的最佳做法

我遇到了一些我無法向自己正確解釋的具體事情,並希望您提問a)爲什麼和b)處理這些案件的最佳做法是什麼。

我的第一個問題是關於Math.pow。我已經在StackOverflow上找到了一些答案,它很好地解釋了它(a),但不知道怎麼做(b)。我的基準測試程序看起來像這樣

Stopwatch watch = new Stopwatch(); // from the Diagnostics class 
watch.Start(); 
for (int i = 0; i < 1000000; i++) 
    double result = Math.Pow(4,7) // the function call 
watch.Stop() 

結果不是很好(〜我的電腦上300毫秒)(我已經運行測試10次,calcuated平均值)。

我的第一個想法是檢查這是因爲它是一個靜態函數。所以,我實現了我自己的直接階級

class MyMath 
{ 
    public static double Pow (double x, double y) //Using some expensive functions to calculate the power 
    { 
     return Math.Exp(Math.Log(x) * y); 
    } 

    public static double PowLoop (double x, int y) // Using Loop 
    { 
     double res = x; 
     for(int i = 1; i < y; i++) 
      res *= x; 
     return res; 
    } 

    public static double Pow7 (double x)   // Using inline calls 
    { 
     return x * x * x * x * x * x * x; 
    } 
} 

我檢查的第三件事是,如果我將取代Math.Pow(4,7)到4 * 4 * 4 * 4 * 4 * 4 * 4。

的結果(平均出10個測試的運行)

300 ms Math.Pow(4,7) 
356 ms MyMath.Pow(4,7) //gives wrong rounded results 
264 ms MyMath.PowLoop(4,7) 
92 ms MyMath.Pow7(4) 
16 ms 4*4*4*4*4*4*4 

現在我的情況現在基本上是這樣的:不要使用數學的戰俘。我唯一的問題就是......我真的必須現在實施我自己的Math-Class嗎?爲功能函數實現一個自己的類似乎不太有效。 (順便說一下,PowLoop和Pow7在Release版本中的速度更快了25%,而Math.Pow則沒有)。

所以我最後的問題是

一)我,如果我不能在所有(但可能分數)(這讓我莫名其妙地傷心難過)使用Math.Pow我錯了。 b)如果你有代碼優化,你是否真的直接寫這些數學運算?

c)是有可能已經快(開源^^)庫數學運算

d)我的問題的來源基本上是:我認爲在.NET Framework本身就已經提供了非常優化編碼/編譯這些基本操作的結果 - 無論是數學類還是處理數組,我都有點驚訝,通過編寫自己的代碼可以獲得多少好處。還有其他的一些「領域」或別的東西在C#中看不到,我不能直接相信C#。

+6

我認爲4 * 4 * 4 * 4 * 4 * 4 * 4會在編譯時評估,因此它的速度非常快。 – Nick 2011-03-04 10:13:54

+0

我認爲對於大多數人來說,100ms左右並不是什麼大不了的事情。 C#通常不是大多數人的這種應用程序的首選。 – Ian 2011-03-04 10:15:26

+1

你用較大的數字測試過嗎?我認爲Math.Pow針對較大的指數進行了優化,並且執行如下操作:x^7 == x^{3 + 3 + 1} == {x^3 + x^3 x},這意味着它正在運行順序是O(log(n)),而你的解決方案是O(n),並且對於大型指數可能會慢得多。 – markijbema 2011-03-04 10:19:01

回答

0

當你正在談論做一行代碼的百萬次迭代時,顯然每一個細節都會有所作爲。

Math.Pow()是一個函數調用,它比您的手動4 * 4 ... * 4示例要慢很多。

不要將自己的課程編寫爲可疑課程,您可以編寫比標準數學課程更優化的任何課程。

1

首先,整數運算是太多比浮點更快。如果您不需要浮點值,請不要使用浮點數據類型。對於任何編程語言來說都是如此。其次,正如你自己所說的,Math.Pow可以處理雷亞爾。它使用了比簡單循環更復雜的算法。難怪它比循環更慢。如果你擺脫了循環,只需執行n次乘法運算,你也可以減少建立循環的開銷 - 從而使其更快。但是如果你不使用循環,你必須事先知道指數的值 - 它不能在運行時提供。

我不知道爲什麼Math.ExpMath.Log更快。但是,如果使用Math.Log,則無法找到負值的力量。

基本上int更快,避免循環,避免額外的開銷。但是當你爲那些人而做時,你正在交易一些靈活性。但是,當你需要的只是整數時避免實數通常是一個好主意,但在這種情況下,當已經存在的自定義函數編碼時似乎有點太過分了。

你必須問自己的問題是這是否值得。 Math.Pow實際上是減慢你的程序嗎?無論如何,已經與你的語言捆綁在一起的Math.Pow往往是最快或非常接近的。如果你真的想做一個真正通用的替代實現(即不僅限於整數,正值等),你可能最終會使用默認實現中使用的相同算法。

+1

雖然我同意你的回答的一般觀點,但我想說一句話:當然庫函數函數是優化的,但並不總是可以針對所有情況進行優化。考慮例如排序,其中有很多有效的算法選項,並且它確實取決於您的特定數據哪一個最好。 – markijbema 2011-03-04 11:57:04

+0

@markijbema:這就是爲什麼我在回答中使用了「通用」這個詞。如果您可以對數據做出額外的假設(例如它們總是整數或在給定的範圍內),當然您可以使用該數據進行優化(例如,計數排序而不是快速排序)。這是我的答案的重點,對於通用功能來說,很難與圖書館相匹配。 – MAK 2011-03-04 12:00:20

4

兩件事情要牢記:

  1. 你可能don't need to optimise這段代碼。你在不到一秒鐘內完成了一百萬次函數調用。這真的會在你的程序中造成很大的問題嗎?

  2. Math.Pow無論如何可能是相當優化的。有人猜測,它會調用一個用低級語言編寫的適當的數字庫,這意味着你不應該期望數量級的增加。

  3. 數值編程比您想象的要困難。即使你認爲你知道如何計算的算法,也不是這樣計算的。例如,當你計算平均值時,你不應該只加上數字併除以你有多少數字。 (現代NUMERICS庫使用兩遍程序糾正了爲浮點錯誤。)

這就是說,如果你決定,你絕對需要優化,然後再考慮使用整數,而不是浮點值,或外包這到另一個數字圖書館。