zoukankan      html  css  js  c++  java
  • js 浮点数加减总结

    https://blog.csdn.net/qinshenxue/article/details/43671763

    说明
    众所周知,js在计算浮点数时候,结果可能会不准确。比如:(在chrome中的运算结果) 
    2.2 + 2.1 = 4.300000000000001 
    2.2 - 1.9 = 0.30000000000000027 
    2.2 * 2.2 = 4.840000000000001 
    2.1 / 0.3 = 7.000000000000001
    
    网上流传的代码(有bug)
    网上流传的优化后的代码如下(有问题的代码,请勿使用)
    
    function add(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;
        } catch (f) {
            d = 0;
        }
        return e = Math.pow(10, Math.max(c, d)), (a * e + b * e) / e;
    }
    
    function sub(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;
        } catch (f) {
            d = 0;
        }
        return e = Math.pow(10, Math.max(c, d)), (a * e - b * e) / e;
    }
    
    function mul(a, b) {
        var c = 0,
            d = a.toString(),
            e = b.toString();
        try {
            c += d.split(".")[1].length;
        } catch (f) {}
        try {
            c += e.split(".")[1].length;
        } catch (f) {}
        return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
    }
    
    function div(a, b) {
        var c, d, e = 0,
            f = 0;
        try {
            e = a.toString().split(".")[1].length;
        } catch (g) {}
        try {
            f = b.toString().split(".")[1].length;
        } catch (g) {}
        return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), c / d * Math.pow(10, f - e);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    原理就是将浮点数转化为整数来计算。
    
    问题代码测试
    但是上面的优化方法真的解决问题了吗,我们可以简单做下测试。 
    测试代码如下:(测试运算中加法)
    
    function test(){
        var a = (Math.random() * 100).toFixed(2) - 0;
        var b = (Math.random() * 1000).toFixed(2) - 0;
        var result = add(a, b);
        if ((result + '').length > 10) {
            console.error('被加数:'+a,'加数:'+b, '结果:'+result);
            return;
        }
        setTimeout(function() {
            test();
        }, 10);
    }
    test();
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    问题代码测试结果
    浏览器控制台很快就打印了结果,说明被测试的加法运算代码存在运算不准确的问题。 
    测试运行结果: 
    
    
    问题代码出错原因
    既然上面的代码有问题,那么出错的点在哪里,我们就以计算错误的数字来调试代码。 
    被加数:19.36 加数:601.19 结果:620.5500000000001 
    调试的过程及结果如下: 
    
    我们发现原来是其中的乘法计算错误。
    
    修正方法
    网上有一些版本你会发现在最终返回结果的时候加上了toFixed,这是一种解决方法。 
    另外既然是乘法出错,我们何不将乘法换成优化后的乘法了。比如修改后的加法如下:
    
    function add(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;
        } catch (f) {
            d = 0;
        }
        return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    然后用上面的方法进行测试,等了”一天“,控制台也没打印了。说明这次真的把问题解决了。
    
    最终版(正确版)
    function add(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;
        } catch (f) {
            d = 0;
        }
        return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
    }
    
    function sub(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;
        } catch (f) {
            d = 0;
        }
        return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
    }
    
    function mul(a, b) {
        var c = 0,
            d = a.toString(),
            e = b.toString();
        try {
            c += d.split(".")[1].length;
        } catch (f) {}
        try {
            c += e.split(".")[1].length;
        } catch (f) {}
        return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
    }
    
    function div(a, b) {
        var c, d, e = 0,
            f = 0;
        try {
            e = a.toString().split(".")[1].length;
        } catch (g) {}
        try {
            f = b.toString().split(".")[1].length;
        } catch (g) {}
        return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
    }
    --------------------- 
    作者:笔心 
    来源:CSDN 
    原文:https://blog.csdn.net/qinshenxue/article/details/43671763 
    版权声明:本文为博主原创文章,转载请附上博文链接!
  • 相关阅读:
    ASIHTTPRequest系列(一):同步和异步请求
    浅谈SQL Server2005的几种分页方法
    在iphone越狱机器中使用Hook
    iphone4 双击Home键 截获
    xcode中打印毫秒时间
    获得一个不错的电子书翻页效果,和大家分享
    【转】iOS平台XML解析类库对比和安装说明
    xml的sax解析方法
    svn 日常使用技巧以及vim profile的配置
    自制固件iOS4.1刷机、解锁教程
  • 原文地址:https://www.cnblogs.com/beimingbingpo/p/10231495.html
Copyright © 2011-2022 走看看