contributed by < PlusThousand0107
>
1
找出最接近且大於等於2的冪的值
利用 bitwise
的技巧,讓 x 和右移後的 x 做 or
操作,此操作能將最高位的 1
之後的所有bit都設成 1
,這樣最後只要再做 x + 1
即可得到最接近且大於等於2的冪的值
以 next_pow2(19)
= 32 為例
x >> 1
的操作後會得到 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1001(2)or
可得 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 1011(2),在這能觀察到在最高位的 1
後面中有本來是 0
的bit被設成 1
了1
後面已經全設成 1
了,只要再做 x + 1
就可得到 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 0000(2) = 32(10)__builtin_clzl
進行改寫__builtin_clzl
可以返回從最高位到第一個 1
之前有幾個 0
,所以用 64 減去此值可知道需位移的量,最後再用 1 向左移此位移量的距離即可得到最接近且大於等於2的冪的值,程式碼如下
以 next_pow2(35)
= 64 為例
__builtin_clzl
會得到 58 ,再用 64 減去 58 得到 6 並將此值設給 shift
(uint64_t)1
往左移 shift
個單位後即可得到 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 0000(2) = 64(10)2
給定一個整數n,將1到n的二進位表示串在一起合成一個二進位字串,將其轉乘十進位數後再 mod + 7
M
設為 1e9 + 7
以表示 + 7for
迴圈中會經過 1 到 n ,透過 len
紀錄整數 i
以二進位表示後的位元長度,在迴圈中還有一個判斷是用 (i & (i - 1)
的方式確認 i
是否為2的冪的值,如果是的話就 len++
i
串到 ans
後面,所以藉由之前以 len
記錄下的長度進行 ans << len
的位移,並將 mod 完 M
後的值傳給 ans
以 n = 5 為例
and
會得到 0 ,所以 len
會從 0 增加到 1 ,最後得到的 ans
為 1len
會從 1 增加到 2 ,這代表目前的這個數的二進位表示法需用到的長度為 2 ,所以用 ans << len
將 1 位移成 100 後,再做 or
並 mod + 7 會得到 110 ,所以 ans
現在是 110len
不會增加,做 ans << len
後可得 11000 ,做完 or
再 mod + 7 會得到 11011len
會再從 2 增加到 3 ,做 ans << len
後會得到 11011000 ,最後的運算結果為 ans
是 11011100len
維持不變,做 ans << len
後可得 11011100000 ,經過 or
和 mod + 7 的運算後得到 11011100101 ,再將這個結果回傳3
這裡參考到了 Ahsen-lab 同學的講解
用 SWAR 的技巧,計算所給定的 UTF-8 字串中 Unicode的字元數量
buf
用 uint64_t
型態的指標 qword
紀錄end
為 qword
的中止條件,這裡從 qword
開始算,後面還須加上 len >> 3
,意思為 len / 8
count
紀錄位元組數量,並用迴圈的方式進行累加t0
取得位元組, 再用 t1
紀錄做完反向運算的結果,之後會讓 t1
和 0x4040404040404040
做 and
,目的為隔離反向的第 6 個位元, t3 = t2 + t2
則是為了左移 1 位元,從第 6 位元移動到第 7 位元,之後的 t4 = t0 & t3
相當於在做 not bit6 and bit7
,最後再用 __builtin_popcountll
計算,並將結果累加給 count
len
除 8 ,再用 bitwise
的方式乘 8 ,減去後續位元組的數量後即可得到 UTF-8 字元的數量len & 7
的方式來做判斷,如果餘數大於 0 就用 count_utf8
處理剩餘的位元組,並將結果加到 count
,若餘數等於 0 則是將 0 加到 count4
判定16位元無號整數是否符合特定樣式,根據給定的範例可發現樣式規定為「最高位必須為 1
,且到最低位的 1
之間的bit也必須都是 1
」,例子如下
做 ~x + 1
的目的是對 x
取二補數,而做 (~x + 1) ^ x
則是想去掉最右邊的 1
,最後再做 ((~x + 1) ^ x) < x
以判別 x
是否符合樣式
True
False
,表示不符合樣式