在JS中 0.1 + 0.2 = 0.30000000000000004 而不是0.3
console.log((0.1).toString(2)) ====>0.0001100110011001100110011001100110011001100110011001101
console.log((1).toString(2)) ====> 1
这是因为js中的浮点数使用IEEE 754标准的双精度浮点数表示
IEEE双精度格式具有53位有效数字精度(包含符号号),并总共占用64位。
双精度二进制小数,使用64个比特存储。
1位
|
11位
|
52位
|
S(符号位),编号63
|
E(阶码位),编号62 ~52
|
M(小数位),编号51 ~ 0
|
0表示正,1表示负
|
−1022~+1023加上1023
|
任意
|
最高位63位是符号位,1表示该数为负,0表示该数为正;
62-52位,一共11位是指数位;
51-0位,一共52位是尾数位。
十进制0.1
=> 二进制0.00011001100110011…(循环0011) ====> 0.1 相当于 1/16+1/32+ 1/256 +1/512 ............
=>尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-4(二进制移码为00000000100),符号位为0
=> 计算机存储为:0 00000000100 10011001100110011…11001
=> 因为尾数最多52位,所以实际存储的值为0.00011001100110011001100110011001100110011001100110011001
而十进制0.2
=> 二进制0.0011001100110011…(循环0011)
=>尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-3(二进制移码为00000000011),符号位为0
=> 存储为:0 00000000011 10011001100110011…11001
因为尾数最多52位,所以实际存储的值为0.00110011001100110011001100110011001100110011001100110011
那么两者相加得:
0.00011001100110011001100110011001100110011001100110011001
+ 0.00110011001100110011001100110011001100110011001100110011 (确认??)
= 0.01001100110011001100110011001100110011001100110011001100
转换成10进制之后得到:0.30000000000000004
解决方法
1 可以奖浮点数化为整数 0.1+0.2 =1+2/10 ; 相当于( a*10+b*10)/10
关于浮点数
浮点数格式使用科学计数法表示实数。科学计数法把数字表示为系数(coefficient)(也称为尾数(mantissa)),和指数 (exponent)两部分。比如 3.684*10^2. 在十进制中,指数的基数为 10,并且表示小数点移动多少位以生成系数。每次小数点向前移动时,指数就递增;
每次小数点向后移动时,指数就递减。例如,25.92 可表示为 2.592 * 10^1,其中 2.592 是系数,值 10^1 是指数。必须把系数和指数相乘,才能得到原始的实数。
另外,如 0.00172 可表示为 1.72*10^-3,数字 1.72 必须和 10^-3 相乘才能获得原始值。
计算机系统使用二进制浮点数,这种格式使用二进制科学计数法的格式表示数值。数字按照二进制格式表示,那么系数和指数都是基于二进制的,而不是十进制,
例如 1.0101*2^2
在十进制里,像 0.159 这样的值,表示的是 0 + (1/10) + (5/100) + (9/1000)。
相同的原则也适用二进制。比如,1.0101 乘以 2^2 后,生成二进制值 101.01 ,这个值表示二进制整数 5,加上分数 (0/2) + (1/4) 。
这生成十进制值 5.25 。下表列出几个二进制小数以及它们对应的十进制值: