簡體   English   中英

我怎樣才能將分裂強度降低2 ^ n + 1?

[英]How can I strength reduce division by 2^n + 1?

我需要在代碼的熱路徑中執行一些整數除法。 我已經通過分析和循環計數確定了整數除法對我造成的損失。 我希望我能做些什么來強化將分裂降低到更便宜的東西。

在這條路徑中,我除以2 ^ n + 1,其中n是可變的。 基本上我想優化此函數以刪除除法運算符:

unsigned long compute(unsigned long a, unsigned int n)
{
    return a / ((1 << n) + 1);
}

如果我除以2 ^ n,我只需用右移n替換div。 如果我用常數除法,我會讓編譯器強度減少那個特定的除法,可能會把它變成乘法和一些變化。

是否存在適用於2 ^ n + 1的類似優化?

編輯:這里可以是任意64位整數。 n只取10和25之間的幾個值。我當然可以為每個n預先計算一些值,但不能為a計算。

由於你只能將一個int轉移到這么多的地方,你可以通過一個常數將所有這些情況選擇為幾個部分中的一個:

unsigned long compute(unsigned long a, unsigned int n)
{
    // assuming a 32-bit architecture (making this work for 64-bits 
    // is left as an exercise for the reader):
    switch (n) {
        case  0: return a / ((1 << 0) + 1);
        case  1: return a / ((1 << 1) + 1);
        case  2: return a / ((1 << 2) + 1);

            // cases 3 through 30...

        case 31: return a / ((1 << 31) + 1);
    }
}

所以現在每個除法都是一個常數,編譯器通常會減少到一系列乘法/移位/加法指令(如上所述)。 請參閱ac / c ++編譯器是否將兩次冪值的常量除法優化為班​​次? 對於deatils。

你可以用一個常數替換整數除法,乘以一個幻數和一個移位乘以(模數詞大小)。

可以針對已知常數預先計算幻數。

由於n不能采用多個值,例如0..31,因此為所有n預先計算這些幻數並“存儲”在具有32個元素的表中是“容易的”。

用於計算幻數的Javascript頁面

如果除數在編譯時是常數,那么一個好的編譯器可以計算幻數並通過乘法和移位替換整數除法。 根據圍繞性能關鍵代碼構建其余代碼的方式,您可以使用宏或內聯技巧來展開n的所有可能值,並讓編譯器完成查找幻數的工作( 類似於交換機的答案) ,但是我會把更多的代碼放在常量區域,否則它可能是一個不值得的交易 - 分支也會花費你的性能

詳細描述以及用於計算幻數的代碼可以在Henry S. Warren,Jr。的書“Hackers Delight”中獲得資金( 強烈推薦必須有書! )pp.180ff。

鏈接到相關章節的Google圖書:

第10-9章除數的無符號除法> = 1

暫無
暫無

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

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