# 2020q3 Homework3 (quiz3)
contributed by < ddj5523fa >
---
### 想法 & 思考
#### 測驗一
題目:
```cpp
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));
}
```
1.
(1)==const int logical = (((int) -1) OP1) > 0;== 根據參考資料unspecified behavior,得知需先判斷是logic shift或是
arithmetic shift。
所以OP1應為>>1(右移才有logic或arithmetic的差別)<------==answer==
(2)==unsigned int fixu = -(logical & (OP2));== 若m值是正的,則不管是logical或arithmetic,右移時候最左bit一定是補0所以沒有影響。 但是如果是負值最左bit補上的數將不一樣 此行程式碼便是判斷此部分,所以
OP2應為==m<0== <--------------------------------==answer==
(3)==int fix = *(int *) &fixu;== 因型態是unsigned int 與 int所以才以取fixu值的位置再取值assign給fix。
---
#### 測驗二:
```cpp
bool isPowerOfFour(int num)
{
return num > 0 && (num & (num - 1))==0 &&
!(__builtin_ctz(num) OPQ);
}
```
4的power首先先得知是的binary:==100==。
16=$4^2$,其binary: ==10000== 相當於100左移動2格。
64=$4^3$,其binary: ==1000000== 相當於10000左移2格。
1.
(1)由程式碼中num>0可過濾負數,然後(num & (num - 1))==0可得知過濾掉了不是2冪次的數了,因為n是2冪次的時候binary是1後面跟著數個(假設m個)0,而n-1就是0後面跟著"數個(m個)"1,做 AND 就會是0。
(2) 已經過濾了負數且確定是2冪次情況下, ==__builtin_ctz(num)== 可得到num的binary中,後面有幾個0。而根據前面分析4冪次的binary可知後面0的數量必定是偶數個(2的倍數個)。所以__builtin_ctz(num)得到偶數值就是4的冪次,但程式碼取了 ==NOT(!)==
```!(__builtin_ctz(num) OPQ)```顯得此是表達取奇數再取反,才會得是4的冪次。
由以上可得知,OPQ應為 ==&0x1== <------------------------==answer==
---
#### 測驗三:
題目是說num是偶數就除以2,是奇數就-1,重複做了幾次操作會得0。
程式碼:
```cpp
int numberOfSteps (int num)
{
return num ? AAA + 31 - BBB : 0;
}
```
p.s. ```__builtin_popcount(x):``` 計算 x 的二進位表示中,總共有幾個 1
由```1342. Number of Steps to Reduce a Number to Zero```的例子14推演一次: binary是0000 0000 0000 0000 0000 0000 0000 1110
而除以2相當於>>1,所以得知最高位元在第幾位便可知道需要右移幾次,而奇數減1則可觀察到在binary中有1的部分在右移到最低位時候變成了奇數要減掉。
所以檢測有幾個1跟最高位元是幾位是此題關鍵!
1.(1)```__builtin_popcount(x)```便是找出幾個1
(2)程式碼中有個31讓人聯想到,題目提到的==假設 int 為 32 位元寬度==,
所以最高位元應是以int __builtin_clz (unsigned int x)取得前面有多少個0然後用31去扣來得知。
所以AAA為==builtin_popcount(x)== <--------------------answer
BBB為==builtin_popcount(x)== <------------------answer
##### 延伸學習:
考慮到不能用判斷式,想到的便是 AND OR NOT等邏輯式
因該題理解到他會用到偶數判斷與奇數判斷,所以想到num與0x1做and可得之。
於是產生以下程式碼:
```cpp=
int numberOfSteps (int num){
int res=0,subtimes=0,divtimes=0;
while(num>0)
{
int odd=num&1;
int even=!(num&1);
subtimes=subtimes+odd;
divtimes=divtimes+even;
num=(num-odd)>>even;
};
res=subtimes+divtimes;
return res;
}
```
測試有成功submit:

---
#### 測驗四:
```cpp=
#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;
}
```
1.
(1).上方程式碼第5行 !((u|v)&1) 表示出u跟v binary中最左是1的時候,該迴圈結束:此效果能表達出迴圈成立時,表示u、v都還有==2的因數==。
所以程式碼該for迴圈中的shift便是紀錄有多少個共同有的2的因數數量。
(2).while迴圈中除去2的因數是為了製造出兩奇數相減,而此時去除2的因數不會影響結果。
(3).接下來 if else中可以看出,每次操作都將減過得成果存至v是因為兩奇數相減變成偶數,而do while中只有處理v所以,必須將偶數存至v。
(4).do while 結束條件:
根據參考 [此篇](https://hackmd.io/@sysprog/gcd-impl#Binary-GCD)的==Binary GCD Algorithm== 。知道最後依然有採用輾轉相除法,所以最後終止結果為0而每次相減結果存於v。
所以,XXX答案應為==v== <--------------answer!
而 GCD(u,0)=u,所以最大公因數答案應為u,但是必須回復之前for迴圈提出的2的因數,
所以,YYY答案應為==u<<shift== <----------answer!
------------------------------
測驗五: