这一章节涉及大量的数学推导,看起来会比较吃力。

2.3 整数运算

2.3.1 无符号加法

image.png
这个图看起来是比较抽象的,换个例子$1111 + 1111 = 11110$,这种情况就是溢出,也就是数值超出数据类型表示的范围,导致符号位或进位异常

1
2
3
4
5
6
7
8
#include <stdio.h>
int main() {
int a = 127; // 01111111(补码)
int b = 2; // 00000010(补码)
int c = a + b; // 01111111 + 00000010 = 10000001(-127,负溢出)
printf("c = %d\n", c); // 输出:-127(错误结果)
return 0;
}

在 C 语言中,并不会将溢出作为错误发出信号,但是有的时候,我们希望判断是否发生溢出。检测溢出的方法也较为简单,无符号数相加时,若结果小于其中一个加数,则必定发生溢出。因为无符号数的加法遵循模运算规则,溢出时结果会“回绕”到低位。

1
2
3
4
int uadd_ok(unsigned x, unsigned y) {
unsigned sum = x + y;
return sum >= x; // 若sum < x或y,说明溢出
}

2.3.2 补码相加

image.png

image.png

补码加法通过统一符号位和数值位的运算规则,简化了计算机硬件设计,同时通过溢出检测机制确保运算可靠性。其核心在于直接相加、忽略进位,并结合符号位分析处理溢出问题,如:

1
2
3
4
  0000 0101  (+5)
+ 1111 1101 (-3)
------------
0000 0010 (+2) // 结果正确,无溢出

溢出检测符号位变化法:两个同号数相加结果符号位不同,或异号数相减结果符号位与被减数相同,则溢出

1
2
3
4
  0111 1000  (+120)
+ 0000 1010 (+10)
------------
1000 0010 (-126) // 溢出(结果符号位为1,但原操作数均为正)
1
2
3
4
5
6
7
int tadd_ok(int x, int y) {
int sum = x + y;
// 正溢出:x>0, y>0, sum<=0
// 负溢出:x<0, y<0, sum>=0
return !( (x > 0 && y > 0 && sum <= 0) ||
(x < 0 && y < 0 && sum >= 0) );
}

2.3.3 补码的非

2.3.4 无符号乘法

image.png

2.3.5 补码乘法

2.3.6 乘以常数

编译器通过移位和加法运算的组合来代替常数因子的乘法

2.3.7 除以 2 的幂

除以2的幂也可以通过移位运算来实现,只不过是使用右移,而不是左移。无符号和补码数分别使用逻辑移位和算数移位来达到目的。
image.png
image.png

2.3.8 关于整数运算的最后思考

通过学习可以知道,计算机执行的“整数”运算实际上是一种模运算形式。


© 2024 Montee | Powered by Hexo | Theme stellar


Static Badge