浮点数相乘失去精度问题
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示例
很简单的一个问题,答案是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); }
相关文章推荐
- js小数相加、相乘失去精度问题解析详解(最优方案)
- 关于浮点数的精度与取值范围的问题
- java中float/double浮点数的计算失去精度问题(即小数位数增加的问题)
- Java之道系列:BigDecimal如何解决浮点数精度问题
- 剖析js对浮点数运算精度问题
- 经得起雷劈:关于double和int/long相互转换失去精度计算错误的问题
- 关于浮点数的精度与取值范围的问题
- 【Python】浮点数减法精度问题
- 如何处理浮点数(float, double)的精度问题
- Java中浮点数的精度问题
- java下double相乘精度丢失问题
- 浮点数使用之精度舍入问题
- java中float/double浮点数的计算失去精度问题(即小数位数增加的问题)
- 【转】关于浮点数的精度与取值范围的问题
- JAVA中浮点数的精度问题
- 经得起雷劈:关于double和int/long相互转换失去精度计算错误的问题
- 由浮点数的精度问题引出设计问题
- javascript浮点数运算精度问题
- 二分求解 切绳子 (浮点数易出现精度问题)
- C++ 字符串转换为浮点数时的精度问题