2013-09-27 93 views
3

如果一個人計算給定int值的一小部分,說:整數除法或浮點乘法?

int j = 78; 
int i = 5* j/4; 

這是不是做快:

int i = 1.25*j; // ? 

如果是,是否有一個可以使用的轉換因子決定使用哪一個,因爲在同一時間內可以完成多少個int乘法?

編輯:我想評論說清楚的浮點運算會慢一些,但問題是,多少?如果我需要更換每個float乘以$ N $ int部門,那麼$ N $會不會再值得呢?

+9

你有基準每一個? – Mysticial

+3

這些數字中有多少是動態的? –

+1

@KerrekSB指的是編譯器爲你優化所有這些。因此,基準爲什麼很重要。 – Adam

回答

5

你說過所有的值都是動態的,這是有差別的。對於特定值5 * j/4,整數運算將會非常快速,因爲幾乎最糟糕的情況是編譯器將它們優化爲兩個班次和一個加法,再加上一些混亂以應對j爲負的可能性。如果CPU可以做得更好(單週期整數乘法或其他),那麼編譯器通常會知道它。編譯器優化這種類型的能力的限制基本上來自於編譯多種CPU的時候(例如,生成最低公分母ARM代碼),編譯器並不十分了解硬件,因此不能總是做出好的選擇。

我想,如果ab是固定的一段時間(但在編譯時不知道),那麼它可能是計算k = double(a)/b一次,然後int(k * x)x許多不同的值,可能比計算a * x/b快對於許多不同的值x。我不會指望它。

如果所有的值每次都有所不同,那麼計算1.25和浮點乘法的浮點除法似乎不可能比整數乘法之後的整數除法更快。但你永遠不知道,測試它。

這不是真的有可能讓這個簡單的相對時序上現代的處理器,它實際上取決於周圍的代碼很多。代碼中的主要成本通常不是「實際」操作:它是「隱形」的東西,例如指令流水線停滯於依賴關係,或溢出寄存器堆棧或函數調用開銷。做這個工作的函數是否可以內聯可能會比函數的實際功能更容易做出更多的改變。就性能的權威性陳述而言,你基本上可以測試真實代碼或者閉嘴。但是,如果你的值是以整數開始的,那麼對它們進行整數運算的速度會比轉換爲double並做類似數量的double運算更快。

1

這是不可能的情況下回答這個問題。由於整數和浮點運算的特性(包括舍入和溢出),另外5*j/4通常不會產生與(int) (1.25*j)相同的結果。

如果你的程序主要是做整數運算,那麼將j轉換爲浮點數,乘以1.25,並且轉換回整數可能是免費的,因爲它使用了不以其他方式參與的浮點單元。

或者,在某些處理器上,操作系統可能會將浮點狀態標記爲無效,這樣第一次進程使用它時,會出現異常,操作系統會保存浮點寄存器包含來自另一個進程的值),爲進程恢復或初始化寄存器,並從異常中返回。與正常的指令執行相比,這將花費大量的時間。

答案也取決於程序正在執行的特定處理器模型,以及操作系統,編譯器如何轉換源到組件的特性,並且甚至可能是什麼系統上的其他進程正在做的。

此外,5*j/4(int) (1.25*j)之間的性能差異是最經常太小,是顯着的一個程序,除非它或操作像它被重複許多次。 (並且,如果是這樣的話,對代碼進行矢量化可能會帶來巨大的好處,也就是說,使用許多現代處理器的單指令多數據[SIMD]功能一次執行多個操作。)

0

對於您的情況, 5*j/4將比1.25*j快得多,因爲通過2的冪除法可通過右移容易地操縱,並且5*j可以由單個指令上ARM上做一些架構,諸如LEA在x86或ADD(帶換檔)。大多數其他人最多需要2條指令(如j + j/4),而不是緩慢的乘法和非常緩慢的除法。使用int multiply/divide還允許編譯器優化除以常量的分割,並且不需要轉換爲浮點值和從浮點值轉換。

對於其他情況下,當分數不浮點表示的(如3*j/10)通過int乘法/除法會更正確的(因爲0.3是不是二進制浮點正好0.3),並極有可能更快(因爲編譯器可以通過將其轉換爲乘以其乘法逆而將除以常量)。 [查看更多Divide a number by 3 without using *, /, +, -, % operatorsDivide by 10 using bit shifts?Divisiblity of 5 without using % and/operator]。而且不需要轉換浮點數值,也不需要花費很多時間。

對於i和j屬於浮點類型的情況,乘以另一個浮點值可能會更快。因爲在float和int域之間移動值需要時間,正如我上面所說的,int和float之間的轉換也需要時間。這就是爲什麼有不同的SSE或AVX指令可以在不同的域上執行完全相同的操作。

也就是說,對於「哪個更快」和「更快多快」這個問題,沒有一般的答案,因爲它取決於特定的架構和特定的環境。您必須測量您的系統並決定。但是如果一個表達式重複地處理了很多值,那麼就該轉向SIMD了。

Why is int * float faster than int/int?
Should I use multiplication or division?
Floating point division vs floating point multiplication