碰巧最近定义接口的时候碰到了浮点数精度的问题,稍微整理了浮点数的一些知识点:
指数部分决定了数的大小范围,有效数字部分决定了数的精度。
举两个简单的例子:
十进制 | 二进制 | 二进制科学计数法 | S | E | M |
---|---|---|---|---|---|
3.0 | 11.0 | 1.1 x 2^1 | 0 | 1 | 1.1 |
-5.0 | -101.0 | -1.01 x 2^2 | 1 | 2 | 1.01 |
double类型和float类型(可能还有long double类型)在计算机的底层存储结构都是一致的,唯一的不同在于float是32位而double是64位的。
无论什么数据,在计算机内存中都是以01存储的,浮点数也不例外。
计算机中小数的表示按照小数点的位置是否固定可以分为浮点数和定点数。为了方便和float32浮点数做对比,我们构造一个32位精度的定点数,其中小数点固定在23bit处:
定点数的底层表示
从定点数的存储上看,它表示的数值范围有限(以小数点在23bit为例,整数部分仅有8位,则整数部分取值范围是0~255),但好在处理定点数计算的硬件比较简单。
以32位浮点数为例,最高一位是符号位s,接着的8位是指数位E,最后的23位是有效数字M。double64最高一位是符号位,有11个指数位和52个有效数字位。下图展示了float32类型的底层表示:
float的底层表示
其中IEEE 754的规定为:
,因此规定M在存储时舍弃第一个1,只存储小数点之后的数字,这样可以节省存储空间(以float32为例,可以保存23位小数信息)
以78.375为例,它的整数和小数部分可以表示为:
因此二进制的科学计数法为:
按照前面IEEE 754的要求,它的底层存储为:
十进制中的0.5(代表分数1/2)表示二进制中的0.1(等同于分数1/2),我们可以把十进制中的小数部分乘以2作为二进制的一位,然后继续取小数部分乘以2作为下一位,直到不存在小数为止。以0.2这个无法精确表示成二进制的浮点数为例:
因此十进制下的0.2无法被精确表示成二进制小数,这也是为什么十进制小数转换成二进制小数时会出现精度损失的情况。
[1] https://q.115.com/182920/T1268124.html
[2] https://blog.csdn.net/u014470361/article/details/79820892
[3] https://www.cnblogs.com/wangsiting1997/p/10677805.html
[4] https://blog.csdn.net/u014470361/article/details/79820892