# 2020q3 Homework3 (quiz3)
contributed by < `fdfdd12345628` >
## 測驗一
```clike=
int asr_i(signed int m, unsigned int n)
{
const int logical = (((int) -1) OP1) > 0;
unsigned int fixu = -(logical & (OP2));
int fix = *(int *) &fixu;
return (m >> n) | (fix ^ (fix >> n));
}
```
由於不知道該系統的 shift 是哪一種,而 asr_i 要當 m<0 時補 1 ,否則補 0 。
因此第三行的 `logical` 就是判斷負數的 shift 是補 1 還是補 0 (如果補 1 則還是負數,補 0 則會變成正數)
第四行的 `fixu` 則是判斷 `m` 是不是負數,如果 `m` 是負數且 `logical` 為 0 (shift 是補 0),則需要特別處理,此時 `fixu` 會是 -1 也就是 `0xffffffff`。
第六行則會直接進行 shift ,並且使用 `fixu` 的數值,如果是 -1 則會把原本補 0 的地方變成 1 。如果是 0 則會直接沿用原本 shift 的結果。
因此 OP1 為 >> 1
OP2 為 m<0
## 測驗二
```clike=
bool isPowerOfFour(int num)
{
return num > 0 && (num & (num - 1))==0 &&
!(__builtin_ctz(num) OPQ);
}
```
根據觀察,如果該數字為四的次方,則該數字為二的次方,且 tailing zero 為偶數。
其中 `(num & (num - 1))==0` 為判斷該數字是不是二的次方。
並且如果 tailing zero 的最後一 bit 為零,則代表其為偶數。
因此 & 0x1 可以判斷是不是基數,而將其反向就是偶數
因此 OPQ 為`&0x1`
## 測驗三
在題目 Number of Steps to Reduce a Number to Zero 中,每當最後的數字是 1 則需要兩次操作(先減一再除以二),若是 0 則是需要一次操作(除以二)
因此全部需要的時間就是(全部的 1 )*2+(除了 leading zero 外的 zero ),而除了 leading zero 外的 zero 就是(32-(全部的 1)- (leading zero))
化減之後就是 32+(全部的 1 )-(leading zero),但是因為最後一個 1 只要減 1 即可,不用除以 2 ,因此會少一步,也就是 31+(全部的 1 )-(leading zero)
也就是 31 + popcount - clz
因此 AAA 為 __builtin_popcount(num)
BBB 為 __builtin_clz(num)
## 測驗四
```clike=
#include <stdint.h>
uint64_t gcd64(uint64_t u, uint64_t v) {
if (!u || !v) return u | v;
int shift;
for (shift = 0; !((u | v) & 1); shift++) {
u /= 2, v /= 2;
}
while (!(u & 1))
u /= 2;
do {
while (!(v & 1))
v /= 2;
if (u < v) {
v -= u;
} else {
uint64_t t = u - v;
u = v;
v = t;
}
} while (XXX);
return YYY;
}
```