contributed by < joshyue
>
1
參照 你所不知道的 C 語言: bitwise 操作,考慮 next_pow2 可針對給定無號 64 位元數值 x,找出最接近且大於等於 2 的冪的值
x
,在此以x = 0b0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
為例。x |= x >> 1
運算,可保證原先最高位的1後面會有6個1,即x = 0b0111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
。x |= x >> 8
、x |= x >> 32
、x |= x >> 64
,則x = 0b0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
,如此便能使一開始最高位的1右邊所有位元皆指派為1。x + 1
才為2的冪,因此最後要return x + 1
,即能得到next_pow2
所求。__builtin_clzl : Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
x
不為0
時,__builtin_clzl(x)
會回傳最高位開始連續0的個數的功能,假設x=1024
時,則clz = 53
。clz
,回傳(1 << (64 - clz))
,即得題目所求。fls
函式,有使用到__builtin_clz
的功能。fls - find last (most-significant) bit set
透過sizeof(x) * 8
可得到x
的位元數量,再減去最高位開始連續0的個數,則可以得到fls
函式所求,即最高位元的1的bit index + 1。
cc -O2 -std=c99 -S next_pow2.c
,觀察所得next_pow2.s
__builtin_clzl(x)
所對應的x86指令,其中 bsrq %rdi, %rdi
會將最高位的1之bit index儲存於rdi暫存器。xorq $63, %rdi
則是對63
與最高位的1之bit index作Exclusive OR
,則等同於63 - 1之bit index
,因此得到所求,即最高位開始連續0的個數。2
LeetCode 1680. Concatenation of Consecutive Binary Numbers 給定一整數 n ,回傳將 1 到 n 的二進位表示法依序串接在一起所得到的二進位字串,其所代表的十進位數字 mod 之值。
i
是否為2的冪,現假設i = 8
,則二進位表示0b1000
,i - 1
的二進位表示則為0b0111
,可觀察到兩者依序對應的bit皆相異,因此當i
為2的冪時,i & (i - 1)
必等於0。ans
)向左shift所需串接的i之位元長度(len
)後,再與i作bitwise OR
,最後再mod ,即為題目所求。__builtin_ffsl : Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
__builtin_ffsl
來取得最低位開始第一個1的bit index + 1,i >> (ffs)
若為0,則表示i
為2的冪,而後發現此程式碼仍可改進,改進如下。__builtin_clzl
得到最高位開始連續0個數後,將i往左shift 64 - __builtin_clzl(i)
(其等同先前的程式碼向左shift len
),這樣的改進能省去if
的分支,不用判斷i
是否為2的冪,使程式碼更加精簡。3
SIMD within a register (SWAR) 是軟體最佳化技巧之一
__builtin_popcountll : Returns the number of 1-bits in x.
__builtin_popcountll
求得位元組內1的總數,conut
即代表題目所述continuation bytes(後續位元組)的個數。(len / 8)
即表示完整處理的次數(因後續要判斷剩餘未滿1個qword的狀況),(1 << 3) * (len / 8)
表示完整處理的次數再乘以8,即已處理字串的長度,並且題目有提到字串長度減去後續位元組,即可確定字元數量,因此我們要再減去第13行得到的count
,得到字元數量。(len & 7)
等同於len % 7
,若len & 7
不為0,表示我們仍有未處理的字元,則呼叫原先的函式count_utf8
,回傳剩餘的字元數量。utf8_strncmp
函式。utf8ncursor
結構表示字串處理的進度,分別透過c1
及c2
獲取目前處理字串位置的一個位元組,並轉換此位元組的型態為unsigned char
,因此若c1
或c2
小於0,則表示程式無效,回傳-EINVAL
,反之的話就是繼續判斷兩個字元是否相等。4
以下程式碼可判定 16 位元無號整數是否符合以下特定樣式 (pattern):
x
觀察是否符合程式碼的樣式(pattern)可發現,只要x
在二進位下符合最高位開始為1的條件,後面依序接著連續的1(可為0個)與連續的0(可為0個),則符合上述的樣式。-x
表示x
的二補數,以下方圖表為例,若x符合樣式,則(n ^ x)
必定小於x
,因此回傳True
。x | n = -x | n ^ x |
---|---|---|
(1111 0000 0000 0000)2 | (0001 0000 0000 0000)2 | (1110 0000 0000 0000)2 |
(1111 0100 0000 0000)2 | (0000 1100 0000 0000)2 | (1111 1000 0000 0000)2 |
(1111 0000 0000 0001)2 | (0000 1111 1111 1111)2 | (1111 1111 1111 1110)2 |