`

JS中浮点数运算误差处理

 
阅读更多

先来个简单的代码片段:

> console.log(0.1 + 0.2)
> 0.30000000000000004

好奇怪的结果,怎么会是0.30000000000000004呢?难道是Javascript语言的bug还是chrome dev tools的bug?

 

其实,这不是语言的bug或者宿主环境的bug。目前所有的程序设计语言在对浮点数进行四则运算时,都会涉及到浮点数精确度的问题。

 

我们知道在计算机的世界中,计算机只认识0,1,我们传入的十进制数字并不会被计算机直接识别。计算机会先将其转换成二进制,然后使用转换后的二进制进行计算。

 

那么0.1和0.2转换成二进制分别是,

 

(0.1) => 0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 101

(0.2) => 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 01

然后对上面的两个二进制数字做加法,得到的结果是,

 

0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 01

再把这个二进制转换成十进制,就是我们前面的结果0.30000000000000004了。

计算机世界的数值计算基本上都是这个过程,只不过C++、C#、Java这些传统强类型语言将这个边界问题封装在内部了,它们在进行浮点数四则运算时,会在语言层面自动解决这个问题。而Javascript作为一门弱类型的语言,它在语言层面并没有对这个问题进行处理,所以需要我们手动去处理。

 

那么,我们如何去避免这个问题呢?

 

基本上有两种思路。

 

先扩大数值到javascript可精确识别的精度级别(比如个位数级别)然后再进行计算,然后再对结果除以放大的倍数。

在运算的过程中通过toFixed()指定运算的精度要求。

比如我们要计算0.1 + 0.2,按照第一种思路,我们可以这么来做,

 

var a = 0.1;

var b = 0.2;

 

var ret = (a * 10 + b * 10) / 10;

console.log(ret);

这里,我们在计算之前,现将a和b乘以10(放大10倍,当然放大100、1000倍也是可以的),此时a和b已经不再是浮点数了,整数的四则运算当然是不需要考虑精度问题啦。最后我们还需要除以之前放大的倍数,得到正确的最终结果。其实这是一种迂回的办法来规避掉浮点数的四则运算精度问题。

 

按照第二种思路,我们可以这么来做,

 

var a = 0.1;

var b = 0.2;

 

var ret = (a + b).toFixed(1);

var ret = parseFloat(ret);

 

注意toFixed()返回的是一个String,所以我们还需要进行parseFloat或Number操作。

 

附上针对js浮点运算的公共方法:

var util = {

/**
* 加法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcAdd: function(arg1, arg2) {
var r1,r2,m;
try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
m=Math.pow(10,Math.max(r1,r2));
return (arg1*m+arg2*m)/m;
},

/**
* 减法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcSub: function accSub(arg1, arg2) {
var r1,r2,m,n;
try{r1=arg2.toString().split(".")[1].length}catch(e){r1=0}
try{r2=arg1.toString().split(".")[1].length}catch(e){r2=0}
m=Math.pow(10,Math.max(r1,r2));
//last modify by deeka
//动态控制精度长度
n=(r1>=r2)?r1:r2;
return ((arg1*m-arg2*m)/m).toFixed(n);
},

/**
* 乘法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcMul: function accMul(arg1, arg2) {
var m=0,s1=arg1.toString(),s2=arg2.toString();
try{m+=s1.split(".")[1].length}catch(e){}
try{m+=s2.split(".")[1].length}catch(e){}
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);
},

/**
* 除法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcDiv: function accDiv(arg1, arg2) {
var t1=0,t2=0,r1,r2;
try{t1=arg1.toString().split(".")[1].length}catch(e){}
try{t2=arg2.toString().split(".")[1].length}catch(e){}
r1=Number(arg1.toString().replace(".",""));
r2=Number(arg2.toString().replace(".",""));
return (r1/r2)*Math.pow(10,t2-t1);
}

};


简化版:

var util = (function(){
        var getFuncByType = function(typeText){
            return new Function('a', 'b', 'var aR = 0, bR = 0;try{aR = Number(a).toString().split(".")[1].length;}catch(e){}try{bR = Number(b).toString().split(".")[1].length;}catch(e){}return Number((a'+ typeText +'b).toFixed(aR+bR));');
        };
        return {
            // 加
            calcAdd: function(a, b){
                return getFuncByType("+")(a, b);
            },
            // 减
            calcSub: function(a, b){
                return getFuncByType("-")(a, b);
            },
            // 乘
            calcMul: function(a, b){
                return getFuncByType("*")(a, b);
            },
            // 除
            calcDiv: function(a, b){
                return getFuncByType("/")(a, b);
            }
        }
    })();

 

 

分享到:
评论

相关推荐

    详解JS-- 浮点数运算处理

    总结来说,JavaScript中的浮点数运算误差是由于二进制浮点数表示的局限性造成的。通过保留小数位数或转换为整数运算,我们可以有效地解决这个问题。在实际开发中,应根据项目需求选择合适的处理策略,确保计算结果的...

    JS浮点数字操作插件floatOPS.js

    在JavaScript编程中,...总结起来,floatOPS.js是一个专注于解决JavaScript中浮点数运算精度问题的插件,通过提供加减乘除四个方法,确保了在进行浮点数运算时的精度,对于需要精确计算的场景具有很高的实用价值。

    详解JS– 浮点数运算处理

    总的来说,JavaScript中的浮点数运算误差主要源于其内部的二进制表示方式,而通过限制小数位数、转换为整数运算或者使用自定义库,可以一定程度上解决这个问题。在实际应用中,应根据项目需求选择合适的策略,以确保...

    解决javascript中的浮点数计算不精确问题

    5. **使用BigDecimal类**:在某些高级应用中,可以考虑使用类似Java的`BigDecimal`类,它提供了高精度的浮点数运算,但JavaScript原生并不支持,可能需要引入第三方库。 理解JavaScript浮点数计算的局限性并采用...

    js浮点数处理转精确值

    本篇文章将深入探讨如何在JavaScript中处理浮点数,确保得到精确的值。 首先,我们需要了解JavaScript中的浮点数是如何存储的。根据IEEE 754标准,JavaScript使用双精度浮点数(64位)来表示浮点数。这种表示方法...

    解决JS浮点数运算出现Bug的方法

    在JavaScript编程语言中,浮点数运算时常会遇到精度问题,这是因为JS的浮点数表示遵循IEEE 754标准,这种表示方式在处理特定数值时可能会产生微小的误差。例如,`37.5 * 5.5` 在JS中计算的结果并不是预期的 `206.08`...

    JavaScript 浮点数运算 精度问题

    JavaScript中的浮点数运算精度问题是一个常见的编程挑战,主要源于计算机内部表示浮点数的方式。在JavaScript中,浮点数是使用IEEE 754标准进行存储和计算的,这导致了某些运算结果可能并不像预期那样精确。例如,1/...

    深化理解JavaScript中的浮点数_.docx

    这也会导致像加法结合律这样的数学定律在浮点数运算中不成立,例如`(0.1 + 0.2) + 0.3`不等于`0.1 + (0.2 + 0.3)`。 为了处理浮点数的精度问题,一种常见的方法是将浮点运算转换为整数运算。例如,通过乘以适当的...

    解决JS浮点数(小数)计算加减乘除的BUG

    总的来说,理解JavaScript浮点数计算的底层原理以及其可能导致的误差是至关重要的。通过采用适当的策略,如四舍五入、使用高精度库或调整比较方式,可以有效地解决这类问题,确保计算结果的准确性。在实际开发中,...

    JavaScript实现检验除法运算

    总之,JavaScript实现除法运算检验需要考虑除数为零的异常情况,可能的浮点数运算误差,以及输入数据的合法性。通过适当的条件判断和异常处理,我们可以编写出健壮且实用的除法运算检查代码。对于更复杂的需求,还...

    Javascript 浮点数精确计算

    1. **四舍五入**:在进行浮点数运算时,可以设定一定的精度,当结果接近这个精度时进行四舍五入,以达到近似精确的效果。例如,使用`Math.round()`函数或者自定义函数来处理。 2. **使用字符串**:将浮点数转换为...

    js中浮点型运算BUG的解决方法说明.docx

    首先,我们要理解JavaScript中的浮点数运算误差。在计算机内部,浮点数是以二进制形式存储的,但不是所有十进制小数都能精确地转换为二进制。因此,当进行浮点数运算时,如加、减、乘、除,可能会出现看似不合理的...

    Javascript中浮点数相乘的一个解决方法

    为了解决这个问题,程序员们开发出了不同的方法来模拟精确的浮点数运算。文档中提到的“Javascript中浮点数相乘的一个解决方法”,便是这样一种方案。该方法的目的是通过转换浮点数,确保乘法运算的精度。 该方案的...

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

    在JavaScript中处理浮点数计算时,精度误差是一个常见但又必须解决的问题。通过上述方法,我们可以有效地避免这类问题的发生,确保计算结果的准确性。不同的应用场景可能需要采用不同的策略,开发者应根据实际情况...

    JS处理货币格式浮点数插件currency.js.zip

    3. **计算**:支持对货币值进行加减乘除运算,同时确保结果的精度,避免因浮点数运算导致的误差。 4. **本地化**:适应不同的货币格式,如欧元(€)或日元(¥),并且可以处理不同国家的货币符号和分隔习惯。 5....

    JavaScript浮点数及运算精度调整详解

    JavaScript中的浮点数精度问题是由于IEEE-754标准的二进制浮点数表示法导致的,这种表示法无法准确表示所有十进制小数,特别是那些有无限循环二进制小数位的数值,例如0.1。在JavaScript中,所有的数字都以64位双...

    js处理浮点算法

    ### JavaScript 浮点数运算处理方法 在JavaScript中进行数学计算时,经常遇到的一个问题是浮点数运算不精确的问题。这种现象主要是由于计算机内部对于浮点数的存储方式导致的。由于JavaScript使用的是IEEE 754标准...

Global site tag (gtag.js) - Google Analytics