# 2017q1 Homework1 (clz)
contributed by <`zmke`>
## 開發環境
OS: Ubuntu 16.04 LTS
Architecture: x86_64
CPU 作業模式: 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
Model name: Intel(R) Core(TM) i5-4200H CPU @ 2.80GHz
L1d 快取: 32K
L1i 快取: 32K
L2 快取: 256K
L3 快取: 3072K
## Count Leading Zero
* 計算從 MSB 開始往下到第一個 1 有幾個 0
### recursive version
```==
static const int mask[]= {0,8,12,14};
static const int magic[]= {2,1,0,0};
unsigned clz2(uint32_t x,int c)
{
if (!x && !c) return 32;
uint32_t upper = (x >> (16>>c));
uint32_t lower = (x & (0xFFFF>>mask[c]));
if (c == 3) return upper ? magic[upper] : 2 + magic[lower];
return upper ? clz2(upper, c + 1) : (16 >> (c)) + clz2(lower, c + 1);
}
```
* 從 `clz2(x, 0)` 開始,將 x 分成兩半(upper and lower)
* 若 `upper == 0` 將 `lower` 代入下層遞迴,否則代入 `upper`
* `c == 3` 時終止,用 `magic[]` 來判斷剩下的兩個 bit 開頭有幾個 0
* 將下層的結果加上確定的 0 數得到答案
### iteration version
```==
static inline __attribute((always_inline))
unsigned clz(uint32_t x)
{
int n = 32, c = 16;
do {
uint32_t y = x >> c;
if (y) {
n -= c;
x = y;
}
c >>= 1;
} while (c);
return (n - x);
}
```
* y 與 upper 類似,用來紀錄前一半的 bit string
* `y != 0` 將關注的 bit string 縮小到 y ,繼續迴圈
* `y == 0` 向 LSB 方向擴大 c 個 bit
* 直到 `c == 0` 終止,回傳 n-x , x 是最後剩下的一個 bit 會等於 1 或 0
### byte shift technique
```==
static inline __attribute((always_inline))
unsigned clz(uint32_t x)
{
if (x == 0) return 32;
int n = 0;
if (x <= 0x0000FFFF) {
n += 16;
x <<= 16;
}
if (x <= 0x00FFFFFF) {
n += 8;
x <<= 8;
}
if (x <= 0x0FFFFFFF) {
n += 4;
x <<= 4;
}
if (x <= 0x3FFFFFFF) {
n += 2;
x <<= 2;
}
if (x <= 0x7FFFFFFF) {
n += 1;
x <<= 1;
}
return n;
}
```
## Reference
[重新理解數值](https://hackmd.io/s/Hy-pTh8Fl)
[ktvexe 筆記](https://hackmd.io/s/BJBZn6Q6)