contributed by < grb72t3yde
>
sysprog2020
一
目前電腦中用得最廣泛的字元集及其編碼,是美國國家標準局 (ANSI) 制定的 ASCII 碼,被國際標準化組織 (ISO) 採納為 ISO 646 標準。7 位碼 ASCII 是以 7 位元二進位數字進行編碼,可表示 128 個字元,第 128~255 號為擴展字元 (extended ASCII)。如果我們明確界定 7 位元編碼的字元隸屬於 ASCII,可透過以下函式來判斷指定的記憶體範圍內是否全是有效的 ASCII 字元:
其中 str
是開頭的記憶體地址, size
則是要檢驗的範圍。逐一字元比對的效率低,在 64 位元的架構下,我們嘗試一次比對 64 位元的資料 (即 word size),程式碼改寫如下:
is_ascii
, 我從 line 10
的 while loop condition
以及 payload
的 data type
得知, 這個 while loop 是以 word width
來做是否為 ascii
的判斷。MSB
必為 0 (其範圍在0~127); 因此, MMM
= 0x8080808080808080
。word
的 bytes
組, 會在第二個 while loop
對 byte
逐一檢查。is_ascii
函式中之 argument const char str[]
接受的引數以 const char
之寬度對齊word
的寬度進行 bit-wise operation, 因此使用 memcpy
, 將 8個 byte 的資料複製到已宣告且以 uint64_t
type 來對齊的變數 payload
中思考 : 如果不使用
memcpy
?
考慮下列修改 :
使用 gdb
觀察, 仍能達到類似效果; 但是參考 Should I worry about the alignment during pointer casting? 後得知, 這是相較於使用 memcpy() 較危險且不具效率的方法 -> 待研究細節。
ASCII
表得知:A
至 Z
的範圍在 0x41 ~ 0x5a
; a
至 z
的範圍在 0x61 ~ 0x7a
。
二
開發解析器 (parser) 時,常會將十六進位表示的字串 (hexadecimal string) 轉為數值,例如 '0xF' (大寫 F 字元) 和 '0xf' (小寫 f 字元) 都該轉換為 15。考慮以下不需要分支 (branchless) 的實作
ASCII
編碼中的低位4個 byte, 發現 : 數字字元不需要修正, 而英文字母需要 + 0x09
(e.g. 0x41 ('A') + 0x09 = 0x4a, mask 掉高位的4個 bit 後得到 0x0a = 10)shift
修正值, 我思考要用 MASK 留下 in 中得以區別字母與數字的部分大寫字母字元 : 0100
小寫字母字元 : 0110
數字字元 : 0011
發現可以用 0100
來 mask 出字母與數字! 因此初步判定 MASK
= 0x40
MASK
= 0x40
以及 in
只會是對應到 ASCII
中大小寫字母與數字假設, 我們得到letter = 0x40, if
in
對應到的ASCII
為大小寫字母
letter = 0x00, else
+0x09
的修正, 而數字不用), 可以判斷 AAA 和 BBB 其一為3, 另一個則為6hexchar2val
擴充為允許 "0xFF"
, "0xCAFEBABE"
, "0x8BADF00D"
等字串輸入,且輸出對應的十進位數值想法 : 首先考慮輸入字元的個數, 如果我們想要以 word
來處理資料, 需要考慮到補 0
實驗 : TODO
三
shift operation
以及 乘法
的組合其中 __uint128_t
是 GCC extension,用以表示 128 位元的無號數值。
D = 3
不為一個 power of 2
的數值, 因此思考題目敘述 : "我們可先估算,並將差值補償回去" 後, 判斷 line2 的 macro 應該在做此 "估算並補償的動作"ceil(2^k / d)
作為 magic
, 並且設定 (能使得 n / 2^k 恆小於 1) 的情況下 :floor(ceil(2^k / d) * n / 2^k)
得到 在數學上正確的 quotientM
, 並根據 ISO/IEC 9899:201x
, UINT64_C(XXX)
將 XXX
expand 至 unsigned long long int
, 這個 data type 沒辦法正確地表示出 C
使用 floor
處理商數的小數點, 於是我們使用 +1
來達到 ceiling
d = 3
時永遠可以得到對的結果;TODO
四
延伸測驗 3
,我們想判斷某個數值能否被指定的除數所整除,在 D 和 M 都沿用的狀況下,程式碼如下:
+2
可以看出在 n 這三種情況下, n*M 的值會因為數值溢位會有對應且固定的表示公式, 再來我們從答案選出一個定值, 能夠分界出 n = 3k
與 n = 3k + 1 和 n = 3k + 2
的 case
五
考慮 strlower
函式的作用是將指定的字串 (或部分字串) 的英文字母全改為小寫,其 in-place 的實作如下:
在 64 位元處理器架構 (以下針對 x86_64, little endian),我們可引入向量化 (vectorized) 的手段,避免一次比對一個字元,而是直接操作一整個 word (對 x86_64 來說,就是 64 bits,或 8 個位元組)。沿用上述的 strlower 函式,我們用這樣的思路實作向量化的 strlower,程式碼列表如下:
六