浮点数运算不精确的原因和解决方式

1,173 阅读2分钟

前言

我的项目经历中,其实涉及浮点运算的场景基本没有(都是toB的项目),通常也都是后端同学去做这个处理。但如果你和我一样有过想知道为什么怎么解决的念头, 可以花个2分钟继续往下阅读 。希望我的整理可以对你有所帮助

计算机存储

首先:要知道计算机的数据存储方式和单位

  1. 存储方式:数据都是 以2进制来做存储
  2. 存储单位:我们以字节为基本单位存储在计算机中,下面的图片存储在我的电脑占用内存156KB,但基本单位是153,994字节

image.png 3. 单位之间的关系(题外话属于):位-->8位-->1字节 -->1024字节-->1kb-->1024kb-->1m--->2014m--->1t

  1. 计算机中字符的存储,其实是存在位上的

0.1+0.2!==0.3的例子

  1. 网络上的通用答案:原因在于在JS中采用的IEEE 754的双精度标准,计算机内部存储数据的编码的时候,0.1在计算机内部根本就不是精确的0.1,而是一个有舍入误差的0.1。
  2. 答案是这样的没错 但是 它没有告诉我们 为什么 JS中采用的IEEE 754的双精度标准
  3. 背后的原因:一个字节的最大存储的了的数+进制转换不精确

一个字节能存储的最大数值255

let sum = 0;
//用8表示位的数量,我们计算一个字节最多能存储的2进制数值对应的10进制是多大的数
for (let i = 0; i < 8; i++) {
  sum += Math.pow(2, i);
}
console.log(sum); //255却不是256  
//因为11111111 要再加一个1才是 256  所以 一个字节 最大存储就只有255了 2^8 -1

进制转换

  1. 十进制转二进制:取余倒着获取对应的进制,转其他也是一样
  2. 二进制转换十进制 parseInt('101',2)//5
  3. 任意进制转成任意进制:(0x64).toString(2)//16进制转2进制 "1100100"

0.1+0.2 为什么不等于0.3

  1. 那十进制的小数怎么转换2进制表示呢?---乘2取整法
  2. 例子
 //0.1 转成2进制
     0.1*2=0.2 //0
     0.2*2=0.4 //0
     0.4*2=0.8 //0
     0.8*2=1.6 //1
     0.6*2=1.2 //1
     0.1*2=0.2 //0
     0.2*2=0.4 //0
     0.4*2=0.8 //0  一个字节的存储=8个位 最多只能存到第8位这么多
     0.8*2=1.6 //1 这个是多的 但是 会做四舍五入 就进到前面去了 实际0.1的二进制表示:比实际大一丢丢的

//0.2 转成2进制也是同理
  1. 结论0.1+0.2>0.3。 所以 js中的浮点数相加会可能出现精确度的问题(严谨些 因为不是所有的都会出现)

浮点数运算不精确的解决

  1. 思路:字符串切割 然后当整数相加,再拼接回去
  2. 实现
const add=(x,y)=>{
  const a=x.toString().split('.')[1]
   const b=y.toString().split('.')[1]
     console.log(a,b)
   return (Number(a)+Number(b))/
}
 console.log(add(0.1,0.2))//0.3

最后如果觉得本文有帮助 记得点赞三连哦 十分感谢