# 2023q1 Homework3 (quiz3)
contributed by < `csm1735` >
## 測驗 `1`
---
## 測驗 `2`
---
## 測驗 `3`
### LFSR 的運作原理及案例
Linear feedback shift register (LFSR) 是指給定前一狀態,將該輸出的線性函數作為輸入的移位暫存器
```c
static void lfsr(uint64_t *up)
{
uint64_t new_bit =
((*up) ^ ((*up) >> 3) ^ ((*up) >> 30) ^ ((*up) >> 55)) & 1u;
/* don't have to map '+1' in polynomial */
*up = ((*up) >> 1) | (new_bit << 63);
/* shift *up by 1 to RIGHT and insert new_bit at "empty" position */
}
```
計算出 `new_bit` 後將 `up` 右移 1 位,再將 `new_bit`補到最高位。
```shell
$ git log --grep lfsr
```
透過該指令可以去搜尋包含關鍵字 `lfsr` 的 commit message
可以發現在此次 [commit](https://github.com/torvalds/linux/commit/dec0fb3946c478e7bb6165a1b7a03092ceefd419) 提及到了 `lfsr` ,而其所提到的 `jent_lfsr_time` 函式可以在 [linux/crypto/jitterentropy.c](https://github.com/torvalds/linux/blob/master/crypto/jitterentropy.c) 中發現
### 解釋程式碼原理
`log2_64` 功能為計算以 2 為底的 `x` 的對數,且下取至整數 (即 `floor` ),從程式碼可看到不斷的透過右移與 `if` 來判斷 `x` 的對數值會落在哪個區間,再以該區間的最小對數值為基底,去加上該部份透過 `log_table_256` 所換算出來的對數值。
```c
static const char log_table_256[256] = {
#define _(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3,
3, 3, 3, 3, 3, _(4), _(5), _(5), _(6), _(6), _(6),
_(6), _(7), _(7), _(7), _(7), _(7), _(7), _(7), _(7),
#undef _
};
```
這邊解釋一下 `log_table_256` 的作法,一開始看到時並沒有看懂,仔細看看後發現有跡可循,才理解是透過 macro 將 `_(n)` 定義成以逗號隔開的 16 個 n 值,因為像是對數值為 4 的為 16 ~ 31 共 16 個值,對數值為 5 的為 32 ~ 63 共 32 個值,而透過這種作法,我們只需要寫 `_(4), _(5), _(5)` 即可,能夠達到程式碼更精簡的效果。
```c
unsigned int bucket_number(uint64_t x)
{
uint64_t mask111 = (1 << (N_BITS + 1)) - 1;
uint64_t mask011 = (1 << (N_BITS)) - 1; /* one 1 less */
unsigned char leq = ((x & mask111) < N_BUCKETS);
/* leq (less or equal) is 0 or 1. */
return (leq * (x & mask111)) +
((1 - leq) * ((x >> (N_BITS + 1)) & mask011));
/* 'x >> (N_BITS + 1)' : take different set of bits -> better uniformity.
* '... & mask011' guarantees that the result is less or equal N_BUCKETS.
*/
}
```
而此處透過 mask 的作法,可以保證結果可以小於 `N_BUCKETS` ,如果與 `mask111` 做 & 後的結果不小於 `N_BUCKETS` ,則改使用 `mask011` 。
---
## 測驗 `4`
### 解釋程式碼原理
`ceil_log2` 功能為計算以 2 為底的 `x` 的對數,且上取至整數 (即 `ceil` )
```c
int ceil_log2(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 >> 1) + 1;
}
```
原理是每次去檢查 `x` 是否大於特定的 2 的冪次,如果有的話則透過左移去對特定的 bit 做 set ,並將 `x` 做右移去繼續檢查,而我們可以看出最後沒有繼續去對 `x > 1` 的狀況去檢查,因此推斷剩餘的程式碼為:
```c
r |= shift;
shift = (x > 0x1) << 0;
x >>= shift;
r |= shift;
```
考量到 `KKKK` 的格式,可以將此段改寫為 `r | shift | x >> 1`