问题描述
在PHP中不使用内置常量PHP_FLOAT_EPSILON
来直接直接计算机器epsilon(浮点舍入误差)的最佳/最正确方法是什么?目前,我已经设法研究了两种方式:“标准”和渐近地接近epsilon:
// Standard way
$x=1.0;
$dx=2.0;
while (($x/=$dx)+1.0!=1.0);
echo "EPSILON : $x".",DEFINED/CALC : ".round(PHP_FLOAT_EPSILON/$x)."x\n";
// Asymptotically approaching
$x=1.0;
$dx=2.0;
while (($x/=$dx)+1.0!=1.0) $dx/=1.0+10**-5;
echo "EPSILON : $x".",DEFINED/CALC : ".round(PHP_FLOAT_EPSILON/$x)."x\n";
问题是,他们给出的答案有不同的错误:
EPSILON : 1.1102230246252E-16,DEFINED/CALC : 2x
EPSILON : 5.6311222663283E-17,DEFINED/CALC : 4x
因此标准给出ε= 1 /2ε 0 ,其他算法给出ε= 1 /4ε 0 。我不确定应该如何正确计算ε。
解决方法
由于@EricPostpischil,导致错误的主要原因是打印了x+1=1
的x的第一个值,而不是我应该打印x+1≠1
的x的最后一个值。固定代码:
// Standard way
$x=1.0;
$dx=2.0;
while (true) {
$px = $x;
$x/=$dx;
if ($x+1.0==1.0)
break;
}
printf ("ε = $x ≈ %.1f ε₀ \n",$px/PHP_FLOAT_EPSILON);
// Asymptotically approaching
$x=1.0;
$dx=2.0;
while (true) {
$px = $x;
$x/=$dx;
$dx/=1.0+10**-5;
if ($x+1.0==1.0)
break;
}
printf ("ε = $x ≈ %.1f ε₀ \n",$px/PHP_FLOAT_EPSILON);
报告=>
ε= 1.1102230246252E-16≈1.0ε₀
ε= 5.6311222663283E-17≈0.5ε₀
这已经足够好了,因为第一标准案例报告epsilon与PHP文档中的相同。至于第二种算法,这可能是由于四舍五入问题造成的,并且可以用不同的方式解释。即如果±ε将您带至下一个可表示的浮点数,则表示误差为半epsilon,因为任何大于| 0.5ε₀|的变化。将四舍五入到下一个可表示的数字。就像物理学家计数测量误差一样。假设您的标尺的最小测量单位为1毫米。然后在当前读数上加上±0.5 mm并四舍五入,将使您到达标尺上的下一个可表示的读数。因此,有人说实际测量误差为0.5毫米,而有人说是1毫米,取决于定义。一样。