csappchap2学习记录

本文详细探讨了整数的左移、右移操作在算术和逻辑上的区别,以及有符号和无符号整数的表示转换。同时涉及浮点数表示方法、规格化与非规格化表示,以及存储中的大端和小端模式。还介绍了位运算在处理这些数值运算中的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

左移右移

  1. 对于左移,低位以0补(无关算术左移还是逻辑右移)
  2. 对于右移,算术右移是用符号位填充,逻辑右移用0填充

整数的编码

  1. 无符号表示
  2. 补码表示(Two’s Complement)(有符号)
    理解:最高bit权值为Tmin,其它权值为正
  3. 对于有符号和无符号的转化,只需要改变系统解释的方式,而不需要改变实际存储

有趣的位级等式

Tmin and Umin
	Tmin = 1<<31 
1.  x + ~x = -1
2. x & (-x) 1110(-2) 0010(2) --> 0010  Brian Kernighan算法
3. 常量默认是signed类型, 但当一个表达式出现了unsigned类型,会将signed类型隐式转化
4. -2147483647 - 1 = Tmin = Umax(the same as -8 to 8)

有符号和无符号扩展

扩展时只需要把高位填充成0(无符号)或符号位(有符号)


有无符号整数 的基本运算

加法

加法 不区分有符号无符号, 合适的模数,并不同解释

乘法

k bits * k bits
乘法 不区分有符号无符号 。C语言只保留k位,截断后结果一致(001)
对 2 ^ k取模,再不同解释
0x101 * 0x101 -> 11 001(25 11001 或 9 1001)
通过位运算实现高效乘法
x * k 等价于 x与k的各位相乘 再相加 k = 14(14 = 8+4+2),进行转化;

除法

只讨论特殊的除以2的k次幂

  1. 无符号整数 向下舍入除法 右移k位
  2. 有符号整数 向下舍入除法 右移k位
x为原数,x1为高w-k位(共w位),x2为低k位,通过对无符号类似的分析
x = 2^k * x1 + x2; 可知向下取整
  1. 由 向上取整 和 向下取整 之间的数学转换,可以得到有符号向上舍入除法
ceil(x/y) = floor((x+y-1) / y); ceiling,天花板,向上取整
若x<0,即有符号, (x+(1<<k)-1) >>k 能得到 有符号整数 的向上舍入

存储方式

大端存储 和 小端存储 Big Endian / Little Endian

#小端存储 把数据的最低字节(不是bit)位置 放在存储端的 最高字节位置
–>假设向右地址增大 则:
0x12 34 56 ff 的存储为:0x ff 56 34 12
#大端存储 相反

检查数据的字节顺序(data representation)

内存地址顺序 逐字节打印 看是否与原数的表示相同

字符串表示

‘0’ -> 0x30

Integer C Puzzles

x &7 == 7 --> x<<30 小于0 正确
(-INT_MAX) * (-INT_MAX) = 1 正确
x< y --> -x > -y(x=Tmin 错)

Floating point(浮点数)

表示方法

类似 原码表示
s(sign) exp(exponent) M->Significand(尾数) M = f + 1
*公式: (sign)2^(E-Bias) M
解释:(规格化表示时,)尾数隐含以1开头,因为除了0以外的小数,都可以用科学计数法 让整数部分为1(2进制)
单精度浮点表示图

浮点数没有补码 的概念,采用类似 原码 的概念

规格化表示

#单精度
指数 8bits 0-255 保留0,255不使用
类似无符号, 但会 -127(biased value/Bias) 来满足负指数的要求
#双精度
Bias = -1023 同样保留0,1023

非规格化表示

为了表示0和接近0的小数 和特殊数 非规格化表示
exp = 0 ->10^-126 (Bias = -126,(-127+1)不一样!!!
这样设计的原因:实现最大非规格化数与最小规格化数 的 平滑转变,作为对非规格化数不隐含开头1的补偿

特殊数

exp全1 无穷数(inf)(frac=0) 和 非法数(NaN,not a number) (frac!=0)
因此,浮点数溢出会得到正无穷或非法数(可见上图看区分规则)

实现C语言的双精度正无穷、负无穷、0
//粗略实现(答案是这么写的)
#define POS_INFINITY 1e400
#define NEG_INFINITY (-POS_INFINITY)
#define NEG_ZERO (-1.0/POS_INFINITY)

浮点运算

浮点加法不具有结合性(误差)
浮点加法与乘法具有单调性

位运算技巧

#实现掩码,获取需要的位
1.取出最低有效字节

x & 0xff

2.取出除最低字节以外其它字节

x & ~0xff

2.5 不使用右移,取出符号位并转化为标准01

//不使用右移
!!(x&(1<<31)) //10000 -> 1, 0->0

3.判断是否为Umax(为真返回1,后同)

return ! ~x

3.5 常用掩码:2^k-1*

通常由移位得到,可以得到大量的、分界的1和0
如果k=0;得到全0(2^0 - 1=0)

4.判断最低有效字节是否全1
结合1,3

return ! ~(x&0xff)

5.判断是否奇数位全1

//mask四个字节全为aa(1010)
mask = (0xAA<<24) | (0xAA<<16) | (0xAA<<8) // A -> 10
//清除x的偶数位 置为0
x = x & mask;
//异或运算来判等
return !(x^mask)

6.用移位实现符号扩展

//1字节到4字节(输入为unsigned char x)
int b = x;//举例,x=15; b=0x000f
b = b<<(3<<2) //b = 0xf000
return b>>(3<<2);//b = 0xffff;

7.用算术右移来完成逻辑右移,或相反(注意怎么生成掩码)

//算术右移实现逻辑右移
unsigned srl(unsigned x, int k){
	/*给出的算术右移值,之后操作不允许再右移*/
	unsigned xsra = (int)x>>k;
	//只需把高k位用掩码置零即可
	//生成掩码方式:让第k位为1,再整体减一(快速出现大量的1!)
	int x = 1<<(32-k) - 1;
	return xsra & x;
}
//逻辑右移实现算术右移
int sra(int x, int k){
	/*给出的逻辑右移值,之后操作不允许再右移*/
	int xsrl = (unsigned)x >> k;
	//高k位用掩码置为符号位 与 sss000 相或 (s表示sign)
	//利用2.5的知识
	int sign = !!(x & (1<<31));//得到标准0,1的s
	unsigned tem = ~((a<<(32-k)) - 1);
	int xsra = xsrl | tem;
	return xsra;
}

8. 实现除以2^k(向0舍入)

即上面提到的 
若x<0,即有符号, (x+(1<<k)-1) >>k 能得到 有符号整数 的向上舍入
若x>=0 直接是 x>>k
写成C表达式:
return x>=0?(x:(x+(1<<k)-1))>>k;
不能用条件判断,考虑怎么让x符号位为0时x+0,反之+(1<<k)-1
-->使用掩码
return (x + sign*((1<<k)-1))>>k //使用了不能使用的乘法
//根据符号位 生成全1 或 全0掩码 来实现乘1或乘0
s=1时,不好得到全1,先得到全0,再取反
s=0时,不好得到全0,先得到全1,再取反
统一为 ~(s-1)
return (x + ~(s-1) & (1<<k-1))>>k;

判断是否含奇数个1

显然异或
对与 前一半与后一半异或的结果, 只看后一半位数,后一半位数与整体含有1的个数的奇偶性相等
选择性忽略前一半即可
x ^= (x>>16);
x ^= (x>>8);
x ^= (x>>4);
x ^= (x>>2);
x ^= (x>>1); //只看最低位,选择性忽略其它位
return x& 0x1

提取最左位置的1状态

如 0xff00 返回0x8000,注意:if(x===0) return 0
//提示:为得到00010000 可先得到 00001111 or 00011111(再右移1位即可)
//得到 00011111更容易(雾)
//想到 得到交叉01的式子,再 位或 到一起
// 00010101 & (00010101 >>1) --> 00011111
// 利用最左位置的1可以得到 00010101
x |= x >> 16
x |= x >> 8
…
x |= x >> 1
此时得到了包括了最左位置靠右全1,先移位
x = (x >> 1) + 1
``
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雾影林深

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值