# 2022q1 Homework3 (quiz3) contributed by < [2020leon](https://github.com/2020leon) > ## [作業要求](https://hackmd.io/@sysprog/BJJMuNRlq) - [ ] 重新回答[第 3 周測驗題](https://hackmd.io/@sysprog/linux2022-quiz3)^從測驗一到測驗十一^,附帶的「==延伸問題==」也需要完成 - 解釋程式運作原理時,應提供對應的 [Graphviz](https://graphviz.org/) 圖例,可參照 [Linked List 題目 1 + 分析](https://hackmd.io/@sysprog/linked-list-quiz) - [ ] 比照 [課前測驗參考解答: Q1](https://hackmd.io/s/ByzoiggIb), [Linked list 題目分析](https://hackmd.io/s/HyELy5bTz) 和 [參考題解](https://hackmd.io/@RinHizakura/BysgszHNw) 的模式來撰寫共筆,需要詳細分析自己的思路、參閱的材料 (以第一手材料為主,包含 C 語言規格書的章節),以及==進行相關實驗==。 - [x] 將你的共筆加到 [2022q1 Homework3 (作業區)](https://hackmd.io/@sysprog/linux2022-homework3) ## [測驗題目](https://hackmd.io/@sysprog/linux2022-quiz3) ### 測驗 `1` #### 測驗 `1` 填空 ```c #define GENMASK(h, l) \ (((~0UL) >> (LEFT)) & ((~0UL) >> (l) << (RIGHT))) ``` 首先 `~0UL` 為在二進位中全是 `1` 的數,在 64 位元中即 `0xffffffffffffffff` 。若要達到題目要求,須對該數位移。其中 `(~0UL) >> (LEFT)` 的目的為製造在較高位元的 `0` ,故填入 `63 -h` ;而 `(~0UL) >> (l) << (RIGHT)` 則是空出較低位元的 `0` ,故填入 `l` 。 | 陳述式 | 答案 | | ------- | -------- | | `LEFT` | `63 - h` | | `RIGHT` | `l` | :::info 注:事實上如下便可達到要求。 ```c #define GENMASK(h, l) \ (((~0UL) >> (63 - h)) & ((~0UL) << (l))) ``` ::: ### 測驗 `2` #### 測驗 `2` 填空 ```c struct foo; struct fd { struct foo *foo; unsigned int flags; }; enum { FOO_DEFAULT = 0, FOO_ACTION, FOO_UNLOCK, } FOO_FLAGS; static inline struct fd to_fd(unsigned long v) { return (struct fd){EXP1, v & 3}; } ``` 觀察結構成員型態,因此賦值時須轉換型態為 `struct foo *` 以避免編譯器警告。再依據題目要求「對 4 個位元組進行向下對齊」,須清空所傳進之 `v` 參數之最低二位元,即將 `v` 和一特定遮罩進行 AND 運算。而最容易製作遮罩的方式即對 3 進行一補數運算。因此空格需填入 `(struct foo *) (v & ~3)` 。 | 陳述式 | 答案 | | ------ | ------------------------- | | `EXP1` | `(struct foo *) (v & ~3)` | ### 測驗 `3` #### 測驗 `3` 填空 ```c #include <stdint.h> uint8_t rev8(uint8_t x) { x = (x >> 4) | (x << 4); x = ((x & 0xCC) >> 2) | (EXP2); x = ((x & 0xAA) >> 1) | (EXP3); return x; } ``` 逐一位元反轉可見於[課程說明](https://docs.google.com/presentation/d/1B80k91_3_XuZ0zMzfdgS-D1I29VaHxZTg3XD3bok0io/edit#slide=id.g4f2b7eb495_0_12),其原理便是從「大單位」逐漸反轉至「小單位」,直至全部反轉完畢。 | 陳述式 | 答案 | | ------ | ----------------- | | `EXP2` | `(x & 0x33) << 2` | | `EXP3` | `(x & 0x55) << 1` | ### 測驗 `4` #### 測驗 `4` 填空 ```c #include <assert.h> #define _foreach_no_nullval(i, p, arr) \ assert((i) >= sizeof(arr) / sizeof(arr[0]) || (p)) #define foreach_int(i, ...) \ for (unsigned _foreach_i = (((i) = ((int[]){__VA_ARGS__})[0]), 0); \ _foreach_i < sizeof((int[]){__VA_ARGS__}) / sizeof(int); \ (i) = ((int[]){__VA_ARGS__, 0})[EXP4]) #define foreach_ptr(i, ...) \ for (unsigned _foreach_i = \ (((i) = (void *) ((typeof(i)[]){__VA_ARGS__})[0]), 0); \ (i); (i) = (void *) ((typeof(i)[]){__VA_ARGS__, \ NULL})[EXP5], \ _foreach_no_nullval(_foreach_i, i, \ ((const void *[]){__VA_ARGS__}))) ``` 觀察題目範例後可知兩個 `foreach` 巨集均是對 `__VA_ARGS__` 進行遍歷,而 `i` 為遍歷時儲存遍歷值的變數,真正的索引變數為 `_foreach_i` 。在進行遍歷時,須對 `_foreach_i` 做累加,並取其值作為索引。在此為 `++_foreach_i` 而非 `_foreach_i++` 的原因為 `i` 所要儲存的應為下一個元素,因此先加一後再取其值。 | 陳述式 | 答案 | | ------ | -------------- | | `EXP4` | `++_foreach_i` | | `EXP5` | `++_foreach_i` | ### 測驗 `5` #### 測驗 `5` 填空 ```c #include <limits.h> int divide(int dividend, int divisor) { int signal = 1; unsigned int dvd = dividend; if (dividend < 0) { signal *= -1; dvd = ~dvd + 1; } unsigned int dvs = divisor; if (divisor < 0) { signal *= -1; dvs = ~dvs + 1; } int shift = 0; while (dvd > (EXP6)) shift++; unsigned int res = 0; while (dvd >= dvs) { while (dvd < (dvs << shift)) shift--; res |= (unsigned int) 1 << shift; EXP7; } if (signal == 1 && res >= INT_MAX) return INT_MAX; return res * signal; } ``` | 陳述式 | 答案 | | ------ | --------------------- | | `EXP6` | `dvs << shift` | | `EXP7` | `dvd -= dvs << shift` | ### 測驗 `6` #### 測驗 `6` 填空 ```c #include <stdbool.h> #include "list.h" struct Point { int x, y; }; struct point_node { int p1, p2; struct list_head link; }; static bool can_insert(struct list_head *head, int p1, int p2) { struct point_node *pn; list_for_each_entry (pn, head, link) return EXP8; return true; } static int gcd(int x, int y) { while (y) { int tmp = y; y = x % y; x = tmp; } return x; } static int maxPoints(struct Point *points, int pointsSize) { if (pointsSize <= 2) return pointsSize; int i, j, slope_size = pointsSize * pointsSize / 2 + 133; int *dup_cnts = malloc(pointsSize * sizeof(int)); int *hori_cnts = malloc(pointsSize * sizeof(int)); int *vert_cnts = malloc(pointsSize * sizeof(int)); int *slope_cnts = malloc(slope_size * sizeof(int)); memset(hori_cnts, 0, pointsSize * sizeof(int)); memset(vert_cnts, 0, pointsSize * sizeof(int)); memset(slope_cnts, 0, slope_size * sizeof(int)); for (i = 0; i < pointsSize; i++) dup_cnts[i] = 1; struct list_head *heads = malloc(slope_size * sizeof(*heads)); for (i = 0; i < slope_size; i++) INIT_LIST_HEAD(&heads[i]); for (i = 0; i < pointsSize; i++) { for (j = i + 1; j < pointsSize; j++) { if (points[i].x == points[j].x) hori_cnts[i]++, hori_cnts[j]++; if (points[i].y == points[j].y) vert_cnts[i]++, vert_cnts[j]++; if (points[i].x == points[j].x && points[i].y == points[j].y) dup_cnts[i]++, dup_cnts[j]++; if (points[i].x != points[j].x && points[i].y != points[j].y) { int dx = points[j].x - points[i].x; int dy = points[j].y - points[i].y; int tmp = gcd(dx, dy); dx /= tmp; dy /= tmp; int hash = dx * dy - 1333 * (dx + dy); if (hash < 0) hash = -hash; hash %= slope_size; if (can_insert(&heads[hash], i, j)) { struct point_node *pn = malloc(sizeof(*pn)); pn->p1 = i; pn->p2 = j; EXP9; } } } } for (i = 0; i < slope_size; i++) { int index = -1; struct point_node *pn; list_for_each_entry (pn, &heads[i], link) { index = pn->p1; slope_cnts[i]++; } if (index >= 0) slope_cnts[i] += dup_cnts[index]; } int max_num = 0; for (i = 0; i < pointsSize; i++) { if (hori_cnts[i] + 1 > max_num) max_num = hori_cnts[i] + 1; if (vert_cnts[i] + 1 > max_num) max_num = vert_cnts[i] + 1; } for (i = 0; i < slope_size; i++) { if (slope_cnts[i] > max_num) max_num = slope_cnts[i]; } return max_num; } ``` | 陳述式 | 答案 | | ------ | ----------------------------------- | | `EXP8` | `p1 == pn->p1` 或 `pn->p1 == p1` | | `EXP9` | `list_add(&pn->link, &heads[hash])` | ### 測驗 `7` #### 測驗 `7` 填空 ```c int ilog32(uint32_t v) { int ret = v > 0; int m = (v > 0xFFFFU) << 4; v >>= m; ret |= m; m = (v > 0xFFU) << 3; v >>= m; ret |= m; m = (v > 0xFU) << 2; v >>= m; ret |= m; m = EXP10; v >>= m; ret |= m; EXP11; return ret; } ``` | 陳述式 | 答案 | | ------- | ------------------ | | `EXP10` | `m = (v > 3) << 1` | | `EXP11` | `ret += v > 1` | ### 測驗 `8` #### 測驗 `8` 填空 ```cpp void remove_data(tree &t, int d) { tnode **p = &t; while (*p != 0 && (*p)->data != d) { if (d < (*p)->data) EXP12; else EXP13; } tnode *q = *p; if (!q) return; if (!q->left) *p = q->right; else if (!q->right) *p = q->left; else { tnode **r = &q->right; while ((*r)->left) r = EXP14; q->data = (*r)->data; q = *r; *r = q->right; } delete q; } ``` | 陳述式 | 答案 | | ------- | ------------------ | | `EXP12` | `p = &(*p)->left` | | `EXP13` | `p = &(*p)->right` | | `EXP14` | `&(*r)->left` | ### 測驗 `9` #### 測驗 `9` 填空 ```c /* maximum alignment needed for any type on this platform, rounded up to a power of two */ #define MAX_ALIGNMENT 16 /* Given a size, round up to the next multiple of sizeof(void *) */ #define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ (((x) + MAX_ALIGNMENT - MMM) & ~(NNN)) ``` | 陳述式 | 答案 | | ------ | ------------------- | | `MMM` | `1` | | `NNN` | `MAX_ALIGNMENT - 1` | ### 測驗 `10` #### 測驗 `10` 填空 ```c #define DIVIDE_ROUND_CLOSEST(x, divisor) \ ({ \ typeof(x) __x = x; \ typeof(divisor) __d = divisor; \ (((typeof(x)) -1) > 0 || ((typeof(divisor)) -1) > 0 || \ (((__x) > 0) == ((__d) > 0))) \ ? ((RRR) / (__d)) \ : ((SSS) / (__d)); \ }) ``` | 陳述式 | 答案 | | ------ | ---------------------- | | `RRR` | `(__x) + ((__d) >> 1)` | | `SSS` | `(__x) - ((__d) >> 1)` | <!-- (__x) + (__d) --> ### 測驗 `11` #### 測驗 `11` 填空 ```c static inline unsigned long fls(unsigned long word) { int num = 64 - 1; if (!(word & (~0ul << 32))) { num -= 32; word <<= 32; } if (!(word & (~0ul << (64 - 16)))) { num -= 16; word <<= 16; } if (!(word & (~0ul << (64 - 8)))) { num -= 8; word <<= 8; } if (!(word & (~0ul << (64 - 4)))) { num -= 4; word <<= 4; } if (!(word & (~0ul << (64 - 2)))) { num -= 2; word <<= 2; } if (!(word & (~0ul << (64 - 1)))) num -= 1; return num; } unsigned long i_sqrt(unsigned long x) { unsigned long b, m, y = 0; if (x <= 1) return x; m = 1UL << (fls(x) & ~1UL); while (m) { b = y + m; XXX; if (x >= b) { YYY; y += m; } ZZZ; } return y; } ``` | 陳述式 | 答案 | | ------ | --------- | | `XXX` | `y >>= 1` | | `YYY` | `x -= b` | | `ZZZ` | `m >>= 2` |