C/C++中的整数和浮点数在计算机中是如何表示的?
2017-10-13 16:03
417 查看
一、整数在计算机中的表示
在C/C++中,整数一般分为无符号数(unsigned char、unsigned short、unsigned int等)和有符号数(char、short、int、long等),在计算机中通过补码来表示,那么有童鞋会问了,不是有那什么原码、反码之类的吗?为什么不用它们而偏偏用补码呢?一开始我也有这样的困惑,于是通过各种查,各种看,算是理解了一点点,这里不打算详细解释原码和反码,只举几个例子说明在计算机中为什么不用它们表示十进制数,而用补码来表示。
我们能认识0、1、2、3、、、9等自然数,然而计算机却不认识,计算机“笨”的只认识0和1,所以那些大神们就通过各种手段,将现实世界中的各种信息都转化为一连串由0和1组成的序列。然后计算机就通过不同的解读方式,对这一系列的01串串根据具体的上下文解释成不同的信息。
我们都知道
1 + (-1) = 0,那么如果用原码、反码来表示这个会怎样呢?
原码:
原码 十进制 0000 0001 1 + 1000 0001 -1 ---------------- 1000 0010 -2
反码:
反码 十进制 0000 0001 1 + 1111 1110 -1 ---------------- 1111 1111 -0 // 需要通过转换为原码,才能直观的看出所表示的实际数字,原码:1000 0000
通过上面两个例子,我们看到,不管是用原码还是反码,都不能正确的表达结果。另外,我们可以发现,在原码和反码中,对于0的表示有两种,一种是
0000 0000(+0),一种是
1000 0000(-0),这也是一种缺陷,最好的方式是在给定一个十进制整数的范围内,该范围内的每一个数在相应的二进制表示中有且只有一个与之对应,也就是存在一一映射的关系。那么如何解决上述的问题呢?
终于等到补码登场了,一般主角都压轴,哈哈。补码,就是在反码的基础上再加1,比如-1的补码就是
1111 1110+
1=
1111 1111,用补码来进行上面的计算就是:
反码 十进制 0000 0001 1 + 1111 1111 -1 ---------------- 1 0000 0000 0 // 最高位的1被丢弃
结果为0,符合我们的实际逻辑。我们再来看看前面提到的一一映射的问题,在C/C++中,
char表示一个8bit的有符号整数,在计算机中用补码表示,所能表示的十进制范围为
[-128, 127]共256个数,那么这个范围是怎么得来的呢?
补码 十进制 0000 0000 0 0000 0001 1 ... ... ... 0111 1111 127(2^7 - 1) 1000 0000 -128(-2^7 + 0) 1000 0001 -127(-2^7 + 1) ... ... ... 1111 1111 -1(-2^7 + 127)
从上面可以看出,前128个数表示正数(最高位以0开始),后128个表示负数(最高位以1开始)。对于
unsigned char来说,由于其为无符号数,所以所能表示的最大范围为
[0, 255]。对于其它的整数数据类型可以通过类似的方法得到他们的表示范围,感兴趣的童鞋可以自己算算试试。
二、小数在计算机中的表示
对于float来说,在一般机器上都是以四个字节即32bit来表示,那么它在计算机中是怎么表示的呢?
IEEE 754规定,对于32位的浮点数,最高位的那位表示符号位
s,紧接着的8位是指数
E,剩下的23位为有效数字
M或者称为尾数。
图1 32位浮点数在计算机中的表示
图2 个人理解
在十进制中,对于任何一个小数都可以用科学计数法来表示,比如
12 a692 3.567的科学计数法就是
1.23456*10^2,
0.0097就是
9.7*10^-3;同样地,在二进制的世界中,任何一个小数也可以用类似的科学技术法来表示,只不过不在以
10为底,而是以
2为底。那么对于十进制的
123.567和
0.0097在二进制中如何表示呢?
十进制小数:123.567 在二进制中的表示: 1. 首先取整数部分123,用二进制中表示为1111011。 2. 小数部分.567如何表示? 我们都知道,在十进制整数进行二进制转化的时候有一个方法,就是对十进制数进行不断的除以2,然后取余数(要么为0,要么为1),然后按逆序排列就得到了十进制整数的二进制表示。 那么对于十进制的小数该如何用二进制表示是否找到了灵感?对,就是对小数部分不断的乘以2,然后对得到的新小数取整数部分(要么为0,要么为1)直到小数部分为0或者已经达到精度上限(比如所取得0、1已经达到23位了,再继续乘下去,对于32位的float来说,已经不能继续存储了)。 0.567 * 2 = 1.134 …… 取1 , 基数 = 0.134 0.134 * 2 = 0.268 …… 取0 , 基数 = 0.268 0.268 * 2 = 0.563 …… 取0 , 基数 = 0.563 0.563 * 2 = 1.126 …… 取1 , 基数 = 0.126 …… …… …… 最终结果为:10010001001001101110100。(23位) 所以.567在二进制中的表示为:.10010001001001101110100。 因而123.567在二进制中的表示为:1111011.10010001001001101110100。 用科学计数法表示为:1.1110 1110 0100 0100 1001 1011 1010 0 * 2^6。 通过IEEE 754的规定,我们可以很容易将其在计算机中表示: 符号位:0 指数位:Exp - 127 = 6 --> Exp = 133 -->1000 0101 尾数部分:1110 1110 0100 0100 1001 101 【IEEE 754规定,在计算机内部保存M时(1.XXXXXXX),默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。】 所以123.567在计算机中的完整表示就是: 0 1000 0101 1110 1110 0100 0100 1001 101
通过在线工具,可以验证上面结果的正确性,如下图:
图3 123.567在计算机中的表示
对于
0.0097也可以用同样的方法得到其在计算机内部的表示,这里就不在赘述了,有兴趣的童鞋可以自己尝试一下,然后通过上面提到的在线工具验证一下。
这里稍微再提一下,在C/C++中,
float所能保持的精度一般为小数位6-7位,那么这个6或7是怎么得来的呢?通过上面我们知道,对于32位的浮点数,后23位表示的是小数部分,总共可以表示
2^23 = 8388608,也就是说,后面的23位最多可以表示十进制小数的前7位小数位,通过四舍五入,至少可以保证6位的精度是正确的,至于第7位......呵呵!
好了,通过上面的描述,基本了解了
float在计算机内存是如何表示的了,那么
double在计算机中如何表示呢?其实和
float的表示原理是一样的,只是
double一般用64位bit来表示,最高位还是符号位,但是指数部分用了11位来表示,而剩余的52位全用来表示尾数(所能表示的精度一般为
2^52 = ?15-16位),其余的规则和32位的
float没啥区别,所以这里就仅放一张图,各位童鞋可以慢慢去体会。
图4 64位浮点数在计算机中的表示
参考
你应该知道的浮点数基础知识浮点数的二进制表示
IEEE 754-1985
(完)
相关文章推荐
- 浮点数在计算机中是如何表示的
- 计算机如何表示浮点数(小数)
- 浮点数如何在计算机中表示
- 关于浮点数和整数在计算机中的表示
- 关于浮点数和整数在计算机中的表示
- 求助:如何在UML中表示C++的析构函数?
- 浅谈计算机内存中浮点数的表示
- C++中如何表示2进制,8进制,16进制变量
- C++中,如何使double不用科学计数法表示
- int abs(int number)函数有感: 求补码和通过补码求对应的整数 C++(增加:数字的二进制表示中1的个数)
- C++ 将整数、浮点数转为字符串
- 负数在计算机中如何表示,计算机中负数为什么用补码表示?
- 关于浮点数的小数部分的二进制表示、精度以及浮点数如何在内存中存放问题
- C语言中位操作符(1)-计算机中的整数表示方法
- C/C++中如何表示上级和上上级路径?
- C++ 浮点数(double、float)如何定义NaN、正无穷、负无穷,以及如何判断是否是NaN
- C++内置类型在计算机内存中如何存储的
- 深入理解计算机系统(2.4)------整数的表示(无符号编码和补码编码)
- JAVA中如何将整数表示的ip地址转换为字符串表示
- Java浮点数在计算机中的表示方法(IEEE754-1985)