contributed by < fwfly
>
題目要求 :
在 c 語言的規格中,對於負數的向右位移是 implementation-defined .
實作一個可運算有號數的向右位移
4 的 bitwise 表示為 0100
而 4 的次方相當於向左位移 2 個 bits ( <<2 )
所以只要是 4 的次方.
裡面都會只有一個 bit 為 1.
透過 (num & (num - 1))==0 可以知道這個數字是不是存在唯一一個為 1 的 bit
但是如果單純這樣檢查,其實也會把 2 或者 8 的次方算進去.所以需要透過額外的方式去判斷是否為 4 的次方
可以看到 2 跟 8 被認為是 4 的次方
如果用 __builtin_ctz 去跑 4 次方的倍數則會得到
也就是從右邊數來(直到碰到第一個為 1 的 bit ) 0 bits 的個數都會剛好是 2 的倍數,也就是第一個 bit 為 0
所以 & 0x1 再取 not 的意思就是第一個 bit 不等於 1
因此加上這個條件就可以得知是否為 4 的次方數
leedcode 的問題是給定一個數字,計算在幾次的運算後會歸零 ?
運算方式有兩種 :
問題可以轉換成
先放上答案
這邊有兩個 gcc 函式對應的則是上面兩種運算方式
下面的程式碼可以解決這樣的問題
假定數字大小為 32 位元,因為最後一位數不做位移,所以最多會做 31 次,假設碰到 (0xFFF…FF)
剩下的問題是從第幾個 bit 開始做位移 ?
這個問題可以換成
最左邊為 1 的 bit 前面有多少個 0 ?
__builtin_clz 可以幫忙做這樣的運算
根據測驗 2 的題目描述可知
這個 function 是 return 有多少個 leading 0
因為前面的 0 可以不用做運算,所以扣掉前面 bit 為 0 的個數,就可以知道剩下有多少個 bits 要做位移運算
比方說
第 25 個 bit 是 1,前面 24 位是 0.
所以需要做 31 - 24 = 7 次位移 ( >>1 )
上面算完了位移,再來是要算減 1
減 1 可以想像成最右邊的 bit 為 1 的次數.
同上面的例子
透過位移可以看到會有四次為 1 的狀態,所以會減 4 次.
而這個 4 次剛好就會等於 10100101 裡面 bit 為 1 的個數.
從原題目可以得知 __builtin_popcount 是用來算一個數字裡面有多少個 bits 為 1
所以再把 __builtin_popcount 數字加回去來得到答案.