平时项目开发中经常会遇到一些精度丢失的问题,像老生常谈的0.1 + 0.2 !== 0.3,只知道是计算机的二进制实现和位数限制,有些数无法有限表示,但却没认真去亲自检测过。今天心情好,来测试一把。
在此之前,我们先来复习一下还给老师的知识点
二进制转十进制:
十进制转二进制:
整数:
小数:
知道是怎么算就阔以了,快速转换进制,工具送上:https://tool.oschina.net/hexconvert/
在计算机中,我们存储一个数的存储结构由三小块组成,对应 符号位 、指数位、尾数位
符号位
简单清晰,占一位: 1代表负数, 0 代表正数
指数位
浮点数可分为单精度类型and双进度类型,单精度指数位: 占8位, 双进度指数位: 占11位。
对前端来说,我们知道JavaScript 存储小数和其它语言如 Java 和 Python 都不同,JavaScript 中所有数字包括整数和小数都只有一种类型 即 Number类型,是以64位双精度浮点数存储所有Number类型值,所以指数位占11位。
关于指数位的计算:
- 计算机对于整数的存储只需要转换成对应的进制。相比于小数,小数点的位置无法确定,小数点后面的位数也无法确定。所以提出借助科学计数法解决,例如:11011.1 科学计数法转化为:1.10111 * 24,这样小数点的位置就确定下来了
- 偏移量: 2k - 1, k代表所占位数,像单精度占8位,双精度占11位,所以单精度指数偏移量为127, 双精度指数偏移量为1023
- 指数位 = 偏移量 + 指数
以双精度来举例:
11011.1 科学计数法转化为:1.10111 * 24,因为是双精度,所以偏移量为1023, 指数为4, 所以指数位的值为1027(此时得到的值位十进制,需要转换成计算机识别的二进制)
再转化为二进制: 1000 0000 011 (tips: 转化的二进制不足位数时,记得补0,这里刚好是11位,不用补)
尾数位
- 单精度占23位, 双精度占52位
- 取转换为科学技术发后小数点后面的值就完事了(下方案例送上)
案例补充:
0.1
转化为二进制:
0.0001100110011001100110011001100110011001100110011001101
转科学计数法:
1.100110011001100110011001100110011001100110011001101 * 2-4
转实际存储:
正数: 0
指数位:1023 + (- 4 ) = 1019 转 二进制: 1111 1110 11 --》 指数位为11位,补0得到:01111111011
尾数位:1001100110011001100110011001100110011001100110011010
结果:0 01111111011 1001100110011001100110011001100110011001100110011010
tip: 指数位从前往后补0;尾数位从后往前补0;
27.5
转二进制:
11011.1
转科学技术法:
1.10111 * 24
转实际存储:
正数: 0
指数位:1023 + 4 = 1027 转二进制:1000 0000 011
尾数位:10111
结果:0 1000 0000 011 10111000000000
机器数0 1000 0000 011 10111000000000 转10进制
取符号位: 0为正数
取指数位:1000 0000 011 转10进制:1027,得到指数: 1027 - 1023 = 4
取尾数位:10111000000000
转科学技术法表示:1.10111000000000 * 24
转二进制:11011.1
转十进制:27.5