[小菜一碟] 將 2 的 n 次方加總結果再拆解回來

在狀態表達的設計手法中,有一種是以 2 的 n 次方來設計,例如:Status1 = 1、Status2 = 2、Status3 = 4、...依此類推,當我們得知某物件的 Status = 5,我們就知道它包含了 Status1 以及 Status3(因為 5 = 1 + 4),.NET Framework 中有一個列舉型別 System.Reflection.BindingFlags 就是這樣設計的,那重點來了,我們要怎麼知道任意一個正整數可以由哪些 2 的次方加總結果呢?

想不到我們又再度地與 >>(右移)<<(左移)運算子見面了(請參考此篇文章),除此之外這次還會使用到 yield 關鍵字,我們限定數值型別為 int 跑一個迴圈,索引值從 1 開始,每迴圈一次就 <<= 1,將目標參數 value 與當前的索引值做 & 運算,若結果 > 0 則 yield return 當前的索引值,並且從 value 中減掉當前的索引值,直到 value == 0 時 yield break,這樣我們就可以知道目標參數 value 是由哪些 2 的次方加總得來的了。

private static IEnumerable<int> GetBinaryExponentiations(int value)
{
    for (var currentPow = 1; currentPow != 0; currentPow <<= 1)
    {
        if ((currentPow & value) > 0)
        {
            yield return currentPow;
            
            if ((value -= currentPow) == 0) yield break;
        }
    }
}

執行結果:

參考資料