您当前位置:首页 > 文章中心 > SCSCMS

javascript公式计算引擎-解决浮点数计算误差

稿件来源: 阳光企业网站管理系统   撰稿作者: 太阳光   发表日期: 2015-07-15   阅读次数: 376   查看权限: 游客查看

我们大家都知道,javascript在计算公式的时候,会出现误差,导致我们本来就应该正确的代码,出现了我们意想不到的结果。

例如:

45.6*13=592.8000000000001(结果应该是592.8);
0.7+0.1=0.7999999999999999(应该是0.8);
//还有N多,在此不一一列举。

网上有一个比较认可的解决方法,就是自己去写加法,减法,乘法,除法。

例如:

// 两个浮点数求和
    function accAdd(num1,num2){
       var r1,r2,m;
       try{
           r1 = num1.toString().split('.')[1].length;
       }catch(e){
           r1 = 0;
       }
       try{
           r2=num2.toString().split(".")[1].length;
       }catch(e){
           r2=0;
       }
       m=Math.pow(10,Math.max(r1,r2));
       // return (num1*m+num2*m)/m;
       return Math.round(num1*m+num2*m)/m;
    }
     
    // 两个浮点数相减
    function accSub(num1,num2){
       var r1,r2,m;
       try{
           r1 = num1.toString().split('.')[1].length;
       }catch(e){
           r1 = 0;
       }
       try{
           r2=num2.toString().split(".")[1].length;
       }catch(e){
           r2=0;
       }
       m=Math.pow(10,Math.max(r1,r2));
       n=(r1>=r2)?r1:r2;
       return (Math.round(num1*m-num2*m)/m).toFixed(n);
    }
    // 两浮点数相除
    function accDiv(num1,num2){
       var t1,t2,r1,r2;
       try{
           t1 = num1.toString().split('.')[1].length;
       }catch(e){
           t1 = 0;
       }
       try{
           t2=num2.toString().split(".")[1].length;
       }catch(e){
           t2=0;
       }
       r1=Number(num1.toString().replace(".",""));
       r2=Number(num2.toString().replace(".",""));
       return (r1/r2)*Math.pow(10,t2-t1);
    }
     //两位数相乖
    function accMul(num1,num2){
       var m=0,s1=num1.toString(),s2=num2.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);
    }

但是有的时候,我们需要计算一连串的公式,并且里面包含了括号等等的复杂的符合运算,这个时候咱们应该怎么办呢?

例如:计算(0.7+0.1)÷(45.6*13)

这样的公式,我们是无法通过上面的自定义函数来解决的。因此今天给大家介绍一个比较好的计算引擎。

CalcEval.js

CalcEval引擎是一个专门解决javascript浮点数误差的的引擎,能够完美的解决各种复合的运算,最终输出正确的结果。

CalcEval.js可上网下载或者见以下源码:

Number.prototype.toFixed=function(j){var h=this+"";if(!j){j=0}if(h.indexOf(".")==-1){h+="."}h+=new Array(j+1).join("0");if(new RegExp("^(-|\\+)?(\\d+(\\.\\d{0,"+(j+1)+"})?)\\d*$").test(h)){var h="0"+RegExp.$2,g=RegExp.$1,e=RegExp.$3.length,c=true;if(e==j+2){e=h.match(/\d/g);if(parseInt(e[e.length-1])>4){for(var f=e.length-2;f>=0;f--){e[f]=parseInt(e[f])+1;if(e[f]==10){e[f]=0;c=f!=1}else{break}}}h=e.join("").replace(new RegExp("(\\d+)(\\d{"+j+"})\\d$"),"$1.$2")}if(c){h=h.substr(1)}return(g+h).replace(/\.$/,"")}return this+""};var CalcEval=function(){};CalcEval.prototype.eval=function(str){var isRetStr=str.match(new RegExp(/^".+"$/g))!=null;if(isRetStr==true){str=str.replace(/^"|"$/g,"")}var bracketsList=this.matchOutBrackets(str);for(var i=0;i<bracketsList.length;i++){var newCalc=bracketsList[i];var calcStr=this.eval(newCalc.str.replace(/^\(|\)$/g,""));str=str.replace(newCalc.str,calcStr)}var errorObj=new Array();while(1){var multObj=this.matchExp(str,"/");if(multObj==null){break}var v=this.executeDivi(multObj.firstValue,multObj.secondValue);if(v=="NaN"){var t="T"+new Date().getTime();errorObj.push({Name:t,Exp:multObj.str});str=str.replace(multObj.str,t)}else{str=str.replace(multObj.str,v)}}while(1){var multObj=this.matchExp(str,"*");if(multObj==null){break}var v=this.executeMult(multObj.firstValue,multObj.secondValue);if(v=="NaN"){var t="T"+new Date().getTime();errorObj.push({Name:t,Exp:multObj.str});str=str.replace(multObj.str,t)}else{str=str.replace(multObj.str,v)}}while(1){var multObj=this.matchExp(str,"+");if(multObj==null){break}var v=this.executeAddi(multObj.firstValue,multObj.secondValue);if(v=="NaN"||isNaN(v)){var t="T"+new Date().getTime();errorObj.push({Name:t,Exp:multObj.str});str=str.replace(multObj.str,t)}else{str=str.replace(multObj.str,v)}}while(1){var multObj=this.matchExp(str,"-");if(multObj==null){break}var v=this.executeSubt(multObj.firstValue,multObj.secondValue);if(v=="NaN"){var t="T"+new Date().getTime();errorObj.push({Name:t,Exp:multObj.str});str=str.replace(multObj.str,t)}else{str=str.replace(multObj.str,v)}}for(var i=errorObj.length-1;i>=0;i--){var ex=errorObj[i];str=str.replace(ex.Name,ex.Exp)}while(1){var multObj=str.match(/\d*={2,3}\d*/g);if(multObj==null){break}var v=eval(multObj[0]);str=str.replace(multObj[0],v)}if(isRetStr==true){try{return eval('"'+str+'"')}catch(e){}try{return eval(str)}catch(e){}return str}if(str.match(/(^true$)|(^false$)/g)){return str==="true"}if(!isNaN(Number(str))){return Number(str)}try{return eval(str)}catch(e){}return str};CalcEval.prototype.matchOutBrackets=function(f){var h=new Array();if(f==null){return h}if(typeof f!="string"){f=f+""}var d=f.split("");var a=0;var g=false;var b=-1;for(var c=0;c<d.length;c++){if(d[c]=="("){a++;g=true;if(b==-1){b=c}}if(d[c]==")"){a--}if(g==true&&a==0){var e=new Object();e.str=f.substring(b,c+1);e.firstIndex=b;e.lastIndex=c+1;h.push(e);b=-1;g=false;a=0}}return h};CalcEval.prototype.matchExp=function(l,f){var j=null;if(l==null){return retList}if(typeof l!="string"){l=l+""}var k=l.split("");var c=0;var b=0;var g="";var e="";var a="";var d=false;for(var h=0;h<=k.length;h++){if(k[h]=="+"||k[h]=="-"||k[h]=="*"||k[h]=="/"||k[h]=="%"||h==k.length){if(a==""&&k[h]=="-"){a+=k[h];continue}if(d==true){e=a;b=h;j=new Object();j.firstIndex=c;j.secondIndex=b;j.str=l.substring(c,b);j.firstValue=Number(g);j.secondValue=Number(e);break}if(k[h]==null){break}if(k[h]==f){d=true;g=a;a=""}else{a="";c=-1}}else{a+=k[h];if(c==-1){c=h}}}return j};CalcEval.prototype.executeMult=function(d,b){var a=0,f=d.toString(),c=b.toString();try{a+=f.split(".")[1].length}catch(g){}try{a+=c.split(".")[1].length}catch(g){}return Number(f.replace(".",""))*Number(c.replace(".",""))/Math.pow(10,a)};CalcEval.prototype.executeDivi=function(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 this.executeMult(r1/r2,pow(10,t2-t1))}};CalcEval.prototype.executeAddi=function(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(this.eval(arg1+"*"+m)+this.eval(arg2+"*"+m))/m};CalcEval.prototype.executeSubt=function(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((this.eval(arg1+"*"+m)-this.eval(arg2+"*"+m))/m).toFixed(n)};

在页面上调用CalcEval的解析引擎入口

var ce = new CalcEval();//创建引擎对象
var result = ce.eval("(0.7+0.1)/(45.6*13)");//调用引擎接口来解析公式的字符串,这个地方,必须要将公式以字符串的形式传入。
alert(result);//查看返回结果。

就这么简单的过程,就可以解决了每个浏览器中的浮点数计算bug。同时也可以制作自己的网页计算器了。

关键词: javascript,浮点数,CalcEval.js   编辑时间: 2015-08-11 18:34:16

  • 感到高兴

    0

    高兴
  • 感到支持

    0

    支持
  • 感到搞笑

    0

    搞笑
  • 感到不解

    0

    不解
  • 感到谎言

    0

    谎言
  • 感到枪稿

    0

    枪稿
  • 感到震惊

    0

    震惊
  • 感到无奈

    0

    无奈
  • 感到无聊

    0

    无聊
  • 感到反对

    0

    反对
  • 感到愤怒

    0

    愤怒
0%(0)
0%(0)
共有0 条评论 发言请遵守【相关规定

网友评论

会员头像
发 表同步腾讯微博    验证码:  点击更新请先登陆
  • 暂无评论
关闭模块文章图片 article Pictrue
  • 我的妈妈爸爸
  • 基于koa2+mysql+vue2.0+Element阳光内容管理系统
  • 代码覆盖率工具 Istanbul 入门教程
  • 全栈工程师的武器——MEAN
  • 9款超炫的 CSS3 复选框(Checkbox)
  • 微信开发在线翻译功能
  • CSS3那些不为人知的高级属性
  • 给easyui的datebox添加清空事件
  • flash写字效果
  • kendoUI系列教程之DropDownList下拉菜单
  • kendoUI系列教程之datetimepicker日期时间选择
  • kendoUI系列教程之datepicker日期选择
  • kendoUI系列教程之combobox下拉列表框
  • kendoUI系列教程之colorpicker
  • kendoUI系列教程之calendar日历表
  • kendoUI系列教程之autocomplete自动补齐