# 2019q1 第 2 週測驗題
:::info
目的: 檢驗學員對 [bitwise operator](https://hackmd.io/s/By0MltO_m) 及 C 程式設計的認知
:::
---
### 測驗 `1`
考慮以下程式碼,回傳給定整數乘上 `3.5` 的結果:
```clike
int mul3_5(int x) {
return (((8 A x) B x ) C 1);
}
```
請補完。A, B, C 都是 operator。
==作答區==
A = ?
* `(a)` +
* `(b)` -
* `(c)` *
* `(d)` /
* `(e)` <<
* `(f)` >>
* `(g)` |
* `(h)` &
* `(i)` ^
B = ?
* `(a)` +
* `(b)` -
* `(c)` *
* `(d)` /
* `(e)` <<
* `(f)` >>
* `(g)` |
* `(h)` &
* `(i)` ^
C = ?
* `(a)` +
* `(b)` -
* `(c)` *
* `(d)` /
* `(e)` <<
* `(f)` >>
* `(g)` |
* `(h)` &
* `(i)` ^
:::success
延伸題目:
1. 早期的 C 語言做數值運算時,會將 `int` 轉型為 `double` (`float` 型態是 ANSI 標準化時才納入),待運算完畢後,再轉型回 `int`。本例來說,原本 `* 3.5` 的操作就意味著要先將 `int` 轉型為 `float`/`double` 並在運算後再去轉型,涉及較多的指令週期,但適當調整後,則可避免轉型到浮點數再轉回的成本。研讀相關文獻,找出類似的最佳化技巧;
2. 編譯器將原始程式碼解析為 abstract syntax tree (AST) 後,是如何處理上述語意分析呢?請用 gcc/clang 舉例說明;
:::
---
### 測驗 `2`
[population count](https://en.wikichip.org/wiki/population_count) 簡稱 popcount 或叫 sideways sum,是計算數值的二進位表示中,有多少位元是 `1`,在一些場合下很有用,例如計算 0-1 稀疏矩陣 (sparse matrix)或 bit array 中非 `0` 元素個數、計算兩個字串的 [Hamming distance](https://en.wikipedia.org/wiki/Hamming_weight)。Intel 在 2008 年 11 月 Nehalem 架構的處理器 Core i7 引入 SSE4.2 指令集,其中就有 `CRC32` 和 `POPCNT` 指令,`POPCNT` 可處理 16-bit, 32-bit, 64-bit 整數。
對應到 C 程式的實作:
```clike
unsigned popcnt_naive(unsigned v) {
unsigned n = 0;
while (v)
v &= (v - 1), n = -(~n);
return n;
}
```
可改寫為以下常數時間的實作:
```clike
unsigned popcnt(unsigned v)
{
unsigned n;
n = (v >> 1) & 0x77777777;
v -= n;
n = (n >> 1) & 0x77777777;
v -= n;
n = (n >> 1) & 0x77777777;
v -= n;
v = (v + (v >> X)) & Y;
v *= 0x01010101;
return v >> 24;
}
```
請補完。
==作答區==
X = ?
* `(a)` 0
* `(b)` 1
* `(c)` 2
* `(d)` 3
* `(e)` 4
* `(f)` 5
* `(g)` 6
* `(h)` 7
Y = ?
* `(a)` 0x55555555
* `(b)` 0x33333333
* `(c)` 0x0F0F0F0F
* `(d)` 0x00FF00FF
* `(e)` 0x0000FFFF
* `(f)` 0x0F0F0F0F
:::success
延伸題目: 解釋原理並找出可抵抗 [timing attack](https://en.wikipedia.org/wiki/Timing_attack) 的相關程式和場景
:::
---
### 測驗 `3`
考慮以下程式碼:
```clike
#include <stdio.h>
#define cons(x, y) E
struct llist { int val; struct llist *next; };
int main() {
struct llist *list = cons(9, cons(5, cons(4, cons(7, NULL))));
struct llist *p = list;
for (; p; p = p->next)
printf("%d", p->val);
printf("\n");
return 0; }
```
預期執行時期輸出 `9547`,補完 `E`。
E = ?
* `(a)` {x, y}
* `(b)` {{x, y}}
* `(c)` {.val = x, .next = y}
* `(d)` (struct llist[]){.val = x, .next = y}
* `(e)` (struct llist[]){{x, y}}
:::success
延伸題目: 參照 C 語言規格,解釋原理並找出 Linux 核心內部相似的程式碼
:::