php 小数相乘精度,浮点数相乘失去精度问题

0.1 * 3 = ?

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

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

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

十进制浮点数转换二进制数

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);

}

转载时请注明出处及相应链接,本文永久地址:https://blog.yayuanzi.com/1137.html

75d087ef9a9fb11dc373caaf33adbf7f.png

微信打赏

支付宝打赏

感谢您对作者terry的打赏,我们会更加努力!    如果您想成为作者,请点我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值