前面两篇博客咱们具体讲解了核算机中整数的表明,包含有符号和无符号(补码编码)的具体介绍。那么这篇博客咱们将对它们的运算有个具体的了解。
在讲解之前首先看下面的一个程序,看看输出成果是啥?
#include <stdio.h>
int main()
{
int i = 2147483647;
printf("%d\n",i+1);
printf("%d\n",i+i);
return 0;
}
成果是:
咱们预期的:
i+1 = 2147483647 + 1 = 2147483648
i+i = 2147483647 + 2147483647 = 4 294 967 294
为什么程序中的成果和咱们数学中的常识会有这么大的区别?两个正数相加得到负数。这就需求咱们了解核算机中整数的运算原理。
1、核算机整数运算的限制
咱们知道核算机是用二进制序列来表明数的。而二进制序列的长度是和核算机本身的字长有关。不同的数据类型界说的二进制序列长度不一样,即不同的数据类型表明数的巨细规模是不一样的。可是不管是什么数据类型,它界说的二进制序列长度是有限的,即它表明的数的巨细规模是有限的。
所以两个数做运算,假如成果超出了界说数据类型所表明数的巨细规模,那么成果将会出现失真。并且这个失真的成果也不是随机的,而是有迹可循的,那么到底是怎样发生失真的,请接着往下面看。
PS:下面给出 64 位机器上C言语的整型数据类型的取值规模。本篇博客中程序运转环境都是在64位体系中进行。
2、无符号数加法运算
前面咱们讲过,关于一个 w 位的无符号二进制整数[xw-1 , xw-2 , … , x2 , x1 , x0],其值巨细满意 0 <= x <= 2w-1.
假如两个无符号数相加,那么其成果应该是 0 <= x+y <=2w+1-2。很显然表明这个规模的数必需求 w+1 位二进制。
当咱们对无符号数做加法运算的时候,假如成果超过了 2w-1,那么这个成果就会失真。
#include <stdio.h>
int main()
{
unsigned short int i = 65535;
unsigned short int j = i+1;
printf("%u\n",j);
return 0;
}
成果为:
关于上面的程序,咱们是在64位体系中进行运算。由上面给出的图片咱们能够知道 unsigned short int 在核算机中占用 2 个字节。表明的数据规模是 0——216-1,即0——65535
咱们在程序中界说 i = 65535,那么 i+1=65536,这个成果是超出了 unsigned short 表明的数据规模。所以成果失真了,可是成果为什么是 0 呢?
上一篇博客咱们讲过C言语中二进制数的截断:
将一个 w 位的数 [xw-1 , xw-2 , … , x2 , x1 , x0] 截断为一个 k 位数字时,咱们会丢掉高 w-k 位。得到 [xk-1 , xk-2 , … , x2 , x1 , x0]
关于上面的 i = 65535,二进制表明为:[1111 1111 1111 1111],加1 成果为 65536,用二进制表明为 [1 0000 0000 0000 0000],为了将成果保持在 4个字节,即32位二进制序列,咱们去掉最高位的 1,那么成果就变成了 [0000 0000 0000 0000],也便是打印出来的成果 0.
一般来说,无符号加法等价于核算和模上2w
比方上面的两者核算和为 65536,模上 2w,即模上216=65536,成果为0
ps:模表明两者共处取余
现在界说 0<= x,y <2w,那么它们运算满意下面联系:
留意:当 2w <= x+y < 2w+1,对 x + y 进行2w的取模运算,与 x + y – 2w是等价的。
所以假如两个无符号整数作加法运算。当 x+y < 2w 时,它们的成果不变;当 2w <= x+y < 2w+1,它们的成果为 x+y-2w
3、补码加法运算
关于补码加法运算,由于补码编码是表明有符号的整数。
关于一个 w 位的补码二进制整数[xw-1 , xw-2 , … , x2 , x1 , x0],其值巨细满意 -2w-1 <= x <= 2w-1-1。那么 -2w <= x+y <=2w-1
想要表明上面的两个数相加和的规模,那么或许需求 w+1 来表明。这儿咱们也需求截取。
与无符号加法运算不同,补码加法会出现三种状况:正溢出、正常、负溢出。界说如下:
规模在 -2w-1 <= x,y <= 2w-1-1 做加法运算时,满意:
简单来说:补码加法运算便是先依照无符号加法进行运算,而后在进行无符号和有符号的转换。
这儿咱们看个例子:
#include <stdio.h>
int main()
{
short int i = -32768;
short int j = i-1;
printf("%d\n",j);
return 0;
}
成果为:
为什么 -32768-1 成果会是 32767?
依据上面的公式:
咱们需求先将 -32768 和 -1 分别转换成无符号数进行加法运算,然后对得到的成果转换成有符号数。
①、-32768 转换成无符号数也便是 -32768+2^16=32768
②、-1 转换成无符号数也便是-1+2^16=65535
③、将上面两步的成果相加,然后转换成有符号数:
即(65535+32768)-2^16=65535+32768-65536=32767
这个过程用到的公式分别有:
4、无符号数乘法运算
关于一个 w 位的无符号二进制整数[xw-1 , xw-2 , … , x2 , x1 , x0],其值巨细满意 0 <= x <= 2w-1.
假如两个无符号数相乘,那么其成果应该是 0 <= x*y <=(2w-1)2=22w-2w+1+1。很显然表明这个规模的数或许需求 2w 位来表明。也便是 2w 位的整数乘积的低 w 位表明的值。依据咱们前面讲的截断原理:能够看做是核算乘积模2w,即:
#include <stdio.h>
int main()
{
unsigned short int i = 2;
unsigned short int j = i*2;
printf("%u\n",j);
return 0;
}
比方上面的程序成果是:(2*2)mod 216=4 mod 65536=4
5、总结
那么本篇博客结束咱们关于整数的表明以及运算都已经了解了。留意整数的运算我没有将减法,其实减法也便是转换为补码相加。并且核算机中也只有加法器,是没有减法器的。咱们只需求将减法转换为加法运算即可。
整数的表明和运算结束了,下一篇博客咱们将会讲解浮点数,也便是有小数的数。