目录
概念:
简述:
Everybody Kown,计算机历史上有两位很重要的人物,第一位是计算机科学奠基人(Alan Mathison Turing) 阿伦·图灵 ,他在计算机科学方面的贡献主要有两个,一是建立图灵机(Turing Machine,TM)模型,奠定了可计算理论的基础;二是提出了图灵测试(Turing Test),阐述了机器智能的概念……(计算机里面最高的奖项就是图灵奖,每年颁发给在计算机科学领域做出杰出贡献的人才,被誉为计算机业界和学术界的诺贝尔奖),
第二位则是被称为现代计算机之父的美籍匈牙利数学家(Von Neumann) 冯·诺依曼,他的主要贡献是1945年,冯·诺依曼在指定EDVAC(电子离散变量计算机)的计划中(公认的第一台计算机),提出了存储程序的概念,就是将程序和数据一起存放在存储器中,以后凡是以此概念为基础的各类计算机,都被称为冯·诺依曼计算机,它的特点主要包括了:
- 计算机有运算器,存储器,控制器和输入设备,输出设备五大部件组成
- 指令和数据以同等地位存于存储器中,并可按地址寻访
- 指定和数据均用二进制代码表示
- 指令由操作码和地址码组成,操作码用来表示操作的性质,地址码用来表示操作数在存储器中的位置
- 指令在存储器内按顺序存放,通常,指令是顺序执行的,在特定的条件下,可以根运算结果或根据设定的条件改变执行顺序
- 机器以运算器为中心,输入输出设备与存储器键的数据传送通过运算器完成。
其中运算器,只有加法运算器,没有减法运算器
- 减法和加法是一样的,只要加个电信号,把减数变成负的就可以了,把加变成减,看看加法器的电路图,一般“加法器”同时是“减法器”。
- 乘法器和除法器:乘法器很简单,用加法器多加几次,或者增加硬件,多弄几个加法器就可以了,乘数、被乘数都要先转化为二进制,二进制的乘法远比十进制简单,比如乘数是1011,只需将将被乘数分别左移3位、1位,移动后补入0,并将这三个数(被乘数左移3位的、被乘数左移1位的及未移位的被乘数)在累加器中相加,所得总和就是积,根据需要积可再转化为十进制。
除法与乘法类似,除法就是乘法的逆运算,只不过将左移改为右移,加改成减。实际上减也是通过取补码后再加,因此计算机芯片上的累加器是最繁忙的部分。运算比较复杂,大概就是这么回事。 - 乘法运算使用加法和移位操作实现的,根据机器数的不同,又分为原码乘法和补码乘法,具体的细节记不太得了……就不一一赘述了。(这个是涉及到位运算,一般在开发中很少使用位运算的,具体怎么运算的是computer的cpu完成的,复杂且繁琐,如果特别感兴趣,《计算机组成原理》中有详细的介绍……)
- 除法运算可用加(减)和移位操作实现的,根据机器数的不同,又分为原码除法和补码除法,具体的细节记不太得了……就不一一赘述了。(这个是涉及到位运算,一般在开发中很少使用位运算的,具体怎么运算的是computer的cpu完成的,复杂且繁琐,如果特别感兴趣,《计算机组成原理》中有详细的介绍……)
- Notice:计算机硬件结构中,也不全是“只有一个加法器”,至少还有“浮点运算的加法单元和浮点乘法,浮点除法的单元”.
所以,计算机中没法直接做减法运算的,它的减法运算都是通过加法运算来实现的
比如,10 - 3 = 7 ,这很简单,在计算机中,它会加上减数的相反数得到的是一样的结果: 那么就是 10 + -3 = 7;所以这时候就要有负数的概念,那么这就是为什么不得不引入一个符号位来表示正数,和负数了,(最高位是符号位,“0” 表示正数,“1”表示负数)
说明: 原反补码的引入是为了做负数的运算的,整数的原反补码都是一样的!
原码:
原码就是指的二进制定点表示法,每个十进制数字都有它对应的二进制码,即最高位是符号位,“0” 表示正数,“1”表示负数,其他的位数存放该数的二进制的绝对值,也就是表示该数值的大小。
如下图所示,给出部分数字的二进制原码;
比如:
先加正数(这很简单):
3 + 3 = 6 ;换成二进制就是:(这没问题)
3 + 3 = 6
0000 0011 + 0000 0011 = 0000 0110
0 + 0 = -0;换成二进制就是:(这也没问题,0 和 -0 本身就是同一个数字)
0 + -0 = -0
0000 0000 + 1000 0000 = 1000 0000
但如果是一个正数加它的相反数:比如:
3 + -3 = ? ; 换成二进制就是:
3 + -3 = -6
0000 0011 + 1000 0011 = 1000 0110
3 + -3 = -6? why?
原因很简单: 就是表示正负数的符号位所引起的
不光只是一个正数加它的相反数使用原码运算会这样,负数和负数使用原码运算也是会出现莫名其妙的效果的;
比如:
-3 + -3 = 6
1000 0011 + 1000 0011 = 1(丢弃最高位1) 0000 0110 (由于一个字节规定了只能是八个位所以最高位丢弃不要,硬件决定了)
由此可以看出,如果是正数之间的运算使用原码进行运算,完全没有任何的问题,因为这本身就是一个很简单的二进制加法,但是正数和负数,负数和负数的运算就有问题了;
于是,引入了反码:
反码:
正数的反码与原码相同,而负数的反码,是对其原码逐位取反,但符号位不变(所谓取反就是 1 变 0 , 0 变 1)
如下图所示,给出部分负数数字的二进制反码;
光是从原码的运算就不难看出,原码最大的问题就在于任意一个正数加上它的相反数不等于 0 ;
紧接着: 试试用正数的原码加上它的相反数的反码?
比如:
3 + -3 = ?
3 + -3(反码) = -0(就是0本身)
0000 0011 + 1111 1100 = 1111 1111
3 + -3 = 0;
正数 + 负数?
7(原码) + -2(反码) = -5(反码)
0000 0111 + 1111 0010 = 1111 0101
再比如:
-4(原码)+ -4(反码)= 6(原码)?
1000 1011 + 1111 1011 = 1(丢弃最高位)0000 0110 (由于一个字节规定了只能是八个位所以最高位丢弃不要,硬件决定了)
负数相加?why?
-1(原码) + -5(反码)= -7(反码)?
1000 0001 + 1111 1010 = 1111 1000
发现明显不对:
反码的出现的好处就是解决了正数加它的相反数等于0 和正数加负数的运算的结果是正确,而负数和负数相加的结果始终都是错的,这始终不是还不是完美的解决方案;
于是引入了补码:
补码:
正数的补码与其原码相同(换言之就是正数的原、反、补都是一样的);负数的补码是在反码的末位 + 1;(负数的补码是它的原码自低位向高位,尾数的第一个 “1” 及其右边的 “0” 保持不变,左边的各位按位取反,符号位不变,0除外!0则全部取反,0比较特殊,介于正数与负数之间,它的原、反、补都是 0000 0000 ,它严格意义上来说属于自然数!)
如图所示:
补的概念:
例如生活中的时钟:
比如现在是6点整,那么下一次到3点整的时候会在多少个小时呢?
- 逆时针3小时之前 即 6h - 3h = 3h
- 顺时针9小时之后 即 6h + 9h = 15h , 15h - 12h = 3h
可见 -3 可用 +9 代替 减法 ———》 加法
称 +9 是 -3 以 12为模的补数 , 可以说 6-3 和 6+9 在模为12的情况下的结果是等效的
记作
同理
现在再来试验
正数与负数相加,
比如:
3(补码)+ -6(补码)= -3 (补码)
0000 0011 + 1111 1010 = 1111 1101
-2(补码)+ 7(补码) = 5(补码)
1111 1110 + 0000 0111 = 1(丢弃最高位1)0000 0101(由于一个字节规定了只能是八个位所以最高位丢弃不要,硬件决定了)
正数与它的相反数相加
9(补码) + -9(补码)= 0(补码)
0000 1001 + 1111 0111 = 1(丢弃最高位1) 0000 0000(由于一个字节规定了只能是八个位所以最高位丢弃不要,硬件决定了)
6(补码) + -6(补码) = 0(补码)
0000 0110 + 1111 1010 = 1(丢弃最高位1)0000 0000(由于一个字节规定了只能是八个位所以最高位丢弃不要,硬件决定了)
0(补码)+ -0(补码) = 0(补码)
0000 0000 + 0000 0000 = 0000 0000
Notice:从数学的角度来说 0 和 -0 就是同一个数, 0这个数比较特别,介于正数和负数之间,它的绝对值就是它本身,它并没有相反数,它就是自然数中的一类!
负数与负数相加:
-4(补码)+ -5(补码) = -9(补码)
1111 1100 + 1111 1011 = 1111 0111
-2(补码)+ -6(补码) = -8(补码)
1111 1110 + 1111 1010 = 1111 1000
-8(补码) + -9(补码) = -17(补码)
1111 1000 + 1111 0111 = 1110 1111
-7(补码) + -3(补码) = -10(补码)
1111 1001 + 1111 1101 = 1111 0110
OK,Perfect ,运算全部正确!
Notice:如果运算结果超出了其字节大小所表示的范围,会产生不正确的结果:比如:这里使用的是八个字节, -60 + -70 = 126 ,产生了数值溢出!
-60(补码)+ -70(补码)= 126(补码)?
1100 0100 + 1011 1010 = 1 0111 1110
此时就要选择2个字节来表示运算结果了,正确结果如下:
-60(补码) + -70(补码) = -130(补码)
1111 1111 1100 0100 + 1111 1111 1011 1010 = 1111 1111 0111 1110
由此可见!计算机中的运算都是按照补码的形式进行运算的!
平时使用的计算器,它的负数都是已经以补码的形式转好了的,
由于正数的原码,反码,补码都是一样的,所以看到的始终都是一样的二进制码!
不难看出,计算机科学家们引入了原码、反码、补码的就是为了解决做减法的问题,加减乘除四则运算甚至更复杂的运算得到很完美的解决方案!存在即合理,尤其是这种发明的,定死的,千万不要纠结为什么要有反码?,为什么要有补码?我猜之所以这样,设计理念,设计思想均来源于生活,只能说二级制和十进制的运算机制不一样……,它没有加减乘除法口诀表…… 加法,减法是相对的,乘法,除法是相对的……,就好比正数, 负数是相对的一样