之前在做浮点数计算时,偶然发现计算结果有误差,度娘了解了下,补充整理了下。

误差是什么样子的呢?举例

  1. console.log(0.1+0.2); // 0.30000000000000004

事实上在很多的编程语言当中都存在着或多或少的精度问题,只不过类似于Java这些语言经历这么多年,已经封装好了很多方法来解决这个问题了。而JavaScript是一门弱类型的语言,从设计思想上就没有对浮点数这个严格的数据类型,所以精度误差的问题就较为明显。

产生原因:计算机只能识别二进制的数,所以我们将0.1和0.2转为二进制来看下结果

  1. 0.1 => 0.0001 1001 1001 1001…(无限循环)
  2. 0.2 => 0.0011 0011 0011 0011…(无限循环)

无限循环了,而计算机是不允许无限循环的,所以会进行舍入处理。即使是双精度浮点数,它的小数部分最多也只支持52位,所以两者相加之后会得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

解决方案

1、 指定要保留的小数位数(0.1+0.2).toFixed(1) = 0.3;这个方法toFixed是进行四舍五入的也不是很精准,对于计算金额这种严谨的问题,不推荐使用,而且不同浏览器对toFixed的计算结果也存在差异。

2、把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完毕再降级(除以10的n次幂),这是大部分编程语言处理精度差异的通用方法。

  1. (0.1 * 10 + 0.2 * 10) / 10 == 0.3 // true

在网上看到的一个修复方法

  1. * ** method **
  2. * add / subtract / multiply /divide
  3. *
  4. * ** explame **
  5. * 0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004
  6. * 0.2 + 0.4 == 0.6000000000000001 (多了 0.0000000000001
  7. * 19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002
  8. *
  9. * floatObj.add(0.1, 0.2) >> 0.3
  10. * floatObj.multiply(19.9, 100) >> 1990
  11. *
  12. */
  13. var floatObj = function() {
  14.  
  15. /*
  16. * 判断obj是否为一个整数
  17. */
  18. function isInteger(obj) {
  19. return Math.floor(obj) === obj
  20. }
  21.  
  22. /*
  23. * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100
  24. * @param floatNum {number} 小数
  25. * @return {object}
  26. * {times:100, num: 314}
  27. */
  28. function toInteger(floatNum) {
  29. var ret = {times: 1, num: 0}
  30. if (isInteger(floatNum)) {
  31. ret.num = floatNum
  32. return ret
  33. }
  34. var strfi = floatNum + ''
  35. var dotPos = strfi.indexOf('.')
  36. var len = strfi.substr(dotPos+1).length
  37. var times = Math.pow(10, len)
  38. var intNum = parseInt(floatNum * times + 0.5, 10)
  39. ret.times = times
  40. ret.num = intNum
  41. return ret
  42. }
  43.  
  44. /*
  45. * 核心方法,实现加减乘除运算,确保不丢失精度
  46. * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)
  47. *
  48. * @param a {number} 运算数1
  49. * @param b {number} 运算数2
  50. * @param digits {number} 精度,保留的小数点数,比如 2, 即保留为两位小数
  51. * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)
  52. *
  53. */
  54. function operation(a, b, digits, op) {
  55. var o1 = toInteger(a)
  56. var o2 = toInteger(b)
  57. var n1 = o1.num
  58. var n2 = o2.num
  59. var t1 = o1.times
  60. var t2 = o2.times
  61. var max = t1 > t2 ? t1 : t2
  62. var result = null
  63. switch (op) {
  64. case 'add':
  65. if (t1 === t2) { // 两个小数位数相同
  66. result = n1 + n2
  67. } else if (t1 > t2) { // o1 小数位 大于 o2
  68. result = n1 + n2 * (t1 / t2)
  69. } else { // o1 小数位 小于 o2
  70. result = n1 * (t2 / t1) + n2
  71. }
  72. return result / max
  73. case 'subtract':
  74. if (t1 === t2) {
  75. result = n1 - n2
  76. } else if (t1 > t2) {
  77. result = n1 - n2 * (t1 / t2)
  78. } else {
  79. result = n1 * (t2 / t1) - n2
  80. }
  81. return result / max
  82. case 'multiply':
  83. result = (n1 * n2) / (t1 * t2)
  84. return result
  85. case 'divide':
  86. result = (n1 / n2) * (t2 / t1)
  87. return result
  88. }
  89. }
  90.  
  91. // 加减乘除的四个接口
  92. function add(a, b, digits) {
  93. return operation(a, b, digits, 'add')
  94. }
  95. function subtract(a, b, digits) {
  96. return operation(a, b, digits, 'subtract')
  97. }
  98. function multiply(a, b, digits) {
  99. return operation(a, b, digits, 'multiply')
  100. }
  101. function divide(a, b, digits) {
  102. return operation(a, b, digits, 'divide')
  103. }
  104.  
  105. // exports
  106. return {
  107. add: add,
  108. subtract: subtract,
  109. multiply: multiply,
  110. divide: divide
  111. }
  112. }();
  113.  
  114. // toFixed 修复
  115. function toFixed(num, s) {
  116. var times = Math.pow(10, s)
  117. var des = num * times + 0.5
  118. des = parseInt(des, 10) / times
  119. return des + ''
  120. }

JavaScript浮点数运算的精度问题的更多相关文章

  1. JavaScript 浮点数运算的精度问题

    问题描述 在 JavaScript 中整数和浮点数都属于 Number 数据类型,所有数字都是以 64 位浮点数形式储存,即便整数也是如此. 所以我们在打印 1.00 这样的浮点数的结果是 1 而非 ...

  2. JavaScript 浮点数运算 精度问题

    JavaScript小数在做四则运算时,精度会丢失,这会在项目中引起诸多不便,先请看下面脚本. //加减 <script type="text/javascript" lan ...

  3. 浮点数运算的精度问题:以js语言为例

    在 JavaScript 中整数和浮点数都属于 Number 数据类型,所有数字都是以 64 位浮点数形式储存,即便整数也是如此. 所以我们在打印 1.00 这样的浮点数的结果是 1 而非 1.00  ...

  4. JS007. 深入探讨带浮点数运算丢失精度问题(二进制的浮点数存储方式)

    复现与概述 当JS在进行浮点数运算时可能产生丢失精度的情况: 从肉眼可见的程度上观察,发生精度丢失的浮点数是没有规律的,但该浮点数丢失精度的问题会100%复现.经查阅,这个问题要追溯至浮点数的二进制存 ...

  5. 【转】javascript 浮点数运算问题

    大多数语言在处理浮点数的时候都会遇到精度问题,但是在JS里似乎特别严重,来看一个例子 alert(45.6*13); 结果居然是592.800000000001,当然加法之类的也会有这个问题 那这是j ...

  6. JS 浮点数运算丢失精度解决方案

    除法 function accDiv(arg1,arg2){ var t1=0,t2=0,r1,r2; try{t1=arg1.toString().split(".")[1].l ...

  7. Number浮点数运算详解

    文章来自我的 github 博客,包括技术输出和学习笔记,欢迎star. 一道题 0.1 + 0.2 = ? 在浏览器中测试下计算结果,得到的结果是 0.30000000000000004,并不是理想 ...

  8. JavaScript 浮点数陷阱及解法

    众所周知,JavaScript 浮点数运算时经常遇到会 0.000000001 和 0.999999999 这样奇怪的结果,如 0.1+0.2=0.30000000000000004.1-0.9=0. ...

  9. JavaScript 浮点数处理

    众所周知,JavaScript 浮点数运算时经常遇到会 0.000000001 和 0.999999999 这样奇怪的结果,如 0.1+0.2=0.30000000000000004.1-0.9=0. ...

随机推荐

  1. Preface Numbering序言页码

    题面 (preface.pas/c/cpp) 一类书的序言是以罗马数字标页码的.传统罗马数字用单个字母表示特定的数值,以下是标准数字表: I 1 V 5 X 10 L 50 C 100 D 500 M ...

  2. 苹果IOS内购二次验证返回state为21002的坑

    项目是三四年前的老项目,之前有IOS内购二次验证的接口,貌似很久都没用了,然而最近IOS的妹子说接口用不了,让我看看啥问题.接口流程时很简单的,就是前端IOS在购买成功之后,接收到receipt后进行 ...

  3. Java 读写 excel 实战完全解析

    本文微信公众号「AndroidTraveler」首发. 背景 时值毕业季,很多毕业生初入职场. 因此,这边也写了一些新手相关的 Android 技术点. 比如上一篇的 Android 开发你需要了解的 ...

  4. 通过sysbench工具实现MySQL数据库的性能测试

    1.背景 sysbench是一款压力测试工具,可以测试系统的硬件性能,也可以用来对数据库进行基准测试.sysbench 支持的测试有CPU运算性能测试.内存分配及传输速度测试.磁盘IO性能测试.POS ...

  5. .NET开发框架(八)-服务器集群之网络负载平衡演示(视频)

    (有声视频-服务器集群之负载平衡-NLB演示) 观看NLB视频的童鞋,都会继续观看IIS的负载平衡教程,点击>> 本文以[图文+视频],讲解Windows服务器集群的网络负载平衡NLB的作 ...

  6. Java NIO ByteBuffer 的使用与源码研究

    一.结论 ByteBuffer 是Java NIO体系中的基础类,所有与Channel进行数据交互操作的都是以ByteBuffer作为数据的载体(即缓冲区).ByteBuffer的底层是byte数组, ...

  7. Linux中bash shell环境变量

    别名 别名是命令的快捷方式.为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用.语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令.重要的 ...

  8. sort+结构体+简单数学+暴力-例题

    A-前m大的数 还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大 ...

  9. decode函数的几种用法

    1:使用decode判断字符串是否一样 DECODE(value,if1,then1,if2,then2,if3,then3,...,else) 含义为 IF 条件=值1 THEN RETURN(va ...

  10. java使用栈计算后缀表达式

    package com.nps.base.xue.DataStructure.stack.utils; import java.util.Scanner; import java.util.Stack ...