Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.1 + 0.2不等于0.3? #17

Open
TieMuZhen opened this issue Nov 16, 2021 · 0 comments
Open

0.1 + 0.2不等于0.3? #17

TieMuZhen opened this issue Nov 16, 2021 · 0 comments

Comments

@TieMuZhen
Copy link
Owner

TieMuZhen commented Nov 16, 2021

前言

正文

image

JavaScript是如何表示数字的?

JavaScript使用Number类型表示数字(整数和浮点数),遵循 IEEE 754 标准 通过64位来表示一个数字

通过图片具体看一下数字在内存中的表示
image
图片文字说明

  • 第0位:符号位,0表示正数,1表示负数(s)
  • 第1位到第11位:储存指数部分(e)
  • 第12位到第63位:储存小数部分(即有效数字)f

既然说到这里,再给大家科普一个小知识点:js最大安全数是 Number.MAX_SAFE_INTEGER == Math.pow(2,53) - 1, 而不是Math.pow(2,52) - 1, why?尾数部分不是只有52位吗?

这是因为根据浮点数的存储原理,整数位第一位肯定是1,所以这个第一位就可以省略掉。因此多出了1位。(假设第一位是0的话,可以通过移动指数位调整。)

简单验证一下
image

只有 JavaScript 中存在吗?

这显然不是的,这在大多数语言中基本上都会存在此问题(大都是基于 IEEE 754 标准)

JavaScript

console.log(.1 + .2); // 0.30000000000000004

Python

print(repr(.1 + .2)) # 0.30000000000000004

Java

System.out.println(.1 + .2); // 0.30000000000000004

System.out.println(.1F + .2F); // 0.3

怎么解决精度问题?

1、将数字转成整数

function add(num1, num2) {
    const num1Digits = (num1.toString().split('.')[1] || '').length;
    const num2Digits = (num2.toString().split('.')[1] || '').length;
    const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
    return (num1 * baseNum + num2 * baseNum) / baseNum;
}

但是这种方法对大数支持的依然不好
2、三方库
这个是比较全面的做法,推荐2个我平时接触到的库

  • Math.js
    专门为 JavaScript 和 Node.js 提供的一个广泛的数学库。支持数字,大数字(超出安全数的数字),复数,分数,单位和矩阵。 功能强大,易于使用。
    官网:mathjs.org/
  • big.js
    官网:mikemcl.github.io/big.js

不过很多时候,一个函数能解决的问题不需要引用一个类库来解决。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant