js浮点数加减乘除

js浮点数加减乘除

js浮点数的加减乘除存在着严重的bug,例如:在google浏览器下,0.1+0.2=0.30000000000000004;这完全不是我们想要的结果。

对于这一问题的解决方案就是重写浮点数的加减乘除方法,其原理是现将浮点数转换为整数。进行加减乘数,再除以相应的倍数,使之成为对应的浮点数结果。

原理

浮点数的加减乘数之所以会出现bug,跟javascript的精度有关,js中所有数字都是以64位的浮点数形式存储的,包括整数也是如此。只是整数的计算时会现将浮点数形式的整数转化为32位的整数。浮点数由于位运算而导致不够精确。

1===1.0 //true

js中数字的64位二进制存储形式如下:

  • 第1位:符号位,0表示正数,1表示负数
  • 第2位到第12位:指数部分
  • 第13位到第64位:小数部分(即有效数字)

所以,js数值的范围为:Math.pow(2, -1023)Math.pow(2, 1024)。(1024 = 2的11次方,11为指数位数)
数值的精度范围为:-Math.pow(2, 53)+1Math.pow(2, 53)-1。(符号位+有效位数为53)

Math.pow(2, 53)===9007199254740992

在精度范围内的整数都可以表示,超出该范围的的将无法保证精度。例如:

9007199254740992111
//9007199254740992000,最后3位的精度丢失了。

Math.pow(2, 53) + 1
// 9007199254740992

Math.pow(2, 53) + 2
// 9007199254740994

Math.pow(2, 53) + 3
// 9007199254740996

Math.pow(2, 53) + 4
// 9007199254740996

对于超出精度范围数字的处理,这里暂不介绍,可以大概说一下思路:因为最大精度只能表示16位数字,所以对超出精度范围的数字可以做截取处理,以15位数字为一个单位,将一个大数据分为几个部分,这几个部分组合起来表示这个大数据。至于大数据的加减乘除,肯定也需要重写的,网上有封装好的工具。

解决方案

网上有很多关于浮点数加减乘数的方法,我大致看了一下,都存在或多或少的问题。下面贴上我的代码:

//小数乘法
export const floatMul = (a, b) => {
    let m = 0, n = 0,              //记录a,b的小数位数
        d = a + "",                  //字符串化
        e = b + "";
    try {
        m = d.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    try {
        n = e.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    let maxInt = Math.pow(10, m + n); //将数字转换为整数的最大倍数
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / maxInt;
}

//小数加法
export const floatAdd = (a, b) => {
    let m = 0, n = 0,              //记录a,b的小数位数
        d = a + "",                  //字符串化
        e = b + "";
    try {
        m = d.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    try {
        n = e.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    let maxInt = Math.pow(10, Math.max(m, n)); //将数字转换为整数的最大倍数
    return (floatMul(a, maxInt) + floatMul(b, maxInt)) / maxInt;
}

//小数减法
export const floatSub = (a, b) => {
    let m = 0, n = 0,              //记录a,b的小数位数
        d = a + "",                  //字符串化
        e = b + "";
    try {
        m = d.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    try {
        n = e.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    let maxInt = Math.pow(10, Math.max(m, n)); //将数字转换为整数的最大倍数
    return (floatMul(a, maxInt) - floatMul(b, maxInt)) / maxInt;
}

//小数除法
export const floatDivision = (a, b) => {
    let m = 0, n = 0,              //记录a,b的小数位数
        d = a + "",                  //字符串化
        e = b + "";
    try {
        m = d.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    try {
        n = e.split(".")[1].length;
    } catch (error) {
        console.log(error)
    }
    let maxInt = Math.pow(10, Math.max(n, m)); //将数字转换为整数的最大倍数
    let aInt = floatMul(a, maxInt);
    let bInt = floatMul(b, maxInt);
    return aInt / bInt;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值