**2024q1 Homework4 (quiz3+4)** contributed by <YeeeLiang> # 第三周測驗題 ## 測驗一 ```diff int i_sqrt(int x) { if (x <= 1) /* Assume x is always positive */ return x; int z = 0; - for (int m = 1UL << ((31 - __builtin_clz(x)) & ~1UL); m; m >>= AAAA) { + for (int m = 1UL << ((31 - __builtin_clz(x)) & ~1UL); m; m >>= 2) { int b = z + m; - z >>= BBBB; + z >>= 1; if (x >= b) x -= b, z += m; } return z; } ``` ## 測驗二 進行除以 10 的除法和餘數運算,將 CCCC 設置為除法移位的位元數(例如 32 位),將 DDDD 設置為餘數遮罩的位元數(例如 32 位)。 ```diff #include <stdint.h> void divmod_10(uint32_t in, uint32_t *div, uint32_t *mod) { uint32_t x = (in | 1) - (in >> 2); /* div = in/10 ==> div = 0.75*in/8 */ uint32_t q = (x >> 4) + x; x = q; q = (q >> 8) + x; q = (q >> 8) + x; q = (q >> 8) + x; q = (q >> 8) + x; - *div = (q >> CCCC); + *div = (q >> 28); - *mod = in - ((q & ~0x7) + (*div << DDDD)); + *mod = in - ((q & ~0x7) + (*div << 28)); } ``` ## 測驗三 AAAA、BBBB 和 CCCC 需要根據不同的情況設置適當的值,來確保 ilog2 函數的運作。而這些值應該是 2 的冪次方。 考慮到每個 while 迴圈將 i 右移不同的位數,計算每次迴圈中右移的位數,並設置相應的值。在第二版本中,我們使用了 1UL << n 來計算 2 的冪次方,其中 n 是右移的位數。 以下是修改後的程式碼: ```diff static size_t ilog2(size_t i) { size_t result = 0; - while (i >= AAAA) { + while (i >= 1UL << 16) { result += 16; i >>= 16; } - while (i >= BBBB) { + while (i >= 1UL << 8) { result += 8; i >>= 8; } - while (i >= CCCC) { + while (i >= 1UL << 16) { result += 4; i >>= 4; } while (i >= 2) { result += 1; i >>= 1; } return result; } ``` ## 測驗四 在這個 EWMA 實作中,EEEE 和 FFFF 代表位移量,這些位移量需要確保加法和位移操作的結果不會溢出。 對於 **EEEE**,它代表的是左移的位數,確保不會溢出,因此改寫成 **avg->factor**。因為 avg->factor 是初始化時由 ilog2(factor) 計算得來的。 對於 **FFFF**,它代表的是右移的位數,應確保不會溢出,因此改寫成 **avg->weight**。同樣地,avg->weight 是在初始化時由 ilog2(weight) 計算得來的。 ## 測驗五 這段程式碼是用來計算一個32位的無符號整數的對數(logarithm)的向上取整值。在原始碼中,**GGGG** 被替換為將 x 轉換為二進制後的位數,以得到正確的向上取整值。這是因為向上取整的概念是將小數部分捨去,如果最後一次右移操作將有非零的結果,那麼就需要再加 1。 ```diff int ceil_ilog2(uint32_t x) { uint32_t r, shift; x--; r = (x > 0xFFFF) << 4; x >>= r; shift = (x > 0xFF) << 3; x >>= shift; r |= shift; shift = (x > 0xF) << 2; x >>= shift; r |= shift; shift = (x > 0x3) << 1; x >>= shift; - return (r | shift | x > GGGG) + 1; + return (r | shift | x > (x >> 1)) + 1; } ``` # 第四周測驗題 ## 測驗一 ## 測驗二 ## 測驗三