# 2019-06-03 張景雲
:::warning
:notes: 待做事項
1. 完整回覆題目並解釋
2. 列出實驗過程和參考資料
:::
## Q1: 實作將給定的==地址==做 align to 4-bytes 的 macro
Hint: Linux 核心有類似的程式碼
=>
```cpp
#include <stdint.h>
#define ALIGN_TO_4BTYTE(x) (((uint_32t)(x)) + 0x03) & ~0x03
```
假設有一個數字他必須要是對齊4-byte,代表說這個數值必須要可以被4整除,那什麼情況下可以被4整除? 要在`x & 0x03 == 0` 才會正確。因此我若想要做一個4-byte的對齊器,我就必須要在最後使用 bitmask(`11...11111100 == ~0x03`) 把最後兩位給消除掉。
在這邊 `(uint_32t)(x)) + 0x03` 的意義是要強迫進位到 > 4的位數
有一種例外情況,當 `x > 0xfffe` `x + 0x03` 會 overflow 導致結果不正確
### 推廣
假設我要做 n-btye 的對齊器 `n = 1 2 4 8 16 ...`
```cpp
#include <stdint.h>
#define ALIGN_TO_NBTYTE(x,n) (((uint_32t)(x)) + (n-1)) & ~(n-1)
```
參考自 : [jserv note](https://hackmd.io/s/SyrZMGYr4)
---
## Q2: 假設一個 circular buffer 的容量為 `n = 1024`,用 bitwise 改寫原本 `x = (x + 1) % n` 的操作,使其達到更好的效能
Hint: 1024 is power of 2
=>
因為對於 2 的倍數 mod 其實只要對它做 (2^n-1) 即可達到一模一樣的效果。
```cpp
x = (x+1) & (1024 - 1)
```
---
## Q3: Linux 的 linked list 對於 insertion/deletion 為何可做到 branchless?
因為在linux中,他是環狀的linked list,插頭不用說,已經有 head 資訊了,因此如果我想要差尾,其實我都頂多只需要往前走一格就是尾巴了。
```cpp
head->next->prev = new;
new->next = head->next;
new->prev = head;
head->next = new;
```
## Q4: 以 Linux 的 linked list,實作「找到第 k 大的節點」
減少記憶體的操作數量
=>
最一開始給的solution
```cpp
struct Mylist{
int val;
list_head* head;
}
...
// [5,7,1,3,4]
int top_k(struct Mylist* mylist,int k){
if(!mylist) return NULL;
int queue[k];
int index = 0;
struct Mylist* pos;
list_for_each_entry(pos,mylist->head,head){
int temp = pos->val;
if(index < k){
queue[index] = temp;
index++;
}
else{
for(int i=0;i<k;i++){
if(temp >= queue[i]){
queue[i] = temp;
break;
}
}
}
}
if(index < k-1) return NULL;
int topk = INT_MAX;
for(int i=0;i<k;i++){
if(queue[i] <= topk) topk = queue[i];
}
return topk;
}
```
> 會有問題,因為 `queue[k]` 這東西很危險,你根本不知道 k 能夠多大,假設大到一個程度,程式就會 stack overflow,在加上這樣的資料結構設計,沒辦法重複利用,每次都要重算。可以利用 linked list 特性修正成更好的版本。