Javascript浮点运算问题及简单办法

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/Ruffaim/article/details/82789133

问题描述

在 JavaScript 中整数和浮点数都属于 Number 数据类型,所有数字都是以 64 位浮点数形式储存,即便整数也是如此。 所以我们在打印 1.00 这样的浮点数的结果是 1 而非 1.00 。在一些特殊的数值表示中,例如金额,这样看上去有点变扭,但是至少值是正确了。然而要命的是,当浮点数做数学运算的时候,你经常会发现一些问题,举几个例子:

// 加法 =====================
// 0.1 + 0.2 = 0.30000000000000004
// 0.7 + 0.1 = 0.7999999999999999
// 0.2 + 0.4 = 0.6000000000000001
// 2.22 + 0.1 = 2.3200000000000003
// 减法 =====================
// 1.5 - 1.2 = 0.30000000000000004
// 0.3 - 0.2 = 0.09999999999999998
// 乘法 =====================
// 19.9 * 100 = 1989.9999999999998
// 19.9 * 10 * 10 = 1990
// 1306377.64 * 100 = 130637763.99999999
// 1306377.64 * 10 * 10 = 130637763.99999999
// 0.7 * 180 = 125.99999999999999
// 9.7 * 100 = 969.9999999999999
// 39.7 * 100 = 3970.0000000000005
// 除法 =====================
// 0.3 / 0.1 = 2.9999999999999996
// 0.69 / 10 = 0.06899999999999999

出现原因

JavaScript 里的数字是采用 IEEE 754 标准的 64 位双精度浮点数。该规范定义了浮点数的格式,对于64位的浮点数在内存中的表示,最高的1位是符号位,接着的11位是指数,剩下的52位为有效数字,具体:

第0位:符号位, s 表示 ,0表示正数,1表示负数;
第1位到第11位:储存指数部分, e 表示 ;
第12位到第63位:储存小数部分(即有效数字),f 表示。

符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。 IEEE 754规定,有效数字第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字总是1.xx…xx的形式,其中xx…xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript提供的有效数字最长为53个二进制位(64位浮点的后52位+有效数字第一位的1)。


简单的解决办法

  1. 使用Math.js
    Math.js 强大的Javascript 和 Nodejs 数学库
  2. 自己封装函数(简单封装了一下加减乘除)
// Float.js 代码写的很详细 容易理解
    class Float {
        constructor() {
            console.log(this);
        }

        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)), (this.multiply(a, e) + this.multiply(b, e)) / e;
        }

        subtract(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)), (this.multiply(a, e) - this.multiply(b, e)) / e;
        }

        multiply(a, b) {
            let 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);
        }

        divide(a, b) {
            let c, d, e ,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(".", "")), this.multiply(c / d, Math.pow(10, f - e));
        }
    }

    module.exports = Float;
// 可在浏览器或者NodeJS 引入 Float.js 需要ES5版本以上支持
const Float = require('./float');
const float = new Float();

console.log(float.add(0.1,0.2)); //0.3
console.log(float.subtract(0.1,0.2)); //-0.1
console.log(float.multiply(0.1,0.2)); //0.02
console.log(float.divide(0.1,0.2)); //0.5

猜你喜欢

转载自blog.csdn.net/Ruffaim/article/details/82789133