TOC
Open TOC
Data Lab
在 CSAPP Lab 下载对应的 tar
包并解压。
环境配置:
README 文件解读:
- 在
bits.c
中进行实验
- 通过
dlc
检查 bits.c
是否符合编码规则
- 通过
make btest
编译 bits.c
,第一次会生成 btest
文件
- 通过
btest
检查代码正确性,btest
不会检查代码是否符合编码规则
a
的作用是判断 x+1
和 ~x
是否相等,b
的作用是排除特例 -1
别想太多,每一次测试 8
位即可,注意 0x2a8=4*0xaa
,且正好用了 12
个运算符……
注:上面的写法使用了常数 0x2a8
,不符合编码规范,且相加操作也许会有问题,所以可以像下面逐步构造 mask
,最后一步到位
正好用了 15
个运算符……
a
判断从低到高的第 5
位是否为 3
,b
判断更高位是否都是 0
,c
取从低到高的第 4
位,d
取从低到高的第 2
位和第 3
位,若 c
为 1
,则 d
必须为 0
,若 c
为 0
,则 d
无所谓,总之 c
和 d
不能同时为 1
。
后来感觉想复杂了,只要这样:
通过双重 !!
归一化,若 cond
为 1
,则 mask
为全 1
,否则为全 0
,由此实现选择
需要注意 x
和 y
异号的情形,此时 y-x
会溢出,所以需要单独讨论这两种情形,另外 min
取反加一还是自身,也需要单独讨论,对于 x
与 y
相等的情形也(许)要单独讨论
最后汇总时,将结果为 1
的情形相或,并与上结果为 0
的情形的非
这题一直想不出来 🤣,解释一下,将自身与自身取负相或(怎么想出来的 😒),除了 0
之外,所有的结果的最高位都是 1
,算术右移后,0
对应 0
,其余对应 0xffffffff
,加 1
就可以实现了
这一题就比较唬人了 🤣,竟然给了 90
个操作符,首先我们分析一下样例,对于正数而言,从最高位往低位数,碰到 1
停止,对于负数而言,从最高位往低位数,碰到 0
停止。为了统一这两种情况,我们根据符号位将负数取反,正数则保持不变。
接下来的部分就比较魔幻了 🤣,显然我们不能一位一位的判断,因此我们使用二分的思想。先判断高 16
位中是否有 1
,并使用局部变量(编码规则要求所有的变量在最开始声明)记录下来,若有 1
,我们将数右移 16
位;否则高 16
位都是 0
,只需判断低 16
位即可(保持不变)。如此进行,最后将记录的局部变量附上一定的权重,因为符号位总是 0
,所以最后要加 1
(考虑 howManyBits(0) = 1
)。
终于到了浮点数的部分,我们能够使用的操作变多了 🤣,比如任意大小的常数,==
,if
语句等。
这题考察对浮点数表示的理解,注意到这里是 32
位浮点数,所以符号为 1
位,阶码为 8
位,尾数为 23
位。先根据阶码判断是否为无穷大或者 NaN
,这种情形直接返回。若是规格化的值,我们将阶码加一即可(此处可能会溢出,不过题目中并没有特殊的要求)。若是非规格化的值,我们需要根据尾数的最高位分类讨论,若尾数的最高位为 0
,则将尾数部分左移一位即可;否则,该浮点表示从非规格化表示变为了规格化表示。尾数部分应该乘二减一,阶码部分加一,整体考虑就相当于将尾数部分左移一位(使阶码部分的最低位变为 1
)。
首先,浮点数转补码,向零舍入。其次,需要对阶码进行精细的讨论:
- 阶码全为
1
:无穷大或者 NaN
- 阶码
≤ 126
:若为非规格化,显然舍入为 0
,若为规格化,尾数 ∈[1,2)
,所以只要 E<=-1
,即阶码 ≤ 126
,就会舍入为 0
- 阶码
≥ 158
:此时 E ≥ 31
,对于正数而言,结果必定 ≥ 2^31
,显然溢出,对于负数而言,会包含 -2^31
,然而 -2^31
的表示就是 1<<31
,所以不需要单独讨论
- 其余情形:将尾数提取出来并或上
1
,记为 1+f
,不考虑符号,最终结果为 (1+f)*2^E/2^23
,由于直接计算会溢出,将 E
和 23
的先抵消一部分,也就是计算 (1+f)*2^(E-23)
,最后根据符号位进行取反加一处理
最后一题还挺简单,只要知道单精度浮点数表示的范围 ∈[2^(-23)*2^(-126),(2-2^(-23))*2^127]
即可