美文网首页
js大数运算,浮点型运算,精度问题

js大数运算,浮点型运算,精度问题

作者: 沙克阿拉卡 | 来源:发表于2020-07-24 18:20 被阅读0次

一、js大数运算

       js大数运算的精度问题,以太坊最小单位精度限制是10的18次方,由于js代码处理超过16位的数字时会损失精度,这个时候可以用大整数字符串运算来得出数字字符串,用于运算。记录于此。

可以用字符串的方法进行相加,代码如下:

function sumStrings(a,b){
    var res='', c=0;
    a = a.split('');
    b = b.split('');
    while (a.length || b.length || c){
        c += ~~a.pop() + ~~b.pop();
        res = c % 10 + res;
        c = c>9;
    }
    return res.replace(/^0+/,'');
}

sumStrings('99999999999999999','9'); // "100000000000000008"

字符串进行相减,代码如下:

function minusString(a, b){
    a = a.split('');
    b = b.split('');
    var aMaxb = a.length > b.length; // 标记A是否大于B
    if(a.length == b.length)
    {
        for(var i=0, len=a.length; i<len; i++)
        {
            if(a[i] == b[i]) continue;
            aMaxb = a[i] > b[i];
            break;
        }
    }
    if(!aMaxb){
        a = [b, b = a][0]; // 只要A不比B大都交换
    } 
    var result = '';
    while(a.length)
    {
        var temp = parseInt(a.pop()) - parseInt(b.pop() || 0);
        if(temp >= 0) {
            result = temp + result;
        } else{
            result = temp + 10 + result;
            a[a.length-1]--; // 由于已经保证了a一定大于等于b,所以不存在a[i-1]为undefined的情况
        }
    }
    var resultEnd = (aMaxb?'':'-') + result.replace(/^0*/g, '');// 去掉前面可能的无效0
    if(resultEnd === '-'){
        resultEnd = '0'
    }
    return resultEnd; 
}

minusString('100000000000000000', '8')//"99999999999999992"
minusString('99999999999999992', '100000000000000000')//"-8"

大整数相乘:

function multiString(a,b){
   var str1,str2,len1,len2,maxlen,result = [];
    str1 = a.split("").reverse();
    str2 = b.split("").reverse();
    len1 = str1.length;
    len2 = str2.length;

    for(var i = 0;i < len1;i++){
        for(var j = 0;j < len2;j++){
            result[i + j] = 0;
        }
    }
    for(var i = 0;i < len1;i++){
        for(var j = 0;j < len2;j++){
            result[i + j] += parseInt(str1[i]) * parseInt(str2[j]);
        }
    }
    var n = result.length;
    for(var k = 0;k < n;k++){
        var temp = result[k];
        if(temp >= 10)
        {
            result[k] = temp % 10;
            if(result[k + 1] === undefined){
                result[k + 1] = 0;
            }
            result[k + 1] +=  Math.floor(temp / 10);
        }
    }
    return result.reverse().join("");
}

multiString('50000000000000000','2')//"100000000000000000"

字符串乘以10的n次方:

function multiPowerString(str,s){
    var resData = '';
    if(str&&str!==''){
        var strArr = str.split('.');
        if(strArr.length===1){
            resData = strArr[0];
            for(var i=0;i<s;i++){
                resData = resData + '0';
            }
        }else if(strArr.length===2){
            var l = strArr[1].length;
            var cha = l-s;
            if(cha>=0){
                resData = strArr[1];
                resData = resData.substring(0,l-cha)+'.'+resData.substring(l-cha);
                resData = strArr[0] + resData;
            }else{
                resData = strArr[1];
                for(var i=0;i<-cha;i++){
                    resData = resData + '0';
                }
                resData = strArr[0] + resData;
            }
        }
        //去除多余的0
        var res_ = resData;
        if(res_.indexOf('.')!==-1){
            for(var i=0;i<res_.length;i++){
                if(res_[res_.length-1-i]=='0'){
                    resData = res_.slice(0,res_.length-1-i);
                }else if(res_[res_.length-1-i]=='.'){
                    resData = res_.slice(0,res_.length-1-i);
                    break
                }else{
                    break
              }
           }
        }
        res_ = resData;
        for(var i=0;i<res_.length;i++){
            if(res_[i]=='0'){
                resData = res_.slice(i+1);
            }else if(res_[i]=='.'){
                resData = '0'+res_.slice(i);
                break;
            }else{
                break;
            }
        }
    }
    return resData;
}

multiPowerString('1234567',10)//"12345670000000000"
multiPowerString('0.1234567',2)//12.34567

字符串除以10的n次方:

 function dividePowerString(num,s){
     var l = num.length;//获取字符串长度
     var res = '';
     if(l==(s+1)){
         res = num;
         res = res.slice(0,1) + '.' + res.slice(1);;
     }else if(l<(s+1)){
         var zero = '';
         while(s - l !== zero.length){
         zero = zero + '0';
         }
         res = '0.'+zero+num;
     }else if(l>=(s+1)){
         var a = l-s;
         res = num;
         res = res.slice(0,a) + '.' + res.slice(a);
     }
     //去多余的0
     var res_ = res;
     for(var i=0;i<res_.length;i++){
         if(res_[res_.length-1-i]=='0'){
            res = res_.slice(0,res_.length-1-i);
         }else if(res_[res_.length-1-i]=='.'){
            res = res_.slice(0,res_.length-1-i);
            break
         }else{
            break
         }
     }
     return res;
 }

dividePowerString('1234567',18)//"0.000000000001234567"

精度缺失导致大整数在十六进制转换上也会有精度缺失。下面的方法来转换成十六进制字符串。

function str2hex(str){
    var dec = str.toString().split(''), sum = [], hex = [], i, s
    while(dec.length){
        s = 1 * dec.shift()
        for(i = 0; s || i < sum.length; i++){
            s += (sum[i] || 0) * 10
            sum[i] = s % 16
            s = (s - sum[i]) / 16
        }
    }
    while(sum.length){
        hex.push(sum.pop().toString(16))
    }
    return hex.join('')
}

str2hex('100000000000000000')//"16345785d8a0000"

二、js浮点数运算

       大多数语言在处理浮点数的时候都会遇到精度问题,换算比特币余额的时候又遇到了。比特币最小单位聪的精度限制是10的8次方,转账0.0003的时候,js中0.0003*100000000 会等于29999.999999999996,出现精度问题。

以下js自定义函数,直接调用即可:
//说明:javascript的运算结果会有误差,在两个浮点数加减乘除运算的时候会比较明显。下面函数返回较为精确的运算结果。 
//加法函数
//调用:accAdd(arg1,arg2) 
//返回值:arg1加上arg2的精确的相加结果 
function accAdd(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 
} 

//减法函数
//调用:accSub(arg1,arg2) 
//返回值:arg1减去arg2的精确的相减结果 
function accSub(arg1,arg2){
    var r1,r2,m,n;
    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));
    //动态控制精度长度
    n=(r1>=r2)?r1:r2;
    return ((arg1*m-arg2*m)/m).toFixed(n);
}

//除法函数
//调用:accDiv(arg1,arg2) 
//返回值:arg1除以arg2的精确的相除结果 
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){} 
    with(Math){ 
        r1=Number(arg1.toString().replace(".","")) 
        r2=Number(arg2.toString().replace(".","")) 
        return (r1/r2)*pow(10,t2-t1); 
    } 
} 

//乘法函数
//调用:accMul(arg1,arg2) 
//返回值:arg1乘以arg2的精确的相乘结果 
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) 
} 

另:如果浮点数的小数部分位数已知,可以通过将浮点数放大到整形,运算后在除以放大的倍数,也可得到正确的结果,此方法可用于检测,不推荐使用。

相关文章

  • js大数运算,浮点型运算,精度问题

    一、js大数运算 js大数运算的精度问题,以太坊最小单位精度限制是10的18次方,由于js代码处理超过16位的数字...

  • JavaScript 浮点运算精度问题

    JavaScript 浮点运算精度问题 JavaScript浮点运算存在精度问题,本文阐述问题的产生原因以及解决方...

  • 计算机组成原理:浮点精度运算不精确的原因

    为什么浮点精度运算会有问题 我们平常使用的编程语言大多都有一个问题——浮点型精度运算会不准确。比如 笔者在测试的时...

  • JS浮点型的运算精度问题

    精度问题 大家一定遇到过这种问题: 这真是一个令人黯然蛋碎的bug,而且即使在es6时代依然没能解决,怎么办呢?只...

  • javaScript-02

    运算符 算数运算符 概念:算术运算使用的符号,用于执行两个变量或值的算术运算。 浮点数的精度问题浮点数值的最高精度...

  • 使用underscorejs解决js的大数问题

    js的浮点运算存在精度问题原因:js对于number类型的数使用的是IEEE754标准中的双精度数存储,总共64位...

  • iOS开发浮点数计算精度问题

    1、浮点数运算带来的问题 在日常工作中涉及到浮点数(float、double)的运算 2、浮点数运算精度的解决方案...

  • 【JAVA基础】精度问题

    1. 问题由来 浮点型变量在进行计算的时候会出现丢失精度的问题,如: Java中进行浮点数运算的时候,会出现丢失精...

  • js中计算失去精度问题

    不仅仅在js 中,其他语言中 浮点型的运算都会出现 丢失精度问题,没有遇到过的自己去实验一下 解决办法 --- d...

  • Javascript 盲点

    1.javestript 中所有的数字都是浮点型 js在浮点数运算时会出现多位小数的不准确结果,浮点数运算的误差。...

网友评论

      本文标题:js大数运算,浮点型运算,精度问题

      本文链接:https://www.haomeiwen.com/subject/kqjslktx.html