js float浮点数计算精度问题

/**
 * floatObj 包含加减乘除四个方法,能确保浮点数运算不丢失精度
 *
 * 我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差),其根本原因是二进制和实现位数限制有些数无法有限表示
 * 以下是十进制小数对应的二进制表示
 *      0.1 >> 0.0001 1001 1001 1001…(1001无限循环)
 *      0.2 >> 0.0011 0011 0011 0011…(0011无限循环)
 * 计算机里每种数据类型的存储是一个有限宽度,比如 JavaScript 使用 64 位存储数字类型,因此超出的会舍去。舍去的部分就是精度丢失的部分。
 *
 * ** method **
 *  add / subtract / multiply /divide
 *
 * ** explame **
 *  0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004)
 *  0.2 + 0.4 == 0.6000000000000001  (多了 0.0000000000001)
 *  19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002)
 *
 * floatObj.add(0.1, 0.2) >> 0.3
 * floatObj.multiply(19.9, 100) >> 1990
 *
 */
var floatObj = function() {

    /*
     * 判断obj是否为一个整数
     */
    function isInteger(obj) {
        return Math.floor(obj) === obj;
    }

    /*
     * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100
     * @param floatNum {number} 小数
     * @return {object}
     *   {times:100, num: 314}
     */
    function toInteger(floatNum) {
        var ret = {times: 1, num: 0};
        if (isInteger(floatNum)) {
            ret.num = floatNum;
            return ret;
        }
        var strfi  = floatNum + ‘‘;
        var dotPos = strfi.indexOf(‘.‘);
        var len    = strfi.substr(dotPos+1).length;
        var times  = Math.pow(10, len);
        //var intNum = parseInt(floatNum * times + 0.5, 10); //测试负数会有精度丢失
        var intNum = parseInt(floatNum * times , 10);
        ret.times  = times;
        ret.num    = intNum;
        return ret;
    }

    /*
     * 核心方法,实现加减乘除运算,确保不丢失精度
     * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)
     *
     * @param a {number} 运算数1
     * @param b {number} 运算数2
     * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)
     *
     */
    function operation(a, b, op) {
        var o1 = toInteger(a);
        var o2 = toInteger(b);
        var n1 = o1.num;
        var n2 = o2.num;
        var t1 = o1.times;
        var t2 = o2.times;
        var max = t1 > t2 ? t1 : t2;
        var result = null;
        switch (op) {
            case ‘add‘:
                if (t1 === t2) { // 两个小数位数相同
                    result = n1 + n2;
                } else if (t1 > t2) { // o1 小数位 大于 o2
                    result = n1 + n2 * (t1 / t2);
                } else { // o1 小数位 小于 o2
                    result = n1 * (t2 / t1) + n2;
                }
                return result / max;
            case ‘subtract‘:
                if (t1 === t2) {
                    result = n1 - n2;
                } else if (t1 > t2) {
                    result = n1 - n2 * (t1 / t2);
                } else {
                    result = n1 * (t2 / t1) - n2;
                }
                return result / max;
            case ‘multiply‘:
                result = (n1 * n2) / (t1 * t2);
                return result
            case ‘divide‘:
                result = (n1 / n2) * (t2 / t1);
                return result;
        }
    }

    // 加减乘除的四个接口
    function add(a, b) {
        return operation(a, b, ‘add‘);
    }
    function subtract(a, b) {
        return operation(a, b, ‘subtract‘);
    }
    function multiply(a, b) {
        return operation(a, b, ‘multiply‘);
    }
    function divide(a, b) {
        return operation(a, b, ‘divide‘);
    }
    // 如果是整数,就不会保留小数点,只保留小数点超过指定位数的情况
    function toFixed(num, digits) {
        var times = Math.pow(10, digits);
        var des = num * times;
        return parseInt(des, 10) / times;
    }

    // exports
    return {
        add: add,
        subtract: subtract,
        multiply: multiply,
        divide: divide,
        toFixed: toFixed
    }
}();

另一种方案可参考:https://github.com/MikeMcl/big.js 
时间: 2025-01-06 02:27:14

js float浮点数计算精度问题的相关文章

js中浮点数的精度问题

JS中浮点数的精度问题 value = parseFloat((value.toFixed(2))).toLocaleString(); //大于1的数值没有问题,小于1的,个位数的0会丢失,如:0.1,转换之后:.1 function accAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} try{r2=arg2.toString().split("

关于js浮点数计算精度不准确问题的解决办法

今天在计算商品价格的时候再次遇到js浮点数计算出现误差的问题,以前就一直碰到这个问题,都是简单的使用tofixed方法进行处理一下,这对于一个程序员来说是及其不严谨的.因此在网上收集了一些处理浮点数精度的文章.觉得别人写的挺好了,我在简单的总结一下,以方便后续查阅. 浮点数误差产生的原因: 先看一个实例: 0.1 + 0.2 =? 0.1 + 0.2 = 0.3? 我们先来看一段 JS. console.log( 0.1+ 0.2); 输出为 0.30000000000000004.是不是很奇葩

js浮点金额计算精度

在js中进行以元为单位进行浮点数计算时,会产生精度问题,例如: console.log(0.1+0.2) 结果为:0.30000000000000004 大多数编程语言计算采用的是IEEE 754 标准,那么先来看下浮点数运算产生误差的原因,拿0.1+0.2=0.30000000000000004举例. 首先,站在计算机的角度思考 0.1 + 0.2 这个问题.我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制看看: 0.1 => 0.0001 10

js浮点数精度丢失问题及如何解决js中浮点数计算不精准

js中进行数字计算时候,会出现精度误差的问题.先来看一个实例: console.log(0.1+0.2===0.3);//false console.log(0.1+0.1===0.2);//true 上面第一个的输出会超出我们的常识,正常应该为true,这里为什么会是false呢,直接运行会发现0.1+0.2在js中计算的结果是: console.log(0.1+0.2);//输出0.30000000000000004 这对于浮点数的四则运算(加减乘除),几乎所有的编程语言都会出现上面类似的精

js 浮点小数计算精度问题 parseFloat 精度问题

在js中进行以元为单位进行金额计算时 使用parseFloat会产生精度问题var price = 10.99;var quantity = 7;var needPay = parseFloat(price * quantity); needPay的正确结果应该是76.93元  但是运行后发现needPay为76.93000000000001 此情况可通过 toFixed(n)  方法修正 但是这个方法对 js版本要求较高 不能兼容ie5 另一个解决方案是: 将元为单位的金额乘以100换算为分进

解决JavaScript浮点数计算精度问题

之前在使用JS开发过程中发现计算某些浮点数的时候,出现了精度问题 ! 导致出现了一些错误 ! 比如: 0.1 + 0.2 = 0.30000000000000004 计算结果并不是我们想要的结果 0.3 刚开始发现的时候我也很纳闷, 这是怎么出现的 ? 后面去百度了一下,才知道原来是由于某些浮点数不能精确的转换成二进制造成的 ! 1. 那么 如何将小数转换成二进制呢? 1) 整数部分:除二取余,然后倒序排列,高位补零 2) 小数部分:小数部分乘以2,取整数部分依次从左往右放在小数点后,直至小数点

php float浮点数的精度问题

<?php $v1 = 0.1; $v2 = 0.2; $v3 = 0.3; echo $v1+$v2 == $v3 ?'相等':'不相等';//这里输出不相等,因为0.3的进制是无穷的,所以不相等,里面还有很深的学问,这里就不说了! //如何让他们相等? echo round(($v1+$v2)*10000) == round($v3*10000) ?'相等':'不相等';//让他们乘以1w然后就不是浮点数了,然后在四舍五入,手动给他精确到位. 输出 '相等'; 原文地址:https://ww

关于JS数学计算精度不准和自动转科学计数法的问题

在javaScript中,数学计算是一个很坑爹的问题, 由于系统二进制转十进制的误差,导致浮点数的运算精度很不理想,经常会出现一些意想不到的问题. 而js自动将小数转为科学计数法的问题,也让一些自己写数学插件的同学痛苦不已. 第一个,浮点数计算精度: 比如:1.2*3 = 3.599999999.... 解决办法: ⑴将浮点数乘以10的n次幂化为整数,再进行计算,之后再除以10的n次幂,就可以得到我们想要的数值.即:1.2*3 = 12*3/10 = 3.6;(n为小数点后数位之和); 至于多个

关于js中计算精度的问题解决办法

/** * 解决js中浮点数的精度问题 * @parem f 要精度的值 * @parem digit 要精确的位数 * */ var htmlObj = {};htmlObj.formatFloat = function(f, digit) { var m = Math.pow(10, digit);//Math.pow(x,y)返回 x 的 y 次幂的值 return parseInt(f * m, 10) / m;};