2015-02-10 61 views
1

我有一些我正在分析的代碼,並且驚訝於在Math.min(float, float)上花了多少時間。爲什麼Java的Math.min在我的Android應用程序中如此緩慢?

在我的使用情況下,我需要獲取3個浮點值的最小值,每個值爲保證不是NAN或另一個邊緣情況的浮點值。

我原來的方法是:

private static float min2(float v1, float v2, float v3) { 
    return Math.min(Math.min(v1,v2),v3); 
} 

但是我發現,這是約5倍的速度更快:

private static float min1(float v1, float v2, float v3) { 
    if (v1 < v2 && v1 < v3) { 
     return v1; 
    } 
    else if (v2 < v3) { 
     return v2; 
    } 
    else { 
     return v3; 
    } 
} 

僅供參考這是Math.min代碼:

public static float min(float f1, float f2) { 
    if (f1 > f2) { 
     return f2; 
    } 
    if (f1 < f2) { 
     return f1; 
    } 
    /* if either arg is NaN, return NaN */ 
    if (f1 != f2) { 
     return Float.NaN; 
    } 
    /* min(+0.0,-0.0) == -0.0 */ 
    /* 0x80000000 == Float.floatToRawIntBits(-0.0f) */ 
    if (Float.floatToRawIntBits(f1) == 0x80000000) { 
     return -0.0f; 
    } 
    return f2; 
} 

注意:我的用例是對稱的,上面的所有對於max而不是min都是正確的。

EDIT1: 原來〜5倍就言過其實了,但我仍然看到我的應用程序內的速度差。雖然我懷疑這可能是由於沒有進行適當的時間測試。

發佈這個問題後,我寫了一個適當的微觀優化速度測試在一個單獨的項目。在隨機浮標上測試每種方法1000次,它們都花費相同的時間。我認爲發佈該代碼不會很有用,因爲它只是確認我們所有人已經想到的。

必須有一些特定的項目,我正在致力於導致速度差異。

我在Android應用程序中做了一些圖形工作,我從3個觸摸事件中找到了最小值/最大值。再次,邊緣案例如-0.0f和不同的infinities是這裏不是一個問題。值在0.0f和3000f之間。

最初我使用Android設備監視器的方法分析工具對我的代碼進行了分析,該分析工具確實顯示出約5倍的差異。但是,這並不是像我現在學到的那樣微調代碼的最佳方式。

我加入了下面的代碼我的應用程序中,試圖獲得更好的數據:

long min1Times = 0L; 
long min2Times = 0L; 
... 
// loop assigning touch values to v1, v2, v3 
     long start1 = System.nanoTime(); 
     float min1 = min1(v1, v2, v3); 
     long end1 = System.nanoTime(); 
     min1Times += end1 - start1; 
     long start2 = System.nanoTime(); 
     float min2 = min2(v1, v2, v3); 
     long end2 = System.nanoTime(); 
     min2Times += end2 - start2; 
     double ratio = (double) (min1Times)/(double) (min2Times); 
     Log.d("", "ratio: " + ratio); 

打印帶有每個新觸摸事件正在運行的比率。當我在屏幕上旋動手指時,記錄的第一個比率爲0.0InfinityNaN。這讓我覺得這個測試不是很準確地衡量時間。隨着更多數據的收集,比率往往會在.851.15之間變化。

+0

你使用了什麼測試值?兩個或更多人平等的情況出現了嗎? – 2015-02-10 23:51:30

+0

你使用的是什麼版本的java? – bhspencer 2015-02-10 23:52:08

+3

你可以發佈你執行的測試嗎?如果有人跑了5毫秒。另一個在1毫秒內,它的確說得很多。 – 2015-02-10 23:53:28

回答

0

您的實現應該會導致一些非常緊密的字節碼,它可以通過JIT編譯器輕鬆轉換爲同樣快速的彙編語言。使用Math.min的版本有兩個子例程調用,因此可能不像你的那樣內聯。我認爲結果是可以預料的。

0

問題是關於浮點值的精度。

如果你想打電話給你的方法與參數(0.0f, -0.0f, 0.0f),它將返回你0.0f是最小的浮 - 它不是(浮動明智,-0.0f較小)

嵌套民方法返回預期結果。

因此,要回答你的問題:如果兩個方法都不是100%相同 - 有在比較他們的表現沒有一點:-)

Java將處理0.0f == -0.0f爲真,new Float(0.0)).equals(new Float(-0.0))falseMath.Min會考慮這個,你的方法不行。

使用浮點值時,不應該使用小於或等於運算符。相反,你應該根據預先選定的三角洲來比較數字,以將它們視爲更小,更大或相等。

float delta = 0.005 
if (Math.abs(f1 - f2) < delta) //Consider them equal. 
if (Math.abs(f1 - f2) > delta) // not equal. 

這就是所發生的事情在Math.min方法結束 - 通過實際檢查,如果一個號碼是-0.0f只是在一個非常非常精確的方式 - 按位。

因此,性能的缺點只是計算結果更爲精確。但是,如果您比較像「10」,「5」和「8」這樣的浮點值,則不應該存在性能差異,因爲0檢查從不會被命中。

+0

不平等不是問題。 – chrylis 2015-02-11 00:35:21

相關問題