# 2020q3 Homework5 (quiz5) [toc] ## 測驗 1 ```c= #include <stdio.h> #include <stdlib.h> double divop(double orig, int slots) { if (slots == 1 || orig == 0) return orig; ``` 除數為 1 或被除數為 0 直接回傳被除數 ```c=7 int od = slots & 1; double result = divop(orig / 2, od ? (slots + 1) >> 1 : slots >> 1); ``` 除數為偶數則兩者一起除 2 ,為奇數則加 1 後除 2,之後再將加一導致變小的商補回 ```c=9 if (od) result += divop(result, slots); ``` $$ \begin{align} \frac{orig}{slots} =& \frac{orig}{slots+1}\frac{slots+1}{slots} \\ =& \frac{orig}{slots+1}(1+\frac{1}{slots}) \\ =& \frac{orig}{slots+1}+\frac{orig}{slots+1} \times \frac{1}{slots} \\ \end{align} $$ 也就是要加上再除以 slots 的 result ```c=11 return result; } ``` ## 測驗 2 ```c= #include <stdint.h> /* A union allowing us to convert between a float and a 32-bit integers.*/ typedef union { float value; uint32_t v_int; } ieee_float_shape_type; ``` typedef union 方便我們可以在同一塊記憶體空間使用不同讀取方式,本題用來 f32 與 int 的轉換 ```c=8 /* Set a float from a 32 bit int. */ #define INSERT_WORDS(d, ix0) \ do { \ ieee_float_shape_type iw_u; \ iw_u.v_int = (ix0); \ (d) = iw_u.value; \ } while (0) /* Get a 32 bit int from a float. */ #define EXTRACT_WORDS(ix0, d) \ do { \ ieee_float_shape_type ew_u; \ ew_u.value = (d); \ (ix0) = ew_u.v_int; \ } while (0) static const float one = 1.0, tiny = 1.0e-30; float ieee754_sqrt(float x) { float z; int32_t sign = 0x80000000; uint32_t r; int32_t ix0, s0, q, m, t, i; EXTRACT_WORDS(ix0, x); /* take care of zero */ if (ix0 <= 0) { if ((ix0 & (~sign)) == 0) return x; /* sqrt(+-0) = +-0 */ if (ix0 < 0) return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } ``` 上面的 if 應該可以用 ix0 == 0 下面的 if 應該回傳 0 / 0 即可 ```c=42 /* take care of +INF and NaN */ if ((ix0 & 0x7f800000) == 0x7f800000) { /* sqrt(NaN) = NaN, sqrt(+INF) = +INF,*/ return x; } /* normalize x */ m = (ix0 >> 23); if (m == 0) { /* subnormal x */ for (i = 0; (ix0 & 0x00800000) == 0; i++) ix0 <<= 1; m -= i - 1; } ``` shift right 23 是為了將 23 個 fraction bits 去除,因為負數前面已經處理完了,這邊不需考慮 sign bit 以 signed int32 m 紀錄 exponent m 等於 0 表示為 denormal ,處理方式為強制轉為 normal 並以 m 紀錄轉換後的 exponent ,為負數 ```c=54 m -= 127; /* unbias exponent */ ix0 = (ix0 & 0x007fffff) | 0x00800000; if (m & 1) { /* odd m, double x to make it even */ ix0 += ix0; } m >>= 1; /* m = [m/2] */ ``` 將 m 扣除 bias 呈現出真實的 exponent 讓 ix0 只保留 fraction 並在 fraction 左側補上 1 代表 normalized number 預設小數點前一位的 1 將 m 除以 2 就可達到開根號,但要避免 m 為奇數的情況,對於奇數的 m ,將 ix0 乘二,如次一來當 m >> 1 時,不用擔心奇數 m 會損失 LSB 的 1 ```c=60 /* generate sqrt(x) bit by bit */ ix0 += ix0; q = s0 = 0; /* [q] = sqrt(x) */ r = QQ0; /* r = moving bit from right to left */ while (r != 0) { t = s0 + r; if (t <= ix0) { s0 = t + r; ix0 -= t; q += r; } ix0 += ix0; r >>= 1; } /* use floating add to find out rounding direction */ if (ix0 != 0) { z = one - tiny; /* trigger inexact flag */ if (z >= one) { z = one + tiny; if (z > one) q += 2; else q += (q & 1); } } ix0 = (q >> 1) + QQ1; ix0 += (m << QQ2); INSERT_WORDS(z, ix0); return z; } ```