使用js精度计算

JS 计算问题
问题这样的:
37.55.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 (arg1m+arg2m)/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 ((arg1m-arg2m)/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);

复制代码

Javascript四舍五入(Math.round()与Math.pow())

复制代码

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

numObj.toFixed([fractionDigits])

参数
numObj

必选项。一个 Number 对象。

fractionDigits

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

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

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

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

 一、toFixed能做什么?

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

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

numObj.toFixed([fractionDigits])

参数
numObj
必选项。一个 Number 对象。

fractionDigits

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

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

如果没有 fractionDigits 参数,或者该参数为 undefined,toFixed 方法假定该值为 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后的显示例子如下:

复制代码

复制代码 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)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值