Skip to content

0.1 + 0.2不等于0.3? #17

Open
Open
@TieMuZhen

Description

@TieMuZhen

前言

正文

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

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions