contributed by <raygoah
>
考慮以下整數乘法的實作程式碼:
for
迴圈中,每次都將 m / 2 ,同時將 c 的值加一,可以聯想到 n << 1
代表把 n 乘 2 乘一次,因此若寫成 n << c
,及代表要將 n 乘 2 乘 c 次for
迴圈中的 if
,猜測本題重點便是在於為什麼達成 if
的條件後要進行 OP ,這背後代表的意思,就是完成這題乘法的關鍵if (!(m % 2 - 1)) OP
中可以知道,只有在 m 為奇數時,OP 才會執行,而這代表著只有在 m 一開始就是奇數,第一次進迴圈的時候 OP 會被執行,此外還有在跳出迴圈前一次,m = 1 時,OP 會被執行for
迴圈中,if
的條件式會成立,OP 會執行的這一點,即可以順利的將 m 表示成 <<
的特性,每向左移一位元代表乘以二,以及結合上述的想法,便可以選出正確答案:OP 為 (e)
ret += n << c;<<
,寫成如題目的程式碼,順利的完成可運作的乘法程式rwe0214
在課堂上的講解照著題目順序從 A0 看到 A6,雖然每一題的選項都很多,但只要知道 IEEE 754 的規則,要選出正確答案不難
A0:
A1:
frac += addition;
的部份是用於做捨入的,採用 round to even 的方法,捨入的方法在 code 中的註解有詳細的介紹A2 A3 A4:
rest += addition;
的部份,同樣的也是做捨入exp = rest >> A3 & A4;
這裡,要從 rest 中把第 23 到第 31 bit 的數字取出,也就是只要留下 exp 的部份,因此需要先向右移位 23 次,再和 0x7FFFFFFF 做一次遮罩,便可以得到,因此 A3 為 23,而 A4 則是選擇 0x7FFFFFFF這邊不理解的一點是,對於 exp 為何不直接將其設為 0
因為在乘完 0.5 後,得到的答案會是非規格化的數字,而在 IEEE 754 中,只要是非規格化的數字,exp 都會是 0,那麼為何要選擇用 bitwise 的方式而非將 exp 直接設為 0 呢?
有猜測和質疑很好,那去寫程式驗證吧!
A5
A6
考慮到下方函式 shift_right_arith
和 shift_right_logical
分別表示算術右移和邏輯右移,請嘗試補完程式碼。可由 sizeof(int) * 8
得知整數型態 int
的位元數 w
,而移位量 k
的有效範圍在 0 到 w - 1
。
sizeof(int) * 8
得知整數型態 int
的位元數 w
k
的有效範圍在 0 到 w - 1
首先先由算術右移的部份下手:
int xsrl = (unsigned) x >> k;
首先將 x 右移 K 位int w = sizeof(int) << P1;
這邊可由提示中提到,由 sizeof(int) * 8
得知整數型態 int
的位元數 w
,因此要乘上 8 就等同於向左移位 3 次,因此 P1 為 3int mask = (int) -1 << (P2);
在這裡 mask 為了要讓原本是小於 0 的數,在經過算術右移後得到的結果仍舊是負數,因此之後要對從右邊數來 k 個 bits 做遮罩,所以在這邊要將 -1 向左移 (w-k) 次,因此 P2 選擇 w-k
|
接著是邏輯右移的部份
P4 的地方和 P1 一樣,sizeof(int) * 8
得知整數型態 int
的位元數 w
,因此 P4 為 3
P5 也是和 P2 的概念一樣,只是之後遮罩的作法不同,但這邊也是為了讓 mask 從右數來 k 個 bits 皆為 1 其他位元皆為 0,因此在這裡 P5 也是選擇 w-k
P6 P7 的部份是邏輯右移與算術右移最重要的區別,在邏輯右移中要讓右移後從左邊補上的 bits 全部為 0 ,因此要先將 mask 做一次邏輯運算的 not
,讓 mask 從原本的右邊數來 k 個 bits 皆為 1 其他位元皆為 0 ,變成從右數來 k 個 bits 皆為 0 其他位元皆為 1,接著和 xsrl 做 & ,確認右邊數來 k 個 bits 全部為 0 ,而左邊數來 k 個 bits 留下移位後要的數字,得到最後的結果,因此 P6 為 &
而 P7 為 ~mask
shr src, dest
將 dest 向左移位 src 個 bitssar src, dest
將 dest 向右移位 src 個 bits,並依照原本的 sign bit 是多少,把空缺位都補上一樣的 0 或 1