contributed by < unknowntpo
>
Answer: MMM = (d) 0x8080808080808080
自我問答
str[]
做 check 而不用額外 copy 到 payload 上嗎?
str[1]
這個 object 為例,它的大小是 1 個 byte,而如果要做一次 8 個 byte 的比對的話就需要另一個大小為 8 bytes 的 object,這也是 payload 的作用while ((i + 8) <= size)
,
str[]
內都是 ascii, 但是判斷結果卻是 non-ascii 呢?str[]
的東西while((i + 8) < size)
while (i < size)
?TODO: 做實驗來驗證自己的假設
is
開發解析器 (parser) 時,常會將十六進位表示的字串 (hexadecimal string) 轉為數值,例如 '0xF'
(大寫 F
字元) 和 '0xf'
(小寫 f
字元) 都該轉換為 15
。考慮以下不需要分支 (branchless) 的實作:
AAA = ?
首先觀察字元的規律(用黃色螢光筆標示)
char | ascii code | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | number to transfer: |
---|---|---|---|---|---|---|---|---|---|---|
'0' |
0x30 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0000 |
'1' |
0x31 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0001 |
'2' |
0x32 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0010 |
'9' |
0x39 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1001 |
'A' |
0x41 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1010 |
'a' |
0x61 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1010 |
'F' |
0x46 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1111 |
'f' |
0x66 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1111 |
可以發現:
要轉換的值其實就是那個 character 的 lower 4 bits
e.g. '0'
= 0x30 = [001100000]2 我們要擷取的就是後 4 bits 0000
設計 ascii table 的人真的太有智慧了,處處是玄機呢!
由解答回推運算流程
MASK = (c) 0x40
[0100 0000]2
AAA = (a) 3
[0000 0011]2
BBB = BBB = (a) 6
[0000 0110]2
assume in
為 'f'
[0110 0110]2
line 3:
b6
才是 1in
是否為英文字母
in
是英文字母,letter == 0x40
in
是數字,letter == 0x0
line 4,5:
char | ascii code | b3 | b2 | b1 | b0 | lower 4 bits 代表的數值 |
---|---|---|---|---|---|---|
'a' | 0x41 | 0 | 0 | 0 | 1 | 1 |
'b' | 0x42 | 0 | 0 | 1 | 0 | 2 |
'c' | 0x43 | 0 | 0 | 1 | 1 | 3 |
'd' | 0x44 | 0 | 1 | 0 | 0 | 4 |
'e' | 0x45 | 0 | 1 | 0 | 1 | 5 |
'f' | 0x46 | 0 | 1 | 1 | 0 | 6 |
可以發現只要把每個 letter 的數值 + 9,再 Mask 掉不必要的 higher 4 bits, 就會等於最終我們要轉換的數字了!
+9
這個動作 就對應到 (letter >> 3) | (letter >> 6)
|
運算剛好是 9
!line 5:
TODO: 修飾說明語句
Chang Chen ChienFri, Sep 25, 2020 8:10 AM
延伸問題:
"0xFF"
, "0xCAFEBABE"
, "0x8BADF00D"
等字串輸入,且輸出對應的十進位數值除法運算的成本往往高於加法和乘法,於是改進的策略被引入。其中一種策略是將除法改為乘法運算,例如 在分子和分母分別乘上 後,得到等價的 ,其中對 2 的 N 次方 (power of 2) 進行除法,在無號整數的操作就等同於右移 (shift) N 個位元,又當 (除數) 的數值是已知的狀況下,可預先計算,也就是說, 可轉換為乘法和位移操作,進而減少運算成本。不過,顯然 無法總是用整數來表達 (僅在 是 power of 2 的時候才可),因此,我們可先估算,並將差值補償回去。
重新檢視 ,當我們想將 除以 時,就相當於乘以 ,所以我們可將 改為 ,我們得到整數的部分 (即),和小數部分 (即),後者乘以 就是 ,也就是餘數。下方程式碼展示這概念:
其中 __uint128_t 是 GCC extension,用以表示 128 位元的無號數值。
預期 quickmod(5)
會得到 2
, quickmod(55)
得到 1
, quickmod(555)
得到 0
(555
是 3
的倍數)。
請補完程式碼。
作答區
XXX = ?
(a)
0x00F000F000F00080
(b)
0xF000F000F000F000
(c)
0x0F0F0F0F0F0F0F0F
(d)
0xF0F0F0F0F0F0F0F0
(e)
0x8888888888888888
完全看不懂 …
先從 整數除法開始下手!
LeetCode 29: Divide Two Integers 解析
摘自 < WeiCheng14159> 同學的數學推導
Macro M 的解析
#define M ((uint64_t)(UINT64_C(XXX) / (D) + 1))
UINT64_C
是什麼?
##
接上 ULL
ULL
作用是?
unsigned long long
TODO: run fastdiv
to profile the behavior of macro M
回答 如何確保精確度,不論 是否為整數
不懂: 整數除法上下乘以 後結果是否一樣
div.c
假設我們有
,
其中 , , 都是正整數, 和 已知
我們的目標是不使用除法運算來求出 q = n / d
對於任何 k,
我們可以得到 q =
我們要找出他在何種條件下等於
上式又可寫成
其中
代入 r, 展開式子可得
因為前提是 為整數,所以上式也可以寫成
如果可以滿足
則 (除法運算) 就可以簡化成 (乘法與 bitwise shift)
因為 r < d 且 r / d < 1 總是滿足,為使 ,對於不會超出 的 n,可以令 k = 32 來滿足此條件
How do we get r?
參考解釋
TODO: 解釋 magic number