`

JavaScript 精度丢度丢失

 
阅读更多

Snandy

If you cannot hear the sound of the genuine in you, you will all of your life spend your days on the ends of strings that somebody else pulls.

JavaScript数字精度丢失问题总结

本文分为三个部分

  1. JS 数字精度丢失的一些典型问题
  2. JS 数字精度丢失的原因
  3. 解决方案(一个对象+一个函数)

 

一、JS数字精度丢失的一些典型问题

 

1. 两个简单的浮点数相加

1
0.1 + 0.2 != 0.3 // true

 

Firebug

这真不是 Firebug 的问题,可以用alert试试 (哈哈开玩笑)。

 

看看Java的运算结果

 

再看看Python

 

2. 大整数运算

1
9999999999999999 == 10000000000000001 // ?

Firebug

16位和17位数竟然相等,没天理啊。

 

又如

1
2
var x = 9007199254740992
x + 1 == x // ?

看结果

三观又被颠覆了。

 

3. toFixed 不会四舍五入(Chrome)

1
1.335.toFixed(2) // 1.33

Firebug

 

线上曾经发生过 Chrome 中价格和其它浏览器不一致,正是因为 toFixed 兼容性问题导致

 

二、JS 数字丢失精度的原因

计算机的二进制实现和位数限制有些数无法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926...,1.3333... 等。JS 遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit。如图

 

意义

  • 1位用来表示符号位
  • 11位用来表示指数
  • 52位表示尾数

 

浮点数,比如

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

此时只能模仿十进制进行四舍五入了,但是二进制只有 0 和 1 两个,于是变为 0 舍 1 入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。

 

大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。

大于 9007199254740992 的可能会丢失精度

1
2
3
9007199254740992     >> 10000000000000...000 // 共计 53 个 0
9007199254740992 + 1 >> 10000000000000...001 // 中间 52 个 0
9007199254740992 + 2 >> 10000000000000...010 // 中间 51 个 0

 

实际上

1
2
3
4
9007199254740992 + 1 // 丢失
9007199254740992 + 2 // 未丢失
9007199254740992 + 3 // 丢失
9007199254740992 + 4 // 未丢失

 

结果如图

 

以上,可以知道看似有穷的数字, 在计算机的二进制表示里却是无穷的,由于存储位数限制因此存在“舍去”,精度丢失就发生了。

想了解更深入的分析可以看这篇论文(又长又臭):What Every Computer Scientist Should Know About Floating-Point Arithmetic

 

三、解决方案

对于整数,前端出现问题的几率可能比较低,毕竟很少有业务需要需要用到超大整数,只要运算结果不超过 Math.pow(2, 53) 就不会丢失精度。

对于小数,前端出现问题的几率还是很多的,尤其在一些电商网站涉及到金额等数据。解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)

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

  

以下是我写了一个对象,对小数的加减乘除运算丢失精度做了屏蔽。当然转换后的整数依然不能超过 9007199254740992。

例如

28613750103206269 + 1 == 28613750103206269

 

toFixed的修复如下

1
2
3
4
5
6
7
// toFixed 修复
function toFixed(num, s) {
    var times = Math.pow(10, s)
    var des = num * times + 0.5
    des = parseInt(des, 10) / times
    return des + ''
}
分享到:
评论

相关推荐

    关于javascript精度问题解决

    NULL 博文链接:https://hejie084.iteye.com/blog/1260556

    javascript解决小数的加减乘除精度丢失的方案

    在JavaScript开发中,处理小数加减乘除运算时经常会遇到精度丢失的问题。由于JavaScript中的数字是以IEEE 754标准的双精度64位浮点数来表示的,这就意味着它可以精确地表示的整数范围大约在-***到***之间。当超出这...

    javascript小数精度丢失的完美解决方法

    在使用JavaScript进行小数运算时,由于JavaScript的内部运算规则是基于二进制实现的,而大多数小数在转换为二进制形式时无法精确表示,这就导致了小数运算时可能出现精度丢失的问题。例如,当执行0.3*1的运算时,...

    javascript小数精度丢失的完美解决方法.docx

    ### JavaScript小数精度丢失的完美解决方法 #### 引言 在JavaScript中处理浮点数时,经常会遇到小数精度丢失的问题。这是由于JavaScript内部使用的是64位浮点数格式(即IEEE 754标准)来表示数值,而这种格式在...

    浅谈JavaScript中小数和大整数的精度丢失_.docx

    JavaScript中的数字类型主要基于IEEE 754标准的双精度64位浮点数格式进行存储,这在处理小数和大整数时会导致精度丢失问题。本文将深入探讨这两个问题及其背后的原理。 首先,最大整数问题。JavaScript能够表示的...

    解决JavaScript数字精度丢失问题的方法

    JS 数字精度丢失的一些典型问题 JS 数字精度丢失的原因 解决方案(一个对象+一个函数) 一、JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 0.1 + 0.2 != 0.3 // true 这真不是 Firebug 的问题,可以用...

    javascript解决小数的加减乘除精度丢失的方案.docx

    ### JavaScript 解决小数加减乘除精度丢失的方案 #### 一、引言 在JavaScript中处理小数运算时,经常会遇到一个令人头疼的问题——精度丢失。这主要是因为JavaScript中的数字采用IEEE 754标准下的双精度64位浮点数...

    js加减乘除丢失精度问题解决方法

    代码如下: /** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失。 * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var baseNum, baseNum1, baseNum2; try { baseNum

    Java Double 精度问题总结

    虽然 `double` 提供了相对较高的精度,但在涉及精确数学运算(特别是涉及到小数值)时,由于其内部采用二进制浮点数格式存储,仍会出现精度丢失的情况。这种精度丢失的现象对于需要高精度计算的应用来说是一个常见的...

    javascript避免数字计算精度误差的方法详解

    双精度浮点数小数部分最多只能表示52位,所以当进行加法运算时,超出部分就会丢失,导致最终结果为0.***而非0.3。 为了解决这个问题,文中提出了几种方法: 1. 使用四舍五入:可以通过`.toFixed()`方法对结果进行四...

    JavaScript小数点精确计算

    由于JavaScript内部使用的是IEEE 754标准来存储和处理浮点数,这可能导致在进行小数运算时出现精度丢失问题,尤其是在涉及大数字或者循环计算时。本篇将深入探讨这个问题,并提供一些解决方案。 首先,我们来理解...

    完美解决方案-雪花算法ID到前端之后精度丢失问题.docx

    然后,我们想到可能是精度丢失的问题,并最终发现是JavaScript中的Number类型精度限制所导致的。 三、解决问题 解决问题的思路是使用Jackson将Long类型的ID转换为String类型,然后将其传输到前端。在前端,可以...

    详解JavaScript中精度失准问题及解决方法

    然而,对于更大但仍然可以表示的数字,如果涉及到精确计算,可能会遇到问题,因为超过了53位有效二进制数的限制,会导致精度丢失。为了定义一个可安全进行算术运算的数字范围,JavaScript提供了`Number.MAX_SAFE_...

    js Math.js bigNumber可以解决js运算精度丢失问题

    使用示例: math.config({ number:'BigNumber' }) let result=math.parser().eval(a+ "-" + b); //a,b是需要计算的值,中间是运算符

    gson ajax 数字精度丢失问题的解决方法

    要解决数字精度丢失问题,可以使用以下方法:直接把属性为长整型(long)的属性自动加上双引号成为 JavaScript 字符串,这样就不会发生丢失了,Ajax 自动识别为字符串。 例如,可以使用以下代码来解决数字精度丢失...

    JS大坑之19位数的Number型精度丢失问题详解

    JavaScript中的Number类型在处理大整数时存在精度丢失的问题,特别是在涉及19位或更多位数的整数时。这是由于JavaScript的浮点数表示方式(IEEE 754双精度浮点数)所限制的。JavaScript能精确表示的最大整数是2的53...

    JavaScript 精确计算(2)

    1. **浮点数的不精确性**:JavaScript中的数字是基于IEEE 754标准的双精度浮点数(64位),这意味着在处理大数或小数时可能会丢失精度。例如,0.1 + 0.2 !== 0.3,因为它们在二进制下无法精确表示。 2. **...

    浅谈JavaScript中小数和大整数的精度丢失

    然而,由于双精度浮点数的结构限制,JavaScript中的小数(尤其是不能用有限二进制精确表示的小数,如0.1和0.2)和大整数(超过52位的二进制数)常常面临精度丢失的问题。 对于小数的精度丢失问题,由于尾数位数有限...

Global site tag (gtag.js) - Google Analytics