簡體   English   中英

可以在運行時優化浮點乘以零嗎?

[英]Can floating point multiplication by zero be optimised at runtime?

我正在編寫一個算法來查找nxn矩陣的逆。 讓我們來看一個3x3矩陣的具體情況。

手動反轉矩陣時,通常會查找包含一個或多個零的行/列,以便更快地執行行列式計算,因為它會消除您需要計算的項。

在C / C ++中遵循此邏輯,如果您標識具有一個或多個零的行/列,則最終將得到以下代碼:

float term1 = currentElement * DetOf2x2(...);
//           ^
//           This is equal to 0.
//
// float term2 = ... and so on.

由於編譯器無法知道currentElement在編譯時將為零,因此無法將其優化為float term = 0; 因此浮點乘法將在運行時執行。

我的問題是,這些零值是否會使浮點乘法更快,或者無論currentElement的值如何,乘法都會占用相同的時間量? 如果無法在運行時優化乘法,那么我可以刪除搜索包含零的行/列的邏輯。

除非計算是trival(例如所有常量),否則不允許編譯器優化它。

原因是,DetOf2x2可能返回NAN浮點值。 將NAN與零相乘不會返回零,而是再次返回NAN。

您可以在此處使用此小測試自行嘗試:

int main (int argc, char **args)
{
  // generate a NAN
  float a = sqrt (-1);

  // Multiply NAN with zero..
  float b = 0*a;

  // this should *not* output zero
  printf ("%f\n", b);
}

如果要優化代碼,則必須自行測試零。 編譯器不會為您執行此操作。

float term1 = currentElement * DetOf2x2(...);

即使currentElement為0,編譯器也會調用DetOf2x2(...) :這肯定比最終的乘法要DetOf2x2(...)得多,無論是否為0。 原因有很多:

  • DetOf2x2(...)可能有副作用(如輸出到日志文件),即使currentElement0也需要發生這種副作用,
  • DetOf2x2(...)可以返回值,無論如何都應傳播到term1的非數字/ NaN標記(如Nils Pipenbrinck首先提到的那樣)

鑒於DetOf2x2(...)幾乎肯定會處理只能在運行時確定的值,后者的可能性不能在編譯時排除。

如果你想避免調用Detof2x2(...) ,請嘗試:

float term1 = (currentElement != 0) ? currentElement * DetOf2x2(...) : 0;

現代的CPU會比實際的分支處理乘法由零速度非常快,快於一般的乘法,並迅速。 甚至不打算嘗試優化它,除非零將通過至少幾十個指令傳播。

在運行時執行的優化稱為JIT(即時)優化。 在翻譯(編譯)時執行的優化稱為AOT(提前)優化。 你指的是JIT優化。 編譯器可能會在您的機器代碼中引入JIT優化,但它實現的優化要比常見的AOT優化要復雜得多。 優化通常基於重要性來實現,並且這種“優化”可能被視為負面地影響其他算法。 C實現不需要執行任何這些優化。

您可以手動提供優化,這將是“搜索包含零的行/列的邏輯”,或者類似這樣的內容: float term1 = currentElement != 0 ? currentElement * DetOf2x2(...) : 0; float term1 = currentElement != 0 ? currentElement * DetOf2x2(...) : 0;

當編譯器可以猜測“currentElement”的值時,以下構造在編譯時有效。

float term1 = currentElement? currentElement * DetOf2x2(...):0;

如果在編譯時無法猜到,它將在運行時進行檢查,性能取決於處理器體系結構:分支之間的權衡(包括分支延遲和重建指令管道的延遲可達10或20個周期)和平坦代碼(一些處理器每個周期運行3個指令)和硬件分支預測(當硬件支持分支預測時)。

由於乘法吞吐量在x86_64處理器上接近1個周期,因此根據操作數值(如0.0,1.0,2.0或12345678.99)不存在性能差異。 如果存在這樣的差異,那將被視為加密式軟件中的隱蔽通道。

GCC允許在編譯時檢查函數參數

內聯浮動myFn(float currentElement,myMatrix M)

{

#if __builtin_constant_p(currentElement)&& currentElement == 0.0

返回0.0;

#其他

return currentElement * det(M);

#萬一

}

您需要在編譯器中啟用內聯和過程間優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM