CASPP 第二章课后习题解答
2021年11月更新
一些很好的docker笔记Docker-从入门到入土
发现之前的docker已经不能使用了,同时使用了ubuntu20.04镜像的话会出现问题,于是修改了镜像的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive
RUN sed -i '/security/d' /etc/apt/sources.list
RUN sed -i s@/archive.ubuntu.com/@/mirrors.tencent.com/@g /etc/apt/sources.list
RUN apt-get clean && apt-get update --fix-missing && apt-get upgrade \
&& apt-get install -y build-essential curl wget vim net-tools bzip2 git openssh-server
RUN apt-get install -y gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu
RUN mkdir /var/run/sshd
RUN echo 'root:mypassword' | chpasswd
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
docker run -d -P --name ubuntu20.04 ubuntu20.04
docker inspect xxx
ssh root@localhost -p xxx
|
准备
在实现CSAPP的习题之前,首先需要配置环境。去买一个机器明显不现实,于是我们可以使用docker来搭建我们的学习环境,而且docker非常轻量级,有各种各样的环境可以配置。在接下来的工作中,我们使用vscode+docker进行。推荐七牛云docker镜像
- docker ubuntu16.04
- vscode + ssh插件
附带几个常见命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
docker run -it -p 8022:22 --ipc=host --name=ubuntu:16.04 ubuntu /bin/bash
# 使用清华源
apt update
apt install -y openssh-server
mkdir /var/run/sshd
echo 'root:password' | chpasswd
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
echo "export VISIBLE=now" >> /etc/profile
service ssh restart
ssh root@localhost -p 8022
docker ps -a
docker commit 容器id csapp
|
到这里就可以开启vscode进行远程连接docker容器,从而进行代码的编写(记得安装gcc)。
使用Docker File进行构建Docker镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
# 基础镜像
FROM nvidia/cuda:9.0-cudnn7-runtime-ubuntu16.04
# 指定devnet的网络代理才可以访问外网
ENV http_proxy 'http://devnet-proxy.oa.com:8080/'
ENV https_proxy 'http://devnet-proxy.oa.com:8080/'
# 加速ubuntu的软件下载速度
RUN echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/source.list \
&& echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/source.list \
&& echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/source.list \
&& echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/source.list
RUN apt-get update --fix-missing && apt-get install -y curl wget vim net-tools bzip2 git\
&& rm -rf /var/lib/apt/lists/* && mkdir -p /software
WORKDIR /software
RUN wget --quiet https://repo.anaconda.com/archive/Anaconda3-4.2.0-Linux-x86_64.sh -O ~/anaconda.sh && \
/bin/bash ~/anaconda.sh -b -p /software/conda && \
rm ~/anaconda.sh && \
# ln -s /software/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \
echo "export PATH=/software/conda/bin:$PATH" >> ~/.bashrc
# && \
# echo "conda activate base" >> ~/.bashrc
# RUN /software/conda/bin/conda create -n python3.5 python=3.5 pytorch torchvision -c pytorch\
# && apt clean \
# && apt autoremove -y
RUN /software/conda/bin/pip install PyHamcrest \
&& /software/conda/bin/pip install --upgrade pip \
&& /software/conda/bin/pip install msgpack \
&& /software/conda/bin/pip3 install torch torchvision \
# && /software/conda/bin/conda install pytorch torchvision -c pytorch \
&& /software/conda/bin/pip install opencv-python \
&& apt clean \
&& apt autoremove -y
CMD [ "/bin/bash" ]
|
2.55
在你能够访问的不同机器上,使用show_bytes.c
来编译并运行示例代码,并确定这些机器的字节顺序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]); //line:data:show_bytes_printf
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}
void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}
|
解答: 略。
2.56
试着用不同的示例值来运行show_bytes.c
的代码
解答: 略。
2.57
编写程序show_short
,show_long
,show_double
,分别打印为short、long以及double的C语言对象的字节表示。
1
2
3
4
5
6
7
8
9
|
void show_short(short x) {
show_bytes((byte_pointer) &x, sizeof(short)); //line:data:show_bytes_amp1
}
void show_long(long x) {
show_bytes((byte_pointer) &x, sizeof(long)); //line:data:show_bytes_amp1
}
void show_double(double x) {
show_bytes((byte_pointer) &x, sizeof(double));
}
|
2.58
编写过程is-little_endian
当在小端机器上运行的时候是1,在大端机器上运行是0.
最低有效字节放在前面为小端
1
2
3
4
|
int is_little_end() {
int x = 0x01;
return *((byte_pointer)&x) == 0x01;
}
|
2.59
编写一个C表达式,它生成一个字,由x的最低有效字节和y中剩下的字节组成,对于运算数x=0x89ABCDEF和y=0x765432,就得到0x765432EF.
1
2
3
4
5
|
int fun(int x,int y){
x = x & 0xff;
y = y & (~0xff);
return x | y;
}
|
2.60
假设我们将一个w位的字中从0(最低位)到最高位编号,写出下面的函数,会将指定的字节i换成字节b。
replace(0x12345678, 2, 0xAB) –> 0x12AB5678
replace(0X12345678, 0, 0XAB) –> 0x123456AB
1
2
3
4
5
|
int replace_byte(int x, int i, int v){
int mask = 0xff<<(i<<3);
v = v << (i<<3);
return (x & ~mask) | v;
}
|
2.61
写一个C表达式,在下列描述的条件下产生1,而在其他情况下得到0,假设x是int类型。
- x的任何位都等于1。
!~x
- x的任何位都等于0。
!x
- x的最低有效字节中的位都等于1。
!~(x | ~0xff)
(最低有效字节就是低8位)
- x的最高有效字节中的位都等于0。
!(x>>((sizeof(int)-1)<<3) &0xff)
2.62
编写一个函数int_shifts_are_arithmetic(),在对int类型的数使用算数右移的机器上运行这个函数生成1,而在其他情况生成0。注意这样的事实,-1表达为全1,如果是算数右移,那么不管怎么移,都是-1。
1
2
3
4
5
6
|
int int_shifts_are_arithmetic()
{
int num = -1;
return !(num ^ (num >> 1));
}
|
2.63
将下面的C函数补充完成。函数srl用算数右移(由值xsra给出)来完成逻辑右移。函数sra用逻辑右移(由值xsrl给出)来完成算数右移。可以通过计算8*sizeof(int)
来确定数据类型int中的位数w。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
unsigned srl(unsigned int x, int k)
{
unsigned xrsa = (int)x >> k;
int w = sizeof(int) << 3;
int mask = (int)-1<<(w-k);
return xrsa & ~mask;
}
int sra(int x, int k) {
int xsrl = (unsigned) x >> k;
int w = sizeof(int) << 3;
int mask = (int) -1 << (w - k);
// 当第一个为1时候,保持mask不变
int m = 1 << (w - 1);
mask &= ! (x & m) - 1;
return xsrl | mask;
}
|
2.64
写出代码实现如下函数
1
2
3
4
|
int any_odd_one(unsigned x)
{
return !!(0xAAAAAAAA & x);
}
|
2.65
写出代码实现函数
使用二分法进行对1的处理
1
2
3
4
5
6
7
8
9
|
int odd_ones(unsigned x)
{
x ^= x>>16;
x ^= x>>8;
x ^= x>>4;
x ^= x>>2;
x ^= x>>1;
return x&0x1;
}
|
2.66
写出代码实现函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
int leftmost_one(unsigned x)
{
/*
* first, generate a mask that all bits after leftmost one are one
* e.g. 0xFF00 -> 0xFFFF, and 0x6000 -> 0x7FFF
* If x = 0, get 0
*/
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return (x>>1) + (x && 1);
}
|
2.67
给你一个任务,编写一个过程int_size_is_32(),当在一个int是32位机器上运行的时候产生1,而在其他情况下产生0。不允许用sizeof运算符。
1
2
3
4
5
6
7
|
int bad_int_size_is_32()
{
int set_msb = 1<<31;
int beyond_msb = 1<<32;
return set_msb && !beyond_msb;
}
|
A. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior it undefined.
B. 修改代码,使得它在至少为32位机器上能够运行
1
2
3
4
5
6
|
int int_size_is_32()
{
int set_msb = 1<<31;
int beyond_msb = set_msb<<1;
return set_msb && !beyond_msb;
}
|
C. 修改代码,使得它在至少为16位机器上能够运行
1
2
3
4
5
6
|
int int_size_is_32()
{
int set_msb = 1 << 15 << 15 << 1;
int beyond_msb = set_msb<<1;
return set_msb && !beyond_msb;
}
|
2.68
写出代码实现函数
1
2
3
4
5
|
int lower_one_mask(int n)
{
int w = sizeof(int) << 3;
return (unsigned)-1 >> (w-n);
}
|
2.69
写出具有如下原型的函数代码
1
2
3
4
5
|
unsigned rotate_left(unsigned x, int n)
{
int w = 32;
return (x<<n) + (x>>(w-n));
}
|
2.70
写出具有如下原型的函数代码
1
2
3
4
5
6
7
8
9
|
int fits_bits(int x, int n)
{
int pos_max = (1<<(n-1)) - 1;
int neg_max = -(1<<(n-1));
printf("%d %d\n", pos_max, neg_max);
return x<=pos_max && x>=neg_max;
}
|
在这里,书上第二章45页说到,当有w位补码(最高位表示为符号位)所能表示的范围是
$$
TMin_w=-2^{w-1},TMax=2^{w-1}-1
$$
2.71
实现一组过程来实现操作一个数据结构,要将4个有符号字节封装成一个32位unsigned。一个字中字节从0编号到3.分配给你的任务是:为一个使用补码运算和算术右移的机器编写下面的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int xbyte(packet_t word, int bytenum) {
/*
* pay attention when byte we want is negetive
*
* Assume sizeof(unsigned) is 4
* first shift left 8 * (4 - 1 - bytenum)
* then arthemetic shift right 8 * (4 - 1) reserve signficant bit
*/
int size = sizeof(unsigned);
int shift_left_val = (size - 1 - bytenum) << 3;
int shift_right_val = (size - 1) << 3;
return (int) word << shift_left_val >> shift_right_val;
}
|
2.72
给你一个任务写出一个函数,将整数val复制到缓冲区buf中,但是只有当缓冲区中有足够的可用空间时,才执行复制。
1
2
3
4
5
6
7
|
void copy_int(int val, void *buf, int maxbytes)
{
/* compare two signed number, avoid someone set maxbytes a negetive value */
if(maxbytes>=(int)sizeof(val)){
memcpy(buf, (void*)&val, sizeof(val));
}
}
|
A. 由于sizeof是size_t类型,那么相减以后仍然是该类型>0永远是存在的,因此使用直接比较的方法更好
1
|
printf("%zu", 0 - sizeof(int)); // 4294967292
|
B. 如上
2.73
写出具有如下原型的函数代码
与传统的溢出相反。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int saturating_add(int x, int y)
{
int sum = x + y;
int sig_mask = INT_MIN;
/* x>0, y>0, sum<0 pos_overflow
* x<0, y<0, sum>0 neg_overflow
*/
int pos_over = !(x & sig_mask) && !(y & sig_mask) && (sum & sig_mask);
int neg_over = (x & sig_mask) && (y & sig_mask) && !(sum & sig_mask);
(pos_over && (sum=INT_MAX)) || (neg_over && (sum=INT_MIN));
return sum;
}
|
2.74
写出具有如下原型的函数代码(如果计算x-y不溢出,这个函数就返回1)
1
2
3
4
5
6
7
8
9
10
|
int tsub_ok(int x, int y)
{
int sub = x - y;
int pos_over = x > 0 && y < 0 && sub < 0;
int neg_over = x < 0 && y > 0 && sub > 0;
int res = !(pos_over || neg_over);
return res;
}
|
2.75
计算x*y的完整2w位表示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
int signed_high_prod(int x, int y) {
int64_t mul = (int64_t) x * y;
return mul >> 32;
}
unsigned unsigned_high_prod(unsigned x, unsigned y) {
int sig_x = x >> 31;
int sig_y = y >> 31;
int signed_prod = signed_high_prod(x, y);
return signed_prod + x * sig_y + y * sig_x;
}
unsigned another_unsigned_high_prod(unsigned x, unsigned y) {
uint64_t mul = (uint64_t) x * y;
return mul >> 32;
}
|
2.76
1
2
3
4
5
6
7
8
9
10
11
|
void *another_calloc(size_t nmemb, size_t size)
{
if (nmemb == 0 || size == 0) { return NULL;}
size_t buf_size = nmemb * size;
if (nmemb == buf_size / size) {
void* ptr = malloc(buf_size);
if(ptr != NULL){ memset(ptr, 0, buf_size); }
return ptr;
}
return NULL;
}
|
2.77
为了提高计算效率,乘以不同的因子K,使用+
、-
和<<
来实现。
- K=17
(x<<3)+x
- K=-7
(x-(x<<3))
- K=60
(x<<6)-(x<<2)
- K=-112
(x<<4)-(x<<7)
2.78
写出具有如下原型的函数代码
1
2
3
4
5
6
7
8
|
int divide_power2(int x, int k)
{
int is_neg = x & INT_MIN;
//加上偏量 CSAPP73页
(is_neg && (x=x + (1 << k) - 1));
printf("%d\n", x);
return x >> k;
}
|
2.79
1
2
3
4
|
int mul3div4(int x)
{
return x - ((x+(1<<2)-1)>>2);
}
|
2.80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
int threeforths(int x)
{
int f = x & ~0x3;
int l = x & 0x3;
f = ((f<<1)+f)>>2; // 3f/4
int lm3 = (l<<1)+l;
int bias = (1 << 2) - 1;
int is_neg = x & INT_MIN;
(is_neg && (lm3 += bias));
int lm3d4 = lm3 >> 2;
return f + lm3d4;
}
|
2.81
A. $1^{w-k}0^k$
-1 << k
B. $0^{w-k-j}1^k0^j$
~(-1<<k)<<j;
2.82
我们在一个int类型值为32的机器上运行程序,这些值以补码形式表示,而且他们都是算数右移的。unsigned类型也是32位的。
1
2
3
4
5
|
x = random()
y = random()
ux = (unsigned)x
uy = (unsigned)y
|
对于下列的每一个C表达式,你要指出是否为1
A. (x<y)==(-x>-y)
false(当x为INT_MIN时候, -x==x)
B. ((x+y)<<4)+y-x==17*y+15x
true
C. ~x+~y+1==~(x+y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
true
/*
* right
*
* ~x + ~y + 1
* =>
* ~x + 1 + ~y + 1 - 1
* =>
* -x + -y - 1
* =>
* -(x + y) - 1
* =>
* ~(x + y) + 1 - 1
* =>
* ~(x + y)
*/
|
D. (ux-uy)==-(unsigned)(y-x)
true
E. ((x>>2)<<2)<=x
false
2.83
一些数字的二进制表示由形如0.yyyyyyyy
无穷串组成,其中y是一个k位的序列。
A.
n = 0.yyyyy...
n << k = y.yyyyy... = Y + n
n << k - n = Y
n = Y/(2^k - 1)
B.
- $\frac{5}{7}$
- $\frac{2}{5}$
- $\frac{19}{63}$
2.84
填写下列程序的返回值。(需要理解float在计算机中的表示形式)
浮点数5在计算中的表示为40A00000
,也就是0100 0000 1010 0000 0000 0000 0000 0000
,那么如何变成我们想要的5.(s=1,exp=8,frac=23)
- Bias=127
- E = e-Bias = $2^7$ + $2^0$ - 127 = 2
- $f = 0.01 = \frac{1}{4}$
- $M = 1+f = \frac{5}{4}$
- $V = (-1)^0 * M * 2^E = 5$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
unsigned f2u(float x)
{
return *(unsigned*)&x;
}
int float_le(float x, float y)
{
unsigned ux = f2u(x);
unsigned uy = f2u(y);
unsigned sx = ux >> 31;
unsigned sy = uy >> 31;
return (ux << 1 == 0 && uy << 1 == 0) ||
(sx && !sy) || /* x < 0, y >= 0 or x <= 0, y > 0 */
(!sx && !sy && ux <= uy) ||/* x > 0, y >= 0 or x >= 0, y > 0 */
(sx && sy && ux >= uy); /* x < 0, y <= 0 or x <= 0, y < 0 */
}
|
2.85
给定一个浮点格式,有k位指数和n位小数,对于下列数,写出阶码E、位数M、小数f和值V的公式。
A. 数7.0
B. 能够被准确描述的最大奇整数
C. 最小的规格化数的倒数。
2.86
bias = 2^(15-1) - 1
description |
binary |
decimal |
least positive unstandard |
0 0000…(15) 0 000…(62)1 |
2^(1-bias-63) |
least positive standard |
0 000…(14)1 1 000….(63) |
2^(1-bias) |
bigest standard |
0 111…(14)0 1 111…(63) |
2^bias * (2-2^-63) |
2.87
Desc |
Hex |
M |
E |
V |
D |
-0 |
0x8000 |
0 |
-14 |
-0 |
-0.0 |
>2 least |
0x4001 |
1025/1024 |
1 |
1025/512 |
2.00195312 |
512 |
0x6000 |
1 |
9 |
512 |
512.0 |
bigest denormalized |
0x03FF |
1023/1024 |
-14 |
1023/(2^24) |
6.09755516e-5 |
-∞ |
0xFC00 |
- |
- |
-∞ |
-∞ |
ox3BB0 |
0x3BB0 |
123/64 |
-1 |
123/128 |
0.9609375 |
2.88
A bit |
A value |
B bit |
B value |
1 01110 001 |
-9/16 |
1 0110 0010 |
-9/16 |
0 10110 101 |
13*2^4 |
0 1110 1010 |
13*2^4 |
1 00111 110 |
-7/2^10 |
1 0000 0111 |
-7/2^10 |
0 00000 101 |
5/2^11 |
0 0000 0001 |
1/2^10 |
1 11011 000 |
-2^12 |
1 1110 1111 |
-31*2^3 |
0 11000 100 |
3*2^8 |
0 1111 0000 |
+oo |
2.89
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
int A(int x, double dx) {
return (float)x == (float)dx;
}
/* wrong when y is INT_MIN */
int B(int x, double dx, int y, double dy) {
return dx-dy == (double)(x-y);
}
/* right */
int C(double dx, double dy, double dz) {
return (dx+dy)+dz == dx+(dy+dz);
}
/*
* wrong
*
* FIXME I don't know what conditions cause false
*/
int D(double dx, double dy, double dz) {
return (dx*dy)*dz == dx*(dy*dz);
}
/* wrong when dx != 0 and dz == 0 */
int E(double dx, double dz) {
return dx/dx == dz/dz;
}
|
2.90
分配给你一个任务,编写一个C函数来计算$2^x$的浮点数表示。假设u2f返回的是浮点数值与它的无符号参数有相同的位表示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
float fpwr2(int x)
{
unsigned exp, frac;
unsigned u;
if(x < 2-pow(2,7)-23)
{
// to small
exp = 0;
frac = 0;
}else if (x < 2-pow(2,7))
{
exp = 0;
frac = 1 << (unsigned)(x - (2-pow(2,7)-23));
}else if (x < pow(2,7)-1+1)
{
exp = pow(2,7)-1+x;
frac = 0;
}
else
{
/* too big*/
exp = 0xff;
frac = 0;
}
u = exp<<23 | frac;
return *(float*)&u;
}
|
2.91
大约公元前250年,希腊数学家阿基米德证明了$\frac{233}{71} < \pi < \frac{22}{7}$,$\pi$的十六进制表示为0x40490fdb
A. 这个浮点数二进制为多少? 0 10000000 10010010000111111011011
B. $\frac{22}{7}$ 二进制小数是什么? 1.001001(001)...
C. 从第9位开始不同
2.92
对于浮点数f计算-f,只允许用位级浮点编码规则。
将exp以及frac以及sign提取出来,然后对sign进行操作即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
typedef unsigned float_bits;
unsigned f2u(float f) {
return *(unsigned*) &f;
}
float u2f(unsigned u) {
return *(float*) &u;
}
float_bits float_negate(float_bits f)
{
unsigned sig = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
int is_NAN = (exp == 0xFF) && (frac != 0);
if(is_NAN) return f;
return ~sig <<31 | exp<<23 | frac;
}
|
2.93
对于浮点数f,计算f的绝对值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
float_bits float_absval(float_bits f)
{
unsigned sig = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
int is_NAN = (exp == 0xFF) && (frac != 0);
if(is_NAN) return f;
if (sig & 0x1)
return ~sig <<31 | exp<<23 | frac;
else
{
return sig <<31 | exp<<23 | frac;
}
}
|
2.94
计算2*f。(对指数进行+1即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
float_bits float_twice(float_bits f)
{
unsigned sig = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
int is_NAN = (exp == 0xFF) && (frac != 0);
if(is_NAN) return f;
if(exp==0)
{
frac <<= 1;
}else if (exp == 0xFF - 1)
{
exp = 0xFF;
frac = 0;
}
else
{
exp += 1;
}
return sig <<31 | exp<<23 | frac;
}
|
2.95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
float_bits float_half(float_bits f)
{
unsigned sig = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
int is_NAN = (exp == 0xFF) && (frac != 0);
if(is_NAN) return f;
if(exp==0)
{
frac >>= 1;
}else if (exp == 0xFF - 1)
{
exp = 0xFF;
frac = 0;
}
else
{
exp -= 1;
}
return sig <<31 | exp<<23 | frac;
}
|
2.96
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
int float_f2i(float_bits f)
{
unsigned sig = f >> 31;
unsigned exp = f >> 23 & 0xff;
unsigned frac = f & 0x7FFFFF;
unsigned bias = 0x7F;
int num;
unsigned E;
unsigned M;
if (exp >= 0 && exp < 0 + bias)
{
num = 0;
}
else if (exp >= 31 + bias)
{
num = 0x80000000;
}
else
{
E = exp - bias;
M = frac | 0x800000;
if (E > 23)
{
num = M << (E - 23);
}
else
{
num = M >> (23 - E);
}
}
return sig?-num:num;
}
|
2.97
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
int bits_length(int i) {
if ((i & INT_MIN) != 0) {
return 32;
}
unsigned u = (unsigned)i;
int length = 0;
while (u >= (1<<length)) {
length++;
}
return length;
}
/*
* generate mask
* 00000...(32-l) 11111....(l)
*
* e.g.
* 3 => 0x00000007
* 16 => 0x0000FFFF
*/
unsigned bits_mask(int l) {
return (unsigned) -1 >> (32-l);
}
float_bits float_i2f(int i) {
unsigned sig, exp, frac, rest, exp_sig /* except sig */, round_part;
unsigned bits, fbits;
unsigned bias = 0x7F;
if (i == 0) {
sig = 0;
exp = 0;
frac = 0;
return sig << 31 | exp << 23 | frac;
}
if (i == INT_MIN) {
sig = 1;
exp = bias + 31;
frac = 0;
return sig << 31 | exp << 23 | frac;
}
sig = 0;
/* 2's complatation */
if (i < 0) {
sig = 1;
i = -i;
}
bits = bits_length(i);
fbits = bits - 1;
exp = bias + fbits;
rest = i & bits_mask(fbits);
if (fbits <= 23) {
frac = rest << (23 - fbits);
exp_sig = exp << 23 | frac;
} else {
int offset = fbits - 23;
int round_mid = 1 << (offset - 1);
round_part = rest & bits_mask(offset);
frac = rest >> offset;
exp_sig = exp << 23 | frac;
/* round to even */
if (round_part < round_mid) {
/* nothing */
} else if (round_part > round_mid) {
exp_sig += 1;
} else {
/* round_part == round_mid */
if ((frac & 0x1) == 1) {
/* round to even */
exp_sig += 1;
}
}
}
return sig << 31 | exp_sig;
}
|
参考