在计算机中,任何十进制的整数都可以用二进制表示。但是,浮点数就不是这样了,一个十进制的浮点数一般只能近似地转换成二进制浮点数。
float数据类型是利用二进制科学计数法来表示一个数字。而使用科学计数法的目的是存储极大数和极小数,同时可以容忍一定的精度损失。
float如何记录一个数字?
首先我们知道,任何一个数字都是可以用科学计数法来表示的。比如175,用十进制科学计数法则写作,其中有效数字是1.75,即有效位为3位。那如果表示为二进制科学计数法呢?我们可以先把175转成二进制,即10101111。然后在它后面加个小数点,即10101111.,再用位运算把数字往右推,一直推到小数点左边只剩下最后一个1,那么它就变成1.0101111。这里我们一共往右推了7位,那么最后用二进制科学计数法可以将它写作:。
知道了175是如何用二进制科学计数法表示的以后,我们再来看float类型是怎么记录这个数字的。首先来看float类型记录浮点数的格式。
从数学世界的科学计数法映射到计算机世界的浮点数时,数制从十进制改为二进制,还要考虑内存硬件设备的实现方式。在规格化表示上存在差异,称谓有所改变,指数称为“阶码”,有效数字称为“尾数”,所以用于存储符号、阶码、尾数的二进制分别称为符号位、阶码位、尾数位。
以为例:
- 7是2的指数,即阶码,会被存放在绿色的格子里。按照float的存放规则,这个数,二进制表示即00000111,会被加上127,即01111111,来存放。结果为10000110。
- 小数点后面的数字,即.0101111,是除小数点前数字之外的有效数字,即尾数。它则被存放在黄色的格子里,用二进制表示就是01,011,110,000,000,000,000,000。这里为了方便阅读,我用逗号将数字按每三位隔开。
- 因为175()是正数,所以在符号位,即红色的格子,应填0。
- 小数点前的1,可以省略,因为它在二进制数学计数法中总会是1。
到这里,我们就已经把175用float类型表示出来了。
总结将十进制数字转换成float类型的步骤
为了便于记忆,我们把前面的十进制数转float类型的过程归纳为步骤按顺序列出来。
1. 将十进制数转换成二进制数
至于如何将整数部分和小数部分分别取整,可以参考此篇博客。
十进制小数转化为二进制小数 | 菜鸟教程https://www.runoob.com/w3cnote/decimal-decimals-are-converted-to-binary-fractions.html2. 将步骤1的结果用二进制科学计数法表示,最终的格式应该是这样 ,
3. 将步骤2中得到的结果填入float类型,其中b是尾数位,c是阶码,是符号位。
float能存大数吗?
之前的例子里只用了一个很小的数字175,float可以准确无误地表示出来。但是,如果是一个很大的数字呢?float还能搞定吗?
我们可以用上面介绍的方法做个实验,尝试用float类型来存储1,000,009,003。为了表达更清晰,我在数字间每隔三位加了一个逗号。
1. 将数字转成二进制,得到111,011,100,110,101,110,110,100,101,011
2. 用二进制科学计数法表示,得到1.11,011,100,110,101,110,110,100,101,011e
3. 将结果填入float类型,这时出了问题。。。
在步骤3中,阶码的二进制是11101,float的阶码允许的位数是8位,所以直接填入即可;同样符号位也没问题,因为是正数直接置为0即可;但是到了尾数,它有29位,而float的尾数置允许填23位,也就是说,只有绿色的那部分可以被存储,而红色的部分会被丢弃。
从这个例子,我们能看到,用float来存储大数,必须以牺牲精度为代价。
假如我要用Float来存储一个整数,我最大能存多大的数同时保证精度?