zoukankan      html  css  js  c++  java
  • JS 计算问题

    问题这样的: 
    37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数) 
    我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 
    怎么会这样,两个只有一位小数的数字相乘,怎么可能多出这么小数点出来。 
    我Google了一下,发现原来这是JavaScript浮点运算的一个bug。 
    比如:7*0.8 JavaScript算出来就是:5.6000000000000005 
    网上找到了一些解决办法,就是重新写了一些浮点运算的函数。 
    下面就把这些方法摘录下来,以供遇到同样问题的朋友参考: 

    程序代码 

    //除法函数,用来得到精确的除法结果 
    //说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 
    //调用: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); 
      } 
    } 

    //乘法函数,用来得到精确的乘法结果 
    //说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 
    //调用: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) 
    } 


    //加法函数,用来得到精确的加法结果 
    //说明: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 
    } 

    帖出减法的代码:

    function Subtr(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));
         //last modify by deeka
         //动态控制精度长度
         n=(r1>=r2)?r1:r2;
         return ((arg1*m-arg2*m)/m).toFixed(n);
    }
    //乘法函数,用来得到精确的乘法结果 
    //说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 
    //调用:accMul(arg1,arg2) 
    //返回值:arg1乘以arg2的精确结果 
    function accMul(arg1,arg2) 
    { 
        var m=0,s1=arg1.toString(),s2=arg2.toString(); 
        try{
            if(s1.split(".")[1] != undefined )
                m+=s1.split(".")[1].length
        }catch(e){} 
        try{
            if(s2.split(".")[1] != undefined )
                m+=s2.split(".")[1].length
        }catch(e){} 
        return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m) 
    } 
      
    //浮点数除法运算  
     function accDiv(arg1,arg2){   
        var r1=0,r2=0,m,s1=arg1.toString(),s2=arg2.toString();  
        try{
            if(s1.split(".")[1] != undefined )
                r1=s1.split(".")[1].length;
        }catch(e){} 
        try{
            if(s2.split(".")[1] != undefined )
                r2=s2.split(".")[1].length;
        }catch(e){} 
        m=Math.pow(10,Math.max(r1,r2));   
        return (accMul(arg1,m))/(accMul(arg2,m));   
    }   
    
    function accAdd(arg1,arg2){ 
        var r1=0,r2=0,m,s1=arg1.toString(),s2=arg2.toString();  
        try{
            if(s1.split(".")[1] != undefined )
                r1=s1.split(".")[1].length;
        }catch(e){} 
        try{
            if(s2.split(".")[1] != undefined )
                r2=s2.split(".")[1].length;
        }catch(e){} 
        m=Math.pow(10,Math.max(r1,r2)); 
        return (accMul(arg1,m)+accMul(arg2,m))/m; 
    } 
    
    function Subtr(arg1,arg2){
         var r1=0,r2=0,m,n,s1=arg1.toString(),s2=arg2.toString();
         try{
             if(s1.split(".")[1] != undefined )
                 r1=s1.split(".")[1].length;
         }catch(e){}
         try{
             if(s2.split(".")[1] != undefined )
                 r2=s2.split(".")[1].length;
         }catch(e){}
         m=Math.pow(10,Math.max(r1,r2));
         //last modify by deeka
         //动态控制精度长度
         n=(r1>=r2)?r1:r2;
         return (accMul(arg1,m)-accMul(arg2,m))/m;
    }

    附js方法解释

    pow 方法

    返回底表达式的指定次幂。

    Math.pow(base, exponent)

    参数

    base

    必选项。表达式底的值。

    exponent

    必选项。表达式的指数值。

    示例

    在下面的例子中,等同于 baseexponent数值表达式,返回值为 1000。

    Math.pow(10,3);

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
    <title>Javascript四舍五入(Math.round()与Math.pow())</title>
    <script type="text/javascript">
      //Math.round(x);返回数字最接近的整数,四舍五入取整数,即舍去小数部分
      function f(){
        alert(Math.round(123.567));
        alert(Math.round(123.456));
      }
      //Math.pow(x,y);返回底数的指定次幂
      //返回以x的y次幂,等同于x的y次幂的数值表达式
      //如果pow的参数过大而引起浮点溢出,返回Infinity
      function f1(){
        alert(Math.pow(2,10));//2的10次方等于1024
        alert(Math.pow(1024,0.1));//1024的0.1次方等于2
        alert(Math.pow(99,9999));//溢出则返回Infinity
      }
      /*Javascript设置要保留的小数位数,四舍五入。
      *ForDight(Dight,How):数值格式化函数,Dight要格式化的 数字,How要保留的小数位数。
      *这里的方法是先乘以10的倍数,然后去掉小数,最后再除以10的倍数。
      */ 
      function ForDight(Dight,How){ 
        Dight = Math.round(Dight*Math.pow(10,How))/Math.pow(10,How); 
        return Dight; 
      } 
      function f2(){
        alert(ForDight(12345.67890,3));//保留三位小数
        alert(ForDight(123.99999,4));//保留四位小数
      }
      //另外一种四舍五入的方法,原理一样。
      //里面的两个参数:num就是要转换的数据。n为要转换的位数
      //cheng(123.456,2);//保留两位小数
      function cheng(num,n){
        var dd=1; 
        var tempnum; 
        for(i=0;i<n;i ){
          dd*=10; 
        } 
        tempnum = num*dd;
        tempnum = Math.round(tempnum); 
        alert(tempnum/dd); 
      }
    </script>
    </head>
    <body>
    <input type="button" value="round" onclick="f();" />
    <input type="button" value="pow" onclick="f1();" />
    <input type="button" value="设置要保留的小数位数,四舍五入" onclick="f2();" />
    <input type="button" value="cheng" onclick="cheng(123.456,2);" />
    </body>
    </html>
    其它实现方法参考:
    <script type="text/javascript">
      //用Javascript取float型小数点后两位,例22.127456取成22.13,如何做? 
      //1.最笨的办法....... [我就怎么干的.........] 
      function get(){
        var s = 22.127456 "";
      var str = s.substring(0,s.indexOf(".") 3);
        alert(str);
      } 
    </script>
    <script type="text/javascript">
      //2. 正则表达式效果不错 
      onload = function(){
        var a = "23.456322";
        var aNew;
        var re = /([0-9] \.[0-9]{2})[0-9]*/;
        aNew = a.replace(re,"$1");
        alert(aNew);
      }
    </script>
    <
    script type="text/javascript">   //3. 他就比较聪明了.....   var num=22.127456;   alert( Math.round(num*100)/100); </script>

    <script type="text/javascript">   //4.会用新鲜东西的朋友....... 但是需要 IE5.5 才支持。   var num=22.127456;   alert( num.toFixed(2)); </script>


    toFixed 方法

    返回一个字符串,代表一个以定点表示法表示的数字。

    numObj.toFixed([fractionDigits])

    参数

    numObj

    必选项。一个 Number 对象。

    fractionDigits

    可选项。小数点后的数字位数。其值必须在 0 – 20 之间,包括 0 和 20。

    说明

    toFixed 方法返回一个以定点表示法表示的数字的字符串形式。该字符串中小数点之前有一位有效数字,而且其后必须包含 fractionDigits 数字。

    如果没有 fractionDigits 参数,或者该参数为 undefinedtoFixed 方法假定该值为 0。

     在写脚本处理数字的时候肯定会经常用到toFixed方法。

         一、toFixed能做什么?

    以下是摘自网络的toFixed的介绍:

    toFixed 方法:

    返回一个字符串,代表一个以定点表示法表示的数字。

    numObj.toFixed([fractionDigits])

    参数

    numObj

    必选项。一个 Number 对象。

    fractionDigits

    可选项。小数点后的数字位数。其值必须在 0 – 20 之间,包括 0 和 20。

    说明

    toFixed 方法返回一个以定点表示法表示的数字的字符串形式。该字符串中小数点之前有一位有效数字,而且其后必须包含 fractionDigits 数字。

    如果没有 fractionDigits 参数,或者该参数为 undefinedtoFixed 方法假定该值为 0。

    二、toFixed可以四舍五入吗?

         答案是可以。但是问题也正在于此。这种四舍五入是不稳定的(不同的浏览器不一样)。

         (1).

         在ie7下点击按钮会显示0.00,而ff会是0.01。

        (2) 

         ie和ff都正常。

         可见对于ie而言有一部分数字在使用toFixed时是不能得到正确的四舍五入的结果的。这个问题可能很多朋友都没有意识到,而这个问题说小也小,但有时候却也会带来恶劣的后果。

         就像上面0.009.toFixed(2)这个例子(0.009是一系列处理后的结果),恰好我就遇上了。在一个页面当中因为是在后台代码中做的计算因此显示为1%,而在另一个页面因为使用了toFixed结果显示为0%。为此被客户批了一顿。

         OK,既然有这样的问题,又怎么解决呢?

    三、替代方案:

         正如很多朋友所想,我们可以重写这个方法:

         Number.prototype.toFixed = function( fractionDigits )...

         下面给出一个简陋的解决方案:


    Number.prototype.toFixed = function( fractionDigits )
    {
        
    //没有对fractionDigits做任何处理,假设它是合法输入
        return (parseInt(this * Math.pow( 10, fractionDigits  ) + 0.5)/Math.pow(10,fractionDigts)).toString();
    }

    覆写toFixed后的显示例子如下:


    <html>
    <head>
    <script type="text/javascript">
    Number.prototype.toFixed 
    = function(s)
    {
        
    return (parseInt(this * Math.pow( 10, s ) + 0.5)/ Math.pow( 10, s )).toString();
    }
    </script>
    </head>
    <body>
    <input onclick="alert(0.009.toFixed(2))" type="button" value="显示0.009.toFixed(2)"> 
    </body>
    </html>

    with 语句

    为语句设定默认对象。

    with (object)
       statements

    参数

    object

    新的默认对象。

    statements

    一个或多个语句,object 是该语句的默认对象。

    说明

    with 语句通常用来缩短特定情形下必须写的代码量。在下面的例子中,请注意 Math 的重复使用:

    x = Math.cos(3 * Math.PI) + Math.sin(Math.LN10) 
    y = Math.tan(14 * Math.E)

    当使用 with 语句时,代码变得更短且更易读:

    with (Math){
       x = cos(3 * PI) + sin (LN10)  
       y = tan(14 * E)
    }
  • 相关阅读:
    Clean Code读书笔记
    Junit 断言 assertThat Hamcrest匹配器
    SpringMVC 常用注解
    SpringMVC 流程 配置 接口
    ng-select ng-options ng-repeat的用法与区别
    javascript总结
    intellij安装 配置 创建项目
    git常用操作指令
    springmvc报错 org.springframework.web.servlet.DispatcherServlet
    linux笔记:RPM软件包管理-源码包管理
  • 原文地址:https://www.cnblogs.com/mingforyou/p/2768095.html
Copyright © 2011-2022 走看看