在小明学C++第二篇,我们看到,小明用了整型、浮点型等数据类型,那么这些数据类型在计算机里面是怎么表示的?它们的运算操作又是怎么实现的?此外,主函数调用面积计算函数calculate的时候到底发生了什么?经过翻译后,一条高级语言编写的语句变成了很多不可再分割的独立的机器语言,也就是指令。那么多的指令是如何在计算机上面运行的呢?下面我们就逐一来探讨一下以上的问题。
数的表示和运算
(1)为什么是二进制?
我们知道,计算机使用的是二进制,也就是只有0和1。为什么要这样子呢?为什么不使用人们常用的十进制呢?在我看来原因只有一个,那就是使用二进制简单。0和1是根据电压值来确定的。如果用十进制,就要使用复杂的硬件装备去准确测定到底是多少伏特。但是如果用二进制,“1”用有电压表示,“0”用无电压表示,这样测量到底有没有电压就简单多了,而且不容易出错。
(2)数的表示
数可以分为三种:无符号数、有符号数、浮点数。无符号数只能表示0和正整数,有符号数可以表示负整数、0以及正整数。而浮点数是用来表示可正可负的小数。
二进制和十进制其实是类似的,不同在于二进制是逢二进位,十进制是逢十进位。十进制使用的是位值表示法:
123=1*10^2+2*10^1+3*10^0
位值表示法中,每一个位的权重不同,高位权重大,低位权重小,因此虽然1比3小,但是百位大于个位。同理,二进制1010:
1010=1*2^3+0*2^2+1*2^1+0*2^0
那么二进制与十进制怎么转换?
二进制转换成十进制直接使用上述公式就可以得到十进制表示,比如1010=8+2=10;
十进制转二进制就麻烦一点。我们可以列出一个方程:
10=a3*2^3+a2*2^2+a1*2^1+a0*2^1
于是要想把10转化成二进制,关键在于确定a3-a0的值。
首先因为10是偶数,因此a0值为1;
然后等式两边同时除以2,得到:
5=a3*2^2+a2*2^1+a1*2^0
因为5是奇数,因此a1值为1;再对等式同时除以2:
2 = a3*2^1+a2*2^0
因为2是偶数,因此a2值为0;
同理a3值为1;
故十的二进制表示为1010。
可以将十进制转二进制的方法归纳如下:
a.先构造一个N的二进制展开式;
b.根据N的奇偶值确定最低位的取值,然后等式两边除以2;
c.根据N的符号确定符号位的值。
在计算机里面,称经过这种方法转换得到的叫做原码。
还有一种叫做补码的表示:
如果一个数是正整数,它的补码就是原码。如果一个数是负数,它的补码是原码取反加一。
比如10的补码是01010,而-10的补码是10110(10101+1);
至于为什么要有补码,是为了运算方便,后面讲数的运算你就知道了。
我们现在来讲讲小数的表示吧。
下面讲到浮点数表示都是按照IEEE 754标准来的。
浮点数的表示跟十进制的科学计数法类似。科学技术法规定小数点前面只有一位有效数字,然后小数点后面都是尾数,还要乘以10的n次方。比如6.023*10^23,其中023是尾数,23是阶数。同理,浮点数也采用这种思想:
其中float是单精度,double是双精度,因此double能够表示的数值比float多,因为double的位数更多。从图中可见,float占4字节,而double占八个字节。
S是表示符号位的,E表示阶数,M表示尾数。
比如-6.625的表示:
首先是负数,因此符号位s的值为1;