contributed by < linhoward0522
>
1
給定無號 64 位元數值 x,找出最接近且大於等於 2 的冪的值
想法是我們要先找到數值 x 最高位元的 1 的位置,他的下一個高位元就會是最接近且大於等於 2 的冪的值
透過上述程式碼可知,我們將最高位元的 1 ,依序向右移動並和當前的數值做 or,以此類推最後可得最高位元以下的位元都為 1
而我們知道題目是給定無號 64 位元的數值 x,所以最多只要做 63 次右移即可完成,所以
AAAA
應為 8
BBBB
應為 32
CCCC
應為 x + 1
__builtin_clzl
改寫
int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
int __builtin_clzl (unsigned long)
Similar to __builtin_clz, except the argument type is unsigned long.
If x is 0, the result is undefined
,所以要先設定好 x == 0
的條件Set a bit
的操作
但根據題目所述找出最接近且大於等於 2 的冪的值,所以當我們輸入的數值已經是 2 的冪,則應該就要回傳該值
所以應要加上該條件才正確
在 include/linux/log2.h
中的 __roundup_pow_of_two
此函式的作用是將傳入的無號整數 n 轉換為最接近且大於等於 2 的冪的值
其中 fls_long
定義在 linux/include/linux/bitops.h
中
要探討其應用場景,比照 課前測驗參考解答: Q1 的風格。
fls
用於 unsigned int
為 4 bytes ,而 fls64
用於 unsigned long
為 8 bytes
使用 4 個空白字元,而非 tab 來排版,善用 .clang-format
用於計算一個無號整數中最高位元為 1 之位置
應用場景 : 詢問chatgpt
,回答 :
在網絡編程中,用於調整網絡緩衝區的大小;
在記憶體管理中,用於調整物理頁框的大小;
在虛擬內存管理中,用於調整虛擬頁框的大小等。
可詢問 ChatGPT,但你要驗證,而且舉出實際的 Linux 原始程式碼來討論。
執行 cc -O2 -std=c99 -S quiz2-1.c
後觀察產生的 quiz2-1.s
檔案,確認有 bsrq
指令
2
給定一整數 n ,回傳將 1 到 n 的二進位表示法依序串接在一起所得到的二進位字串,其所代表的十進位數字 之值。
if it is power of 2, we increase the bit length
可知,下面的 if
條件式應是要判斷是否為 2 的冪,若為 2 的冪就會增加 bit length
運用 bit-wise operator
C 語言中,x & (x - 1) == 0 的數學意義
power of two
signed v.s. unsigned
DDDD
應為 i & (i - 1)
bit
數為 len
的長度,才能達到串聯的效果
EEEE
應為 ans << len
__builtin_{clz,ctz,ffs}
改寫__builtin_clz()
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
__builtin_ctz()
Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
__builtin_ffs()
Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
使用 __builtin_clz()
來作改寫,可以算出需要左移多少位元
並且因為不用判斷是否為 2 的冪,所以可以省去 if
條件式所造成的分支。
3
10
11
ASCII | Bytes 1 | Bytes 2 | Bytes 3 | Bytes 4 |
---|---|---|---|---|
1 Bytes | 0xxx.xxxx | |||
2 Bytes | 110x.xxxx | 10xx.xxxx | ||
3 Bytes | 1110.xxxx | 10xx.xxxx | 10xx.xxxx | |
4 Bytes | 1111.0xxx | 10xx.xxxx | 10xx.xxxx | 10xx.xxxx |
if
條件式是用來判斷有多少個首位元組,若大於 -65(0b10111111)
,即表示最高的 2 個位元始必為 11
,就可以得到有多少個字元
SWAR 實作:
len
為位元組數量,*end = qword + len >> 3
表示將 end
指標指向不足 8 個 byte
的起始位置
我們要來判斷後續位元組,已知後續位元組的最高 2 個位元會設定為 10
,所以
not bit6 and bit7
1
這邊是要計算有整除 8 的位元組數量,並求出其字元數量,所以 AAAA
應為 3
(len & BBBB)
來找出,所以 BBBB
應為 7
count_utf8()
來處理
end
指標指向不足 8 個 byte
的起始位置len & CCCC
表示還沒計算出來的位元組數量,所以 CCCC
應為 7
DDDD
應為 0
4
判定 16 位元無號整數是否符合特定樣式 (pattern):
可以看出上面這些樣式的二進位表示法從最高位元開始有一段連續的 1,其餘位元皆為 0
若 x 小於等於 0 或最高位元為 0 ,則會離開迴圈。否則會將 x 左移,並檢查最高位元是否為 1
所以可用來判定符合從最高位元開始有一段連續的 1,其餘位元皆為 0
改寫上述程式碼,使其達到等價行為,但更精簡有效。
若 x
符合樣式
x
取二補數,也就是最靠近低位元的 1 不會改變,仍然會是 1x
做 XOR
,會讓最靠近低位元的 1 變成 0x
還要小首先我們先對 x
取二補數
接著觀察 x ^ -x
,發現 x ^ -x
會使最靠近低位元的 1 變成 0,所以 x ^ -x < x
若 x
不符合樣式,則 x ^ -x > x