---
# System prepended metadata

title: 2023q1 Homework2 (quiz2)

---

# 2023q1 Homework2 (quiz2)
contributed by <`kart81604`>

## 測驗`1`
:::success
AAAA = `8` 
BBBB = `32`
CCCC = `x + 1`
:::
### 程式碼原理
首先要將輸入值從左到右第一個出現 `1` 之後的位元都改成`1` ，如輸入
`x = 0100 0100 0100 0010` 應轉換為 `x = 0111 1111 1111 1111`
程式碼部分前七行皆為
```c
x |= x >> 1;
```
這個連做 7 次後，會得到第一個 `1` 之後的 7 個位元也接著會是 `1` ，因此得到了至少連續 8 個`1` 在一起的數列，那之後就也不用慢慢的只位移一個位元了，我們可以一次位移 8 個位元了
```c
x |= x >> 8;
```
之後就會得到從第一個 `1` 開始數，共連續 16 個 `1` 連在一起的數列，以此類推，等等可以直接位移 16 個位元，再來就是 32 個位元了。
做完上述的行為後，我們得到了第一個 `1` 開始之後，後面皆為 `1` 的數列，之後最後再加上 1 ，就可以得到大於輸入值，且為 2 的冪次的輸出值。
```c
return x + 1
```
### 用 `__builtin_clzl` 改寫
:::	success
`int __builtin_clz (unsigned int x)`
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
`int __builtin_clzl (unsigned long)`
Similar to __builtin_clz, except the argument type is unsigned long.
:::
由上述描述可知，`__builtin_clz` 會回傳 `input` 最左邊有幾個連續 `0` ，那麼只要在 `unit64_t` 型別下，全部都是 `1` 的值，往右位移 `__builtin_clzl(x)` 個位元就好了。
```c
uint64_t next_pow2(uint64_t x)
{
    return (0xFFFFFFFFFFFFFFFF >> __builtin_clzl(x)) + 1 ;
}
```

## 測驗`2`
:::success
DDDD = `i & (i - 1)`
EEEE = `ans << len`
:::
### 程式碼原理
設定輸入: n = 4 ，藉由題目描述，已知 n = 3，串接後為 `11011` ，接著要在此數列後新增 `100` ，因此要將原來的數列空出 3 格來放進去。
```c
     vvv
11011
```
用來判斷要移出多少空格的參數為 `len` ，每經過2的冪次之後，要將 `len` 加 1 。
之後將 `ans` 往左位移 `len` 長度，再用 `|` 將要放入的值放進去，再 mod $10^9+7$ 。

## 測驗`3`
:::success
AAAA = 3 
BBBB = 7
CCCC = 7
DDDD = 0
:::
### 程式碼原理
由於 `*end = qword + len >> 3` ，因此 `len` 要是不為 8 的倍數，會有一部分的 byte 沒有被計算到，因此for迴圈不一定有把 `*buf` 全部都檢查到。
由於我們每 8 個 byte 記錄一次，因此我們減掉 `count` 也應該用以計算的部分去減。
```c
count = (1 << 3) * (len / 8)  - count;
```
這部分就是檢查是否有剩餘的 byte 沒有被檢查到，如果有的話，那麼除以 8 就會有非零的餘數，就利用測驗 `3 `前面提到的
`count_utf8` 來計算剩餘的部分，如果 `len` 是 8 的倍數，則代表 for 迴圈就檢查完所有的 byte 了，就也不用再計算了。
```c
count += (len & 7) ? count_utf8((const char *) end, len & 7) : 0;
```
## 測驗`4`
:::success
EEEE = `-x`
FFFF = `x`
:::
### 程式碼原理
`is_pattern` 是要檢查輸入值以二進位表示，是否能分成左右兩部分，左邊皆為 `1` ，右邊皆為 `0`。
```v
1110 0000 0000 0000  //true
1111 1111 1000 0000  //true
1000 0000 0000 0000  //true
1000 1000 0100 0000  //false
     ^     ^
0000 0000 0000 0000  //false
1111 1111 1111 1111  //true
```
假設輸入值是滿足這個條件，也就是左邊部分為連續 `1` ，右邊部分為連續 `0`。
```c
x     = 1111 1100 0000 0000 //input
n     = 0000 0100 0000 0000 //n = -x
              ^
n ^ x = 1111 1000 0000 0000
              ^
```
可以發現，如果輸入值滿足條件，則它的二補數的形式是他的值最右邊的 `1` 的位子為 `1` ，其餘為 `0`，再與輸入值進行 xor ，會得到原本的輸入值，少了最右邊的 `1` ，其餘與原本一樣，因此會比原輸入值小。

再來觀察不滿足條件的狀況 : 
```c
x     = 1111 1100 1000 0000 //input
n     = 0000 0011 1000 0000 //n= -x
n ^ x = 1111 1111 0000 0000
```
```c
x     = 1111 1100 1000 1000 //input
n     = 0000 0011 0111 1000 //n = -x
n ^ x = 1111 1111 1111 0000
```
可以觀察到，`n ^ x` 會得到除了原本為 `1` 位置，還多了好幾個 `1` ，因此會比原輸入值大。
原理如下，找出輸入值轉成二進位後，其中所有 `1` 中最右邊的位子。下例為 10 。
```
1234 5678 9012 3456 //position
xxxx xxxx x100 0000 //input

```
計算其二補數
```
1234 5678 9012 3456 //position
xxxx xxxx x100 0000 //input
yyyy yyyy y011 1111 //~x
yyyy yyyy y100 0000 //-x = ~x + 1
           ^^^ ^^^^ //same as input
```
可以觀察到，以 `-x` 最右邊的 `1` 開始往右，他的二補數部分都與原輸入值相同，之後進行 xor 運算後得出 : 
```
1234 5678 9012 3456 //position
xxxx xxxx x100 0000 //input
yyyy yyyy y100 0000 //-x
1111 1111 1000 0000 //-x ^ x
```
如果 input 前面那串 xxx... ，皆為 `1`，那麼就會比 `-x ^ x` 大，如果其中有包含 `0` ，則會小於 `-x ^ x` 。