计算机酷学(六)

数字(四)

截断

      截断其实就是大的数据类型转为小的数据类型时发生的操作。一般截断可以从二进制直观地感受一番,比如int转short时从int中取低16位,在进行相应的补码操作得到short。

无符号数的截断

      无符号ω位的位向量x截断为k位的位向量x’,其中ω>k,那么x’ = x % 2k,这很好理解。

有符号数的截断

      有符号ω位的位向量x截断为k位的位向量x’,其中ω>k。原理是一样的,只是比无符号数截断多了一些编码操作。如果硬要算的话,x’ = (x + xω-12ω) % 2k - xk-12k。不过知道原理即可,不需要手动计算。

加法运算

      无符号数x和y,取值范围都是[0, 2ω-1],它们的和在范围[0, 2ω+1-2]内,它们和的值有一部分超过了取值范围,这就发生了溢出,在计算机中它会被截断,减去2ω
在这里插入图片描述
      而有符号数x和y,取值范围为[-2ω-1, 2ω-1-1],和的范围为[-2ω, 2ω-2].同理可得
在这里插入图片描述
      那么我们如何检验溢出呢?以下以有符号数为例,只有当x<0,y<0并且它们的和sum>=0时发生负溢出,只有当x>0,y>0并且sum<0时发生正溢出。那么接下来就很简单了,方法代码如下:

int tadd_ok(int x, int y)
{
	int sum = x + y;
	int neg_over = x < 0 && y < 0 && sum >= 0;      // 判断是否负溢出
	int pos_over = x > 0 && y > 0 && sum < 0;		// 判断是否正溢出
	
	return !neg_over && !pos_over;					// 1代表没发生溢出
}

既然加法可以判断溢出,那么减法当然也可以。

int tsub_ok(int x, int y)
{
	if(y == INT_MIN) return !tadd_ok(x, -y);		// INT_MIN在limits.h中
	return tadd_ok(x, -y);
}

当y不等于INT_MIN时是没有什么问题的,但是当y = INT_MIN时,-y也等于INT_MIN,如果单纯的直接带入tadd_ok方法是会产生错误结果的,当x>=0时,本应会产生正溢出,但是结果返回1,当x<0时,本应不发生溢出,但是结果返回0。

乘法运算

无符号数的乘法

      无符号数x和y的取值范围为[0, 2ω-1],它们乘积的范围为[0, 2-2ω+1+1],因此x×y的最终结果是(x×y) % 2ω

有符号数的乘法

      怎么说呢?x×y的最终结果为(x×y) % 2ω-(x×y)ω-12ω

判断是否溢出

      首次我们令x×y低ω位的数值和为u(无符号),高ω位的数值和为v(有符号),那么x×y的值等于u+v2ω。其中的u应该等于p+pω-12ω,令t = pω-1 + v,q = p / x,r = p % x,则x×y = p + t2ω,p = q × x + r。只有当t=r=0时,y=q。

int tmult_ok(int x, int y)
{
	int p = x * y;
	return !x || p / x == y;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值