bauuuu1021
,BroLeaf
contributed by <BroLeaf
,bauuuu1021
>
2018q1 第 2 週測驗題
一
請完成下方程式碼,依循 IEEE 754 單精度規範,輸出 的浮點數表達法,而且考慮兩種狀況:
注意:這裡假設 u2f
函式返回的浮點數值與其無號數輸入有著相同的位數,也就是至少 32-bit
求 Y0 ~ Y7 使上面程式碼可以正常運作
搭配 CS:APP 3/e 80頁 圖 2-35
來觀看,以單精度浮點數 32-bit 來看
情況 | signed bit | exponent | mantissa |
---|---|---|---|
無限大 | X | 11111111 | 0000…00 |
NaN | X | 11111111 | XXXX…XX |
denormalized | X | 00000000 | XXXX…XX |
最小(負的) | 1 | 00000000 | 0000…01 |
1 | 00000000 | 1111…11 | |
-0.0 | 1 | 00000000 | 0000…00 |
+0.0 | 0 | 00000000 | 0000…00 |
0 | 00000000 | 0000…01 | |
最大(正的) | 0 | 00000000 | 1111…11 |
normalized | X | XXXXXXXX 0 , 255 | XXXX…XX |
最小(負的) | 1 | 11111110 | 1111…11 |
最大(正的) | 0 | 11111110 | 1111…11 |
有了上面表格的基本認識,接下來就可以分析程式碼了 |
frac = 1 << (unsigned) (x - (2 - pow(2, Y3) - Y4));
Reference:
延伸題: 給定一個單精度的浮點數值,輸出較大且最接近的 值,需要充分考慮到邊界
BroLeaf
二
根據 IEEE754 對 float 的規範
A0 = ?
根據 IEEE754 定義,當 exp 為 0xFF 時為 NaN 或 INF;A0 = 0xFF
A1 = ?
f 為 Denormalized 時 exp 為 0,與數值大小有關的剩下 frac 。 因此將 frac 往右一位即可將數值 ,A1 = 1
A2 = ? A3 = ? A4 = ?
因為 exp 只有 1,而 exp 直接與 frac 相連,因此 rest >>= A2;
可以直接視為 denormalized 的情況做運算。A2=1
在 exp 為 1 的狀況下 *0.5 後一定是 denormalized ,也就是 exp = 0 。因此先將 rest 右移到使 exp 在最低位,再用一個 mask 讓 exp 只有 8 位。A3=23 A4=0xFF
A5 = ?
f 為 Normalized 時透過 exp-1 即可將數值 ,A5 = 1
A6 = ?
將數值的每個部分透過 |
連結起來, sig 在最高位元,A6=31
Reference:
bauuuu1021
三
考慮到某些實數的二進位表示形式如同 這樣的無限循環小數,其中 是個 位的二進位序列,例如 的二進位表示為 (y = 01
),而 的二進位表示為 (y = 0011
),考慮到以下 y 值,求出對應的十進位分數值。
010011
=> 101
=> 0110
=> X1 = ?
X2 = ?
X3 = ?
Reference:
(c)63
。(f)7
。(g)5
。接著你可以繼續思考:「如何一般化 (generalize) 呢?」
給定的分數 (即 N/M 形式,當 N 和 M 都是正整數),如何轉換成二進位,而且在表達 bit 數量限制的狀況,轉換的誤差是多少?(對比看 CS:APP 提及的愛國者導彈的誤差議題)
一般化
Current | >1? | 小數點 | Next |
---|---|---|---|
T | 1 | ||
F | 0 | ||
T | 1 | ||
T | 1 | ||
F | 0 | ||
T | 1 |
bit 數量限制
限制位數 | 轉分數 | 誤差 |
---|---|---|
3 | 5.208% | |
6 | 0.651% | |
9 | 0.081% | |
12 | 0.071% | |
… | … | … |
24 | 0.00000248% |
從上表不難發現,這種數值轉換的誤差值較高,實務上如何縮減呢?
四
在 你所不知道的C語言: 遞迴呼叫篇 提到以下程式碼:
預期會得到以下輸出:
(A && B && C) || D
次數 | 1 | 2 | 3 | ~ | 9 | 10 | 9 | ~ | 2 | 1 |
---|---|---|---|---|---|---|---|---|---|---|
i | 1 | 2 | 3 | ~ | 9 | 10 | 9 | ~ | 2 | 1 |
N | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |
1 | 2 | 3 | ~ | 9 | 10 | 9 | ~ | 2 | 1 |
(i < N && printf("%d\n", i) && !p(i + 1, N))
的結果一直都是 False ,所以遞迴回傳到前面時會跑到第 4 行的 printf ,再印一次當前的 i注意 10
只會出現一次。請填補下方程式碼,使得輸出為 1 -> 2 -> 3 -> 4 -> 5 ->
,並且包含換行符號 (\n
)
提示: Q1 是函式名稱,可能包含 ~
(bitwise NOT) 操作,Q2 和 Q3 是有號整數
return p(1, 10)
一定要是 true次數 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
i | 1 | 2 | 3 | 4 | 5 | 6 |
N | 10 | 9 | 8 | 7 | 6 | 5 |
1 | 2 | 3 | 4 | 5 |
為了得到使回傳值回傳相反的結果而使用 ~ (bitwise NOT),我認為並不恰當。
根據本題回傳值有可能是 int ,例如:000111 (true),在使用 ~ 後,會變成111000,結果還是 true,只有在回傳 false 也就是 0 的時候用 ~ 才會得到相反的結果,有可能造成邏輯上的 bug 。
直接改用 ! Logical negation (NOT),可以得到相同 output ,也比較恰當。
BroLeaf