---恢复内容开始---

前面的空缺是我忘了保存 ##2.77## 使用位移运算和+- 实现乘法运算 A k=17 C=x<<4+x B k=-7 C=x-(x<<3) C k=60 C=x<<6-x<<2 D k=-112 就不做了 ##2.78## 写出具有如下原型的函数 ``` int divide_power2(int x,int k){ int w=sizeof(int)*8; int mask=x>>w-1; int bios=(1<>k; } ``` 使用负数掩码添加bios的技巧 ##2.79## 计算函数 ``` int mul3div4(int x){ x=x<<1+x; return divide_power2(x,2); } ``` //这个版本只需要先乘然后除就可以了 ##2.80## 新的版本不要求溢出 ``` int threefourths(int x){ int b1=divide_power2(x,1); int b2=divide_power2(x,2); return b1+b2; } //这个版本可以改进的,所有的掩码应该是一样的,我就不写了 ``` ##2.81## A. 1[w-n]0[n]: ~((1<-y 对于大部分正负合理的数是对的 ,但是极端数当 x等于 INT_MIN时不对 B (((x+y)<<4)+y-x)==17*y+15*x 只是加减构成了阿贝尔群 , 这样的等是没有问题 C ~x+~y+1= ~(x+y) 这个因该是对的 有这个式子 -x=~x+1 恒成立 D 对的 (ux-uy)==-(unsigned)(y-x) E ((x>>2)<<2)<=x 因该是对的 最后的两位被归零了 其余的位不变

2.83##

A. 令x为无穷序列表示的值,可以得到x*2^k = Y + x。 所以 x = Y/(2^k - 1)。 B. (a)1/7, (b)9/15 = 3/5, (c)7/63 = 1/9
表示无穷的方法

2.84##

通过符号位来判断float的大小这种方法是有非常好的性质,因为浮点数的自然顺序就是如此
还是漏掉了一种方法。
有四种不同的情况
一正一负
都是零
同正
同负
((ux<<1)0 && (uy<<1)0) || (!sx && sy) || (!sx && !sy && ux >= uy) || (sx && sy && ux <= uy);

2.85##

有k位指数 n位小数
写出阶码E,尾数M,小数f,和值V得公式

数7.0###

E =10011 (共k位)
f =11000共n位
尾数

够被准确描述的最大奇整数###

小数f 1111(全一 共N位 )
阶码 10011 (值是n) 2^(n-1) 这么大
值因该是
11111111 有n+1个 1
这个值是 2^n -1

最小的规格化数的倒数###

最小的规格化数
阶码
00000001 -2^(k-1) +2// 1-bios bios=2^(k-1)-1
小数
0000000 全零代表 1
值 2{-2(k-1)+2}

取导之后是
2^{ 2^(k-1) -2}
阶码是 11101 只有第1位是0 // 值应该是 2^k-1 -2 + bios
2^(k-1)
尾数是全零表示1

阶数的符号表示不是补码表示,进行计算的时候要带上bios
2^k-1 -1 这个是bios 换句话讲阶数等于0是这样的 01111111 大于零的阶数首位必定是1

2.86##

精度扩展的问题
80位字节下浮点数的一些特值
1 个符号位
15个阶码位
1个整数位 规格化数位1 非规格化数值为零
63个小数位
最小的 正非规格化数

2^( -2^(14) +###2### ) * 2^(-63)
//非规格化数阶数为1- bios 为了平滑的过渡
3.645*10^(-4951)
最小的正规格化数
2(-214 +2 )
最大的规格化数
(2-2(-63))*2

2.87##

在 一个符号位 五个阶码位 10个尾数位 时填表

描述 Hex M E V D
-0 8000 0 0 -0 *
最小的大于2的值 4001 0000000001 10000 2 +2^-9 *
512 6000 0000000000 11000 512 512.0

---恢复内容结束---

前面的空缺是我忘了保存

2.77##

使用位移运算和+- 实现乘法运算
A k=17 C=x<<4+x
B k=-7 C=x-(x<<3)
C k=60 C=x<<6-x<<2
D k=-112 就不做了

2.78##

写出具有如下原型的函数

int divide_power2(int x,int k){
	int w=sizeof(int)*8;
	int mask=x>>w-1;
	int bios=(1<<k)-1;
//	printf("%d",bios);
	return(x+bios&mask)>>k;
}

使用负数掩码添加bios的技巧

2.79##

计算函数

int mul3div4(int x){
	x=x<<1+x;
	return divide_power2(x,2);
}

//这个版本只需要先乘然后除就可以了

2.80##

新的版本不要求溢出

int threefourths(int x){
	int b1=divide_power2(x,1);
	int b2=divide_power2(x,2);
	return b1+b2;
}
//这个版本可以改进的,所有的掩码应该是一样的,我就不写了

2.81##

A. 1[w-n]0[n]: ~((1<<n) - 1)
B. 0[w-n-m]1[n]0[m]: ((1<<n) - 1) << m

2.82##

A x<y == -x>-y
对于大部分正负合理的数是对的 ,但是极端数当 x等于 INT_MIN时不对
B (((x+y)<<4)+y-x)17y+15x 只是加减构成了阿贝尔群 , 这样的等是没有问题
C x+y+1= ~(x+y) 这个因该是对的 有这个式子 -x=~x+1 恒成立
D 对的 (ux-uy)
-(unsigned)(y-x)
E ((x>>2)<<2)<=x 因该是对的 最后的两位被归零了 其余的位不变

2.83##

A. 令x为无穷序列表示的值,可以得到x*2^k = Y + x。 所以 x = Y/(2^k - 1)。 B. (a)1/7, (b)9/15 = 3/5, (c)7/63 = 1/9
表示无穷的方法

2.84##

通过符号位来判断float的大小这种方法是有非常好的性质,因为浮点数的自然顺序就是如此
还是漏掉了一种方法。
有四种不同的情况
一正一负
都是零
同正
同负
((ux<<1)0 && (uy<<1)0) || (!sx && sy) || (!sx && !sy && ux >= uy) || (sx && sy && ux <= uy);

2.85##

有k位指数 n位小数
写出阶码E,尾数M,小数f,和值V得公式

数7.0###

E =10011 (共k位)
f =11000共n位
尾数

够被准确描述的最大奇整数###

小数f 1111(全一 共N位 )
阶码 10011 (值是n) 2^(n-1) 这么大
值因该是
11111111 有n+1个 1
这个值是 2^n -1

最小的规格化数的倒数###

最小的规格化数
阶码
00000001 -2^(k-1) +2// 1-bios bios=2^(k-1)-1
小数
0000000 全零代表 1
值 2{-2(k-1)+2}

取导之后是
2^{ 2^(k-1) -2}
阶码是 11101 只有第1位是0 // 值应该是 2^k-1 -2 + bios
2^(k-1)
尾数是全零表示1

阶数的符号表示不是补码表示,进行计算的时候要带上bios
2^k-1 -1 这个是bios 换句话讲阶数等于0是这样的 01111111 大于零的阶数首位必定是1

2.86##

精度扩展的问题
80位字节下浮点数的一些特值
1 个符号位
15个阶码位
1个整数位 规格化数位1 非规格化数值为零
63个小数位
最小的 正非规格化数

2^( -2^(14) +###2### ) * 2^(-63)
//非规格化数阶数为1- bios 为了平滑的过渡
3.645*10^(-4951)
最小的正规格化数
2(-214 +2 )
最大的规格化数
(2-2(-63))*2

2.87##

在 一个符号位 五个阶码位 10个尾数位 时填表

描述 Hex M E V D
-0 8000 0 0 -0 *
最小的大于2的值 4001 0000000001 10000 2 +2^-9 *
512 6000 0000000000 11000 512 512.0
最大非规格化数 7fff 1111111111 11111 (2 - 2^-10 )*2^16 *
-∞ fc00 * * * *

M 应该是小数值
E 应该是阶码的值,我就不再改了

2.88##

浮点数的转换

1 01110 001 -9/16 1 0110 0010 -9/16
0 10110 101 416 0 1110 1010 416
1 00111 110 -9/1024 0 0000 0111 -7/1024
0 00000 101 5*2^12 0 0000 0000 0
1 11011 000 -2^12 1 1111 0000 -∞
0 11000 100 3*2^8 0 111 1111 (2-24)*28

2.89##

另外在32位的机子上double 和 flaot 是使用了80位的扩展精度(我的机子上只有longdouble 是80 位 的)
喜闻乐见的找错误环节
int x=random()
double dx=(double)x
A (float)x==(float)dx 错的,单精度浮点数误差 最多表示一个数最高位1和最低的1相差不超过24位的数 ,超过这个范围没有办法表示了
B dx-dy (double)(x-y) 显然是错的
C (dx+dy)+dz
dx+(dy+dz) 经典的错误 浮点数的结合律会被舍入规则坑掉的
D dx/dx=dz/dz 其中一个是0的话有可能出来Nan的

2.90##

偷个懒就是判断一些可以有效表示的范围

2.91-2.97##

实现在 flaot_bits 上的函数 我就先不写了