您的位置:首页 > 其它

浮点数相乘失去精度问题

2014-07-08 00:00 246 查看
0.1 * 3 = ?

很简单的一个问题,答案是0.3。然而,在我们的实际编程过程中,得到的却不是预期的结果,而是0.30000000000000004(java及javascript中是这个结果,php输出结果为0.3)。

为什么浮点数会丢失精度?   

在计算机中,数字以二进制的形式进行存储。一般而言,十进制浮点数并没有精确的二进制表示式。十进制浮点数在转化为二进制数时可能会失去一些精度,从而产生未预期的结果。

[b]十进制浮点数转换二进制数[/b]

1.十进制整数转换为二进制整数:“除2取余,逆序排列”(具体 略)。

2.十进制小数转换为二进制小数:“乘2取整,顺序排列”。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,此时0或1为二进制的最后一位。或者达到所要求的精度为止。

如:0.625 =(0.101)B
0.625*2 = 1.25             =======取出整数部分1
0.25*2 = 0.5                  =======取出整数部分0
0.5*2 = 1                         =======取出整数部分1
原理:

关于十进制小数转换为二进制小数
假设一十进制小数B化为了二进制小数0.ab的形式,同样按权展开,得
B=a(2^-1)+b(2^-2)
因为小数部分的位权是负次幂,所以两边乘2,得
2B=a+b(2^-1)
注意a变成了整数部分,我们取整数正好是取到了a,剩下的小数部分也如此。

浮点数计算确保精度方法:转化为整数,计算出结果在转化为浮点数(注意数值溢出)。
javascript示例

// 两个浮点数求和
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: