contributed by < scottxxxabc
>
是否有必要先將數值轉成字串?用十進位的角度處理運算是否產生額外的計算負擔?
isqrt
使用到查表的方式來計算平方根,clz
x << lz
的範圍就會被限定在 0x4000 0000 ~ 0xFFFF FFFF,isqrt
取 x
的最高 8 個 bit,讓表格的大小可以限定在 0x40 () ~ 0xFF () 之間。
接下來用最高 8 個 bit (x >> 56) - 64
作為 index k
查閱表格,可以查到 256 * (k + 65) - 1
的 isqrt
值。
k + 65
的值在 65~256 之間,表格的範圍落在 ~
因為首先取了 8 個 bit,查表時再乘上 256 (),因此還需要將查表得到的 y
值左移 ,也就是24 bit。
最後因為一開始將 x
左移 lz
個 bit,所以還要將 y
右移 lz / 2
個 bit 。
generate_sieve
產生了一個 bitmask,每一個 bit 代表一個數字是否為質數。
max
代表回文數字的上限,因此只需要標記到 isqrt(max)
的數字為止,另外所有的偶數都不是質數,所以 bit 數減半。 bit 為 1 的話就代表 這個數不是質數,bit 為 0 則是質數。
一開始先將 1 (bit 0)設為合數,接下來逐個檢查每個奇數是不是質數 :
n >> 4
來取得 index,psieve[n >> 4]
就是所在的 byte。(n >> 1)
bit 代表的數字為 。利用 bitwise-AND mask,來取得所在 byte 的 offset,將 mask
設為 0x07,相當於除以 8 的餘數,也就是一個byte的長度。n
的所有倍數的 bit 設為 1pquadbits
每次取出 psieve
的 64 個 bitsquad
將 pquadbits
反轉,因此 quad
的 0 代表合數,1 代表質數。& ~0b111
忽略前 3 個 bits ,從 7 開始檢查。prev
代表前一次迴圈檢查到第 prev
個 bit,每次 for 迴圈將 prev
增加 quad
的大小 64 bits。若是 prev
大於 half_max
就結束迴圈。i = __builtin_ctzll(quad)
找出 quad
結尾的 0 的數量。 quad
的 0 代表合數,所有的合數都可以拆解成二個或多個更小質數的乘積,所以可以跳過。!(val % ((next << 1) + 1))
檢查 val
是否能被 整除,若是可以則直接 return false,代表 val
不是質數。quad &= ~(1ULL << i)
將已經檢查過的 bit clear 為 0。