編譯器與程式碼產生

強度削減(strength reduction)

有些操作對處理器來說比其他的便宜:位移位元比一般乘法快、加法比乘法快、乘法比除法快。強度削減就是把一個昂貴操作換成產生相同結果的較便宜操作的最佳化——它「降低了操作的強度」。

有兩種常見口味。簡單的、局部的那種改寫單一操作:無號數乘以 8 變成左移 3 位(x * 8 變成 x << 3),因為位移 3 位等同於乘以 2 的 3 次方;無號數除以 2 的次方變成右移;乘以一個常數可變成幾個位移加上加法。較強大的那種針對迴圈,其中某個變數每次迭代以固定步幅成長(歸納變數,induction variable)。如果迴圈每次都計算 i * 4,編譯器可以改為保留一個累進值、每次迭代加 4,把迴圈本體裡的乘法換成加法——這是大勝,因為它每次迭代都觸發。

它重要在於:它直接削減熱門內層迴圈的成本,尤其是位址算術(為陣列存取計算 base + i * element_size 是教科書級的目標)。對系統程式設計師在意的有號/無號差別,有一個提醒:把乘法或除法換成位移,只有在給出相同結果時才有效。對無號數,除以 2 的次方乾淨地等於右移。對「有號數」則不然——有號除法朝零捨入,而對負數,算術右移朝負無窮捨入——所以編譯器必須輸出額外的修正、或拒絕用簡單的位移。編譯器會正確處理這件事;教訓是「直接用位移取代除法」只有對無號型別才安全。

unsigned y = x * 8; // 變成: y = x << 3; unsigned q = x / 4; // 變成: q = x >> 2; (只限無號數!) // 迴圈中: addr = base + i*4 -> 保留 addr,每次迭代 addr += 4

對無號數,位移取代乘以/除以 2 的次方;在迴圈中,一個加法取代每次迭代的乘法。

把除法換成右移只對「無號」運算元等價:有號除法朝零捨入,但算術右移朝負無窮捨入,所以編譯器必須為有號數加上修正碼——切勿手動以位移取代有號除法。

又称
operator strength reductioninduction-variable strength reduction運算強度降低