contributed by <RusselCK
>
RusselCK
其中 str
是開頭的記憶體地址, size
則是要檢驗的範圍。
0000 0000
~0111 1111
,也就是說只要第 8 個 bit 為 1 ,該欄位便不為有效的 ASCII 字元if (str[i] & 0x80)
),判別第 8 個 bit 是否為 01個
char
的大小 = 1 bytes = 8 bits
0x80 = (1000 0000)2
size_t
uint64_t
void * memcpy ( void * destination, const void * source, size_t num );
num
bytes from the location pointed to by source
directly to the memory block pointed to by destination
.Source : http://www.cplusplus.com/
64 bits = 8 bytes
memcpy(&payload, str + i, 8);
將起始位址 str + i
後的 8 個 bytes 複製到 payload
,再由 if (payload & MMM)
判斷這 8 個bytes 的每一個 bytes 是否都為有效 ASCII 字元& 0x80
來檢查,推理可得,要一次檢查 8 個 bytes ,可以用 & 0x8080808080808080
來檢查0x8080808080808080
size
不為 8 的倍數,前面一個迴圈跳出來後,會剩餘 1~7 個 bytes 沒檢查到return true
>>2
提示: Intel SSE 4.2 加入 STTNI (String and Text New Instructions) 指令,可加速字串比對,詳見: Schema Validation with Intel® Streaming SIMD Extensions 4
已知 in
一定隸屬於 '0', '1', '2', …, '9' 及 'a', 'b', 'c', …, 'f' (小寫) 及 'A', 'B', 'C', …, 'F' (大寫) 這些字元。
預期 hexchar2val('F') 和 hexchar2val('f') 回傳 15 = (1111)2
並且 hexchar2val('0') 回傳 0 = (0000)2
其他輸入都有對應的數值。
Character | Hexdecimal | Binary |
---|---|---|
F | 0x46 | 0100 0110 |
f | 0x66 | 0110 0110 |
0 | 0x30 | 0011 0000 |
in
是 字母 或是 數字in & (0100 0000)
( i.e. in & 0x40
) 來達到此效果
in
為 數字,則 letter
為 0x00 = (0000 0000)2in
為 字母,則 letter
為 0x40 = (0100 0000)2(in + shift) & 0xf
:0xf = (0000 1111)2
in
為 F , ( f 也可推得相同結果 )
(in + shift) & 0xf
= 15shift
) & (0000 1111) = (0000 1111)shift
) = (**** 1111)shift
= (**** 1001)in
為 0 ,
(in + shift) & 0xf
= 0shift
) & (0000 1111) = (0000 0000)shift
) = (**** 0000)shift
= (**** 0000)shift = (letter >> AAA) | (letter >> BBB)
:in
為 字母,則 letter
為 (0100 0000)
shift
= (**** 1001) )
(letter >> AAA)
= (letter >> 3)
= (0000 1000)(letter >> BBB)
= (letter >> 6)
= (0000 0001)in
為 字母、AAA = 3 、 BBB = 6,則 letter
為 (0000 0000)
(letter >> AAA)
= (letter >> 3)
= (0000 0000)(letter >> BBB)
= (letter >> 6)
= (0000 0000)shift
= (**** 0000)total
超過 2^64 - 1 時,會造成 Overflow
#42 total = total << 64 ;
,則可以在更長串的 hexspeak 上執行#44#45
、#47#48
之功能的程式碼payload
為 '8BADF00D'
value
為 0x0d 00 00 0f 0d 0a 0b 08
value
為 0x08 0b 0a 0d 0f 00 00 0d
其中, 可以先算好,節省時間
當我們想將 5 除以 4 時,就相當於乘以 0.25,所以我們可將 改為 5×0.25,我們得到整數的部分 (即 1),和小數部分 (即 0.25),後者乘以 4 就是 1 ,也就是餘數。
uint64_t
UINT64_C
uint_least64_t
uint_least64_t
__uint128_t
M
應該是擔任 的角色,但仍須考量:
uint64
無法表示小數,
D
和 M
都沿用 Q3divisible(7) 要得到 0 (即 7 無法被 3 整除)
divisible(87) 要得到 1 (即白痴是三的倍數)
int tolower ( int c );
在 64 位元處理器架構 (以下針對 x86_64
, little endian),我們可引入向量化 (vectorized) 的手段,避免一次比對一個字元,而是直接操作一整個 word (對 x86_64
來說,就是 64 bits,或 8 個位元組)。
0xff = ( 0000 … 0000 1111 1111 )2
b
為 0x * … * cd = ( **** … **** 1011 1100 )2 ,(uint64_t)(b) & (0xff)
的結果為 ( 0000 … 0000 1011 1100 ) = 0xcd,b
在 16 進制的最後兩位數0xcd * 0x0101010101010101u
結果為 0xcdcdcdcdcdcdcdcd ,即 將前者複製 8 次k
組需要比對#13
判斷 *chunk
是否為 有效的 ASCII 字元 ( 請參考 Q1 )PACKED_BYTE(VV1)
必須為 0x8080808080808080
*chunk & PACKED_BYTE(VV1)
為 0,則 *chunck
8 bytes 皆為有效的 ASCII 字元#17
,我們可以猜測,程式想用 ('A' ^ ' ') // 得到 'a'
的原理,進行大小寫轉換
' '
= 0x20 = 0010 0000
mask
上的對應位置放上 0x20mask
上的對應位置放上 0x00mask = ((A ^ Z) & VV4 ) >>2
應為 0x20 = ( 0010 0000 )
((A ^ Z) & VV4 )
為 ( 1000 0000 ) = 0x80mask = ((A ^ Z) & VV4 ) >>2
應為 0x00 = ( 0000 0000 )
((A ^ Z) & VV4 )
為 ( 0000 0000 ) = 0x00(A ^ Z)
應為 ( 1*** **** )
A
應為 ( 1*** **** ) 、 Z
應為 ( 0*** **** )(A ^ Z)
應為 ( 0*** **** )
A
應為 ( 1*** **** ) 、 Z
應為 ( 1*** **** )#14
應該要找出 ASCII 編碼 >= 'A'
( i.e. ( 0100 0001 ) ) 的 bytes
128 - 'A'
= ( 1000 0000 ) - ( 0100 0001 ) = ( 0011 1111 )*chunk + (128 - 'A' + VV2)
= ( 010* **** ) + ( 0011 1111 ) + VV2
*chunk
是大寫字母,所以
'A'
( 0100 0001 ) + ( 0011 1111 ) = ( 1000 0000 )'Z'
( 0101 1010 ) + ( 0011 1111 ) = ( 1001 1001 )A
應為 ( 1*** **** )#15
應該要找出 ASCII 編碼 <= 'Z'
( i.e. ( 0101 1010 ) ) 的 bytes
128 - 'Z'
= ( 1000 0000 ) - ( 0101 1010 ) = ( 0010 0110 )*chunk + (128 - 'Z' + VV3)
= ( 010* **** ) + ( 0010 0110 ) + VV3
*chunk
是大寫字母,所以
'A'
( 0100 0001 ) + ( 0010 0110 ) = ( 0110 0111 )'Z'
( 0101 1010 ) + ( 0010 0110 ) = ( 1000 0000 )'Z'
以外,其他大寫字母都能達成假設的目標:Z
應為 ( 0*** **** )'Z'
達成目標,可以假設 VV3 = -1*chunk
中有幾個 bytes 不為有效的 ASCII 字元,則無法一次轉換 8 bytesmain
函式的 char str[]
更換為 char *str
,會發生什麼事?( p.62 )
In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.
The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.
For character string literals, the array elements have type char
, and are initialized with the individual bytes of the multibyte character sequence; …
It is unspecified whether these arrays are distinct provided their elements have the appropriate values.
If the program attempts to modify such an array, the behavior is undefined.
( p.130 )
The declaration
defines ‘‘plain’’ char
array objects s
and t
whose elements are initialized with character string literals.
This declaration is identical to
The contents of the arrays are modifiable.
On the other hand, the declaration
defines p
with type ‘‘pointer to char
’’ and initializes it to point to an object with type ‘‘array of char
’’ with length 4 whose elements are initialized with a character string literal.
If an attempt is made to use p
to modify the contents of the array, the behavior is undefined.
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
XOR 運算 = 看到 1 就反轉,看到 0 不變
從 bitwise 的角度出發,note
的每個 bit 分別紀錄以檢查的 nums[i]
各 bit 出現 1 的次數
狀態圖:( 圓圈中的值代表 notei )
A | B | C |
---|---|---|
notei | numi | new notei |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
因此, new notei = notei numi
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
與 q6 相同概念,不同的是,數字可能出現 1~3 次,需要 lower
( 下方簡稱 L )及 higher
( 下方簡稱 H ) 兩個值來幫忙紀錄:
狀態圖:( 圓圈中的值代表 HiLi )
A | B | C | D | E |
---|---|---|---|---|
Hi | Li | numi | new Hi | new Li |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 0 | 1 |
0 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 0 |
因此,new Li = ~ Hi & ( Li numi )
因此,new Hi = ~ (new Li) & ( Hi numi )
故,KKK = ~higher 、 JJJ = ~lower
Q6. 最後的數學推導中, new Hi 還有另一種寫法:
檢測結果:
note
一個值紀錄即可:
數字可能出現 1~5 次,需要 left
( 下方簡稱 L )、middle
( 下方簡稱 M )、right
( 下方簡稱 R ) 三個值來幫忙紀錄:
狀態圖:( 圓圈中的值代表 LiMiRi )
A | B | C | D | E | F | G |
---|---|---|---|---|---|---|
Li | Mi | Ri | numi | new Li | new Mi | new Ri |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 |
0 | 0 | 1 | 0 | 0 | 0 | 1 |
0 | 0 | 1 | 1 | 0 | 1 | 0 |
0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 0 | 1 | 1 |
0 | 1 | 1 | 0 | 0 | 1 | 1 |
0 | 1 | 1 | 1 | 1 | 0 | 0 |
1 | 0 | 0 | 0 | 1 | 0 | 0 |
1 | 0 | 0 | 1 | 0 | 0 | 0 |