contributed by < `tab08222` >
## 測驗一
### 解釋程式碼運作原理
本題要考慮 next_pow2 可針對給定無號 64 位元數值 x,找出最接近且大於等於 2 的冪的值
```c
int main()
{
x |= x >> 1;
x |= x >> 1;
x |= x >> 1;
x |= x >> 1;
x |= x >> 1;
x |= x >> 1;
x |= x >> 1;
x |= x >> AAAA;
x |= x >> 16;
x |= x >> BBBB;
return CCCC ;
}
```
依題目給定的程式碼可以發現,該段程式碼目的在於將最高位元後方的 bit 以 1 替代,最後 +1 來得到最接近的 2 的冪的值,因此:
`AAAA` : 8
`BBBB` : 32
`CCCC` : x+1
### 用`__builtin_clz`改寫
先用`__builtin_clz`找出msb, 接著以 64-msb 找到 input 之 msb 的更高一個位元,即`y`
再以`pow(2,64-y-1)`計算出冪值
```c
uint64_t next_pow2(uint64_t x)
{
int result,y;
y = __builtin_clz(x);
return pow(2,64-y-1);
}
```
---
## 測驗二
### 解釋程式碼運作原理
```c
int concatenatedBinary(int n)
{
const int M = 1e9 + 7;
int len = 0; /* the bit length to be shifted */
/* use long here as it potentially could overflow for int */
long ans = 0;
for (int i = 1; i <= n; i++) {
/* removing the rightmost set bit
* e.g. 100100 -> 100000
* 000001 -> 000000
* 000000 -> 000000
* after removal, if it is 0, then it means it is power of 2
* as all power of 2 only contains 1 set bit
* if it is power of 2, we increase the bit length
*/
if (!(DDDD))
len++;
ans = (i | (EEEE)) % M;
}
return ans;
}
```
`for` 迴圈內的功能在於判斷每一個數字需要用幾個位元(即 `len` )來表達,由於只有遇到 2 的冪值時,`len` 才會增加,因此 `if` 判斷式的目的即為判斷 `n` 是否為 2 的冪值,因此:
`DDDD` : `n&~2^log2(n)`
`EEEE` : `i<<len`
```c
int concatenatedBinary(int n)
{
const int M = 1e9 + 7;
int len = 0; /* the bit length to be shifted */
/* use long here as it potentially could overflow for int */
long ans = 0;
for (int i = 1; i <= n; i++) {
/* removing the rightmost set bit
* e.g. 100100 -> 100000
* 000001 -> 000000
* 000000 -> 000000
* after removal, if it is 0, then it means it is power of 2
* as all power of 2 only contains 1 set bit
* if it is power of 2, we increase the bit length
*/
if (len = __builtin_ctz(n))
len++;
ans = (i | (i<<len)) % M;
}
return ans;
}
```
這裡以` __builtin_ctz` 來計算從右方數來共有多少連續個 0,藉此判斷n是否為 2 的冪的值
---
## 測驗三
---
## 測驗四
### 解釋程式碼運作原理
```c
#include <stdint.h>
#include <stdbool.h>
bool is_pattern(uint16_t x)
{
if (!x)
return 0;
for (; x > 0; x <<= 1) {
if (!(x & 0x8000))
return false;
}
return true;
}
```
該段程式碼可以判斷在輸入當中,是否可以找到一個 bit,使得其左方皆為 1,右方皆為 0
### 改寫上述程式碼,使其達到等價行為
```c
bool is_pattern(uint16_t x)
{
const uint16_t n =EEEE;
return (n ^ x) < FFFF;
}
```
令n的每個bit皆為1,再做 `n ^ x` ,此時若輸入為合法 pattern ,代表 1 集中在高位元,那麼`n ^ x` 會讓數值變小,若輸入不為合法 pattern,則代表有 0 出現在 1 前面,這時 `n ^ x` 會讓數值變大,因此:
`EEEE` : 65535
`FFFF` : x