JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示。其中符号位 S,指数位 E,尾数位M分别占了 1,11,52 位,并且在 ES5 规范 中指出了指数位E的取值范围是 [-1074, 971]。

精度问题汇总

想用有限的位来表示无穷的数字,显然是不可能的,因此会出现一些列精度问题:

浮点数精度问题,比如 0.1 + 0.2 !== 0.3

大数精度问题,比如 9999 9999 9999 9999 == 1000 0000 0000 0000 1

toFixed 四舍五入结果不准确,比如 1.335.toFixed(2) == 1.33

浮点数精度和 toFixed 其实属于同一类问题,都是由于浮点数无法精确表示引起的,如下:

(1.335).toPrecision(20); // "1.3349999999999999645"

而关于大数精度问题,我们可以先看下面这个代码片段:

// 能精确表示的整数范围上限,S为1个0,E为11个0,S为53个1

Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // true

// 能精确表示的整数范围下限,S为1个1,E为11个0,S为53个1

-(Math.pow(2, 53) - 1) === Number.MIN_SAFE_INTEGER // true

// 能表示的最大数字,S为1个0,E为971,S为53个1

(Math.pow(2, 53) - 1) * Math.pow(2, 971) === Number.MAX_VALUE // true

// 能表示的最接近于0的正数,S为1个0,E为-1074,S为0

Math.pow(2, -1074) === Number.MIN_VALUE // true

通过以上可以明白,[MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] 的整数都可以精确表示,但是超出这个范围的整数就不一定能精确表示。这样就会产生所谓的大数精度丢失问题。

解决思路

首先考虑的是如何解决浮点数运算的精度问题,有 3 种思路:

考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));

将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1*2)/3。

把浮点数转化为字符串,模拟实际运算的过程。

先来看第一种方案,在大多数情况下,它可以得到正确结果,但是对一些极端情况,toFixed 到 12 是不够的,比如:

210000 * 10000 * 1000 * 8.2 // 17219999999999.998

parseFloat(17219999999999.998.toFixed(12)); // 17219999999999.998,而正确结果为 17220000000000

上面的情况,如果想让结果正确,需要 toFixed(2),这显然是不可接受的。

再看第二种方案,比如 number-precision 这个库就是使用的这种方案,但是这也是有问题的,比如:

// 这两个浮点数,转化为整数之后,相乘的结果已经超过了 MAX_SAFE_INTEGER

123456.789 * 123456.789 // 转化为 (123456789 * 123456789)/1000000,结果是 15241578750.19052

所以,最终考虑使用第三种方案,目前已经有了很多较为成熟的库,比如 bignumber.js,decimal.js,以及big.js等。我们可以根据自己的需求来选择对应的工具。并且,这些库不仅解决了浮点数的运算精度问题,还支持了大数运算,并且修复了原生toFixed结果不准确的问题。

题外话

还有另外一个与 JavaScript 计算相关的问题,即 Math.round(x),它虽然不会产生精度问题,但是它有一点小陷阱容易忽略。下面是它的舍入的策略:

如果小数部分大于 0.5,则舍入到下一个绝对值更大的整数。

如果小数部分小于 0.5,则舍入到下一个绝对值更小的整数。

如果小数部分等于 0.5,则舍入到下一个正无穷方向上的整数。

所以,对 Math.round(-1.5),其结果为 -1,这可能不是我们想要的结果。

当然,上面提到的 big.js 等库,都提供了自己的 round 函数,并且可以指定舍入规则,以避免这个问题。

php 精度问题怎么解决,JavaScript 中精度问题以及解决方案相关推荐

  1. 用decimal.js库解决JavaScript中计算精度丢失的问题

    项目场景: 涉及小数点的计算 精度丢失原因看这里 解决 用decimal.js库,decimal.js是使用的二进制来计算的, 所以能解决js的精度问题. 安装和引入 执行命令npm i decima ...

  2. 如何解决JavaScript中0.1+0.2不等于0.3

    原文转载自:https://www.cnblogs.com/weshare/archive/2018/02/20/8455470.html >console.log(0.1+0.2===0.3) ...

  3. 如何提高Python计算浮点数的精度(如何解决Python中浮点数计算误差问题)

    我们可以使用decimal模块来提高python中浮点数计算的精度: 1. 导入decimal模块:import decimal 2. 创建一个Decimal对象:a = decimal.Decima ...

  4. sherlock 例程_如何解决JavaScript中的Sherlock和Anagrams编码难题

    sherlock 例程 This post is going to get you through my solution to a coding challenge called "She ...

  5. 如何解决JavaScript中的根查找

    介绍 (Introduction) I've been wanting to write about this topic for a while now. I recently had the op ...

  6. 解决JavaScript中new Date(string)在IE不兼容的问题

    1.问题描述: let date = '2018.09.17'let dateStr = new Date(date);let year = dateStr.getFullYear();let mon ...

  7. 解决JavaScript中使用$.ajax方式提交数组参数

    一般的,可能有些人在一个参数有多个值的情况下,可能以某个字符分隔的形式传递,比如页面上有多个checkbox: $.ajax{url:"xxxx",data:{p: "1 ...

  8. 解决 Javascript 中 atob 方法解码中文字符乱码问题

    转载地址:http://blog.sqrtthree.com/2015/08/29/utf8-to-b64/ 首先, 为什么要编码? 由于一些网络通讯协议的限制, 又或者是出于信息加密的目的, 我们就 ...

  9. HTML5 完美解决javascript中iphone手机和android手机复制文本到剪切板问题

    1. 执行以下解决方案条件:(这个是原理) ①执行复制方法时 所复制文字不能被任何 块级元素和行内块元素和行内元素遮盖否则无效:(解决方案:将文本通过绝对定位或其他方式移除屏幕外) ②ios中不能复制 ...

最新文章

  1. docker容器虚拟化技术_Docker,虚拟机和容器的全面介绍
  2. 使用HttpClient实现一个简单爬虫,抓取煎蛋妹子图
  3. win10 VS2010 VS studio 生成程序默认管理员运行 此任务要求应用程序具有提升的权限
  4. [Apple开发者帐户帮助]三、创建证书(3)创建企业分发证书
  5. JavaScript——闭包函数及拓展题目
  6. StarkWare推出ZK Rollup扩容解决方案StarkNet
  7. 为什么要用implements Serializable
  8. 减小VirtualBox虚拟硬盘文件的大小
  9. SpringBoot入门第一个简单示例
  10. sqlite 查看数据库表和字段
  11. [ROS2 基础] 仿真系统和搭建方法
  12. 散户通过a股量化数据接口实现自动化实盘交易主要方式有哪些?
  13. 惠普服务器故障代码_HP服务器常见代码
  14. 手机开热点但是电脑一直连接不上_电脑连不上wifi,手机可以连上。手机开热点,电脑可以连上。这是怎么回事,电脑就一直循环连接那个w...
  15. 视频教程-大数据电视收视率实战项目教程(企业级案例)-Spark
  16. Ps如何将图片人物素描画
  17. jsonp无X-Requested-With 及其深扒
  18. 那对职业测评行业如何评价?
  19. python去复杂的水印_两种Python基于OpenCV的固定位置半透明水印去除方案
  20. VLAN与PVLAN的区别

热门文章

  1. python中垃圾回收机制_Python中的变量和垃圾回收机制
  2. mysql批量写入100万数据_Mysql数据库实践操作之————批量插入数据(100万级别的数据)-阿里云开发者社区...
  3. python怎么全选_有没有一种方法可以在Python网页上模拟“全选复制粘贴”?
  4. 【SSM面向CRUD编程专栏 2】Spring相关API 数据源(连接池)的配置 注解开发 整合junit
  5. C++ 定义 string
  6. 2019年春季学期第九周作业
  7. js 判断日期时间差
  8. Linux查看系统cpu个数、核心书、线程数
  9. ITU衡量信息社会报告:我国ICT发展指数进入亚太前十
  10. LNMP/LEMP(PHP7.0.04+mysql5.7.12+nginx1.10.0)