Float - > String - > Float Conversion的错误可靠边距?

问题描述:

我有一个float值,我需要将它作为字符串存储在PHP中,然后在重新转换为浮点数后再进行比较。Float - > String - > Float Conversion的错误可靠边距?

由于我知道,靠平等将是一个错误,因为有对精度的损失潜在的,所以我在做类似下面的转换:现在

if (abs((float)$string_value - $float_value) < 0.001) { echo "Values are close enough\n"; } 

,而保证金对于我的直接目的而言,0.001的错误应该没问题,这让我想到;我可以可靠/安全地使用的最小误差范围是多少?

我意识到误差的安全范围会随着浮点的大小而变化(即更大的值具有更小或甚至没有小数精度),所以答案应该可以解释这一点。

换句话说,给定一个浮点值,我希望以10为底进行存储并读回,我如何可靠地确定我的误差范围应该是这样,以便我可以合理地确认这两个值是相同的?

不幸的是我在处理的值必须被存储在纯小数形式,所以我平时去到他们的包装作为网络秩序的64位整数的是不是一种选择这里☹️

编辑:澄清;请假定我的问题是关于处理任意大小的花车;我给出的示例代码是针对最近的一个案例,我在有限的范围内处理浮动内容,因此手动设置错误边界是很好的,但我希望能够处理将来任何大小的浮动内容。

+1

我们需要更多关于如何转换为字符串(和后面)的信息。有了正确的转换,你根本不需要任何的错误余地。例如,如果使用有限的IEEE 754二进制64位浮点数并使用至少17位有效数字(使用某种形式的转换的最近距离)将其转换为十进制数,则会得到一个十进制字符串,该字符串将转换回你开始的_exact_ float,没有错误。 –

+0

不幸的是,我认为我仅限于PHP的默认浮点到字符串转换;实际上,我现在将值存储在memcached中,但这似乎是PHP的memcached模块处理浮动的方式。 – Haravikk

正如Mark Dickinson的评论所述,可以将浮点数转换为字符串并返回而不会损失精度。这仅

  • 您使用足够显著十进制数(17个IEEE双打)工作
  • 的转换是准确的(即他们保证转换为最接近的数字)

从快速查看,似乎在PHP中隐式地或者用(string) $f将一个双重$f铸造成一个字符串,只使用14位有效数字,所以这种方法不够准确。但是,您可以使用sprintf%.16e转换说明符来获取17位有效数字。因此,经过下面的往返

$s = sprintf("%.16e", $f); 
$f2 = (double) $s; 

$f2应该等于$f正是除非PHP使用次优算法内部。

请注意,%e转换说明符使用科学(指数)符号。如果您需要简单的十进制,可以使用%f符和使用log10小数点后计算出所需要的位数:

if ($f != 0) { 
    $prec = 16 - floor(log10(abs($f))); 
    if ($prec < 0) $prec = 0; 
} 
else { 
    $prec = 0; 
} 
$s = sprintf("%.${prec}f", $f); 

这可能会产生极长的字符串非常小或大的数字,虽然。

它可能需要大量的研究来判断这些方法是否完全可靠,如果不是最大误差是什么。这一切都取决于几个实施细节,如PHP版本,底层C库等

另一个想法是将字符串表示,而不是比较浮点值:

# Assuming $string_value was also converted with float_to_string 
if ($string_value == float_to_string($float_value)) { 
    echo "Values are close enough\n"; 
} 

这应该是可靠的,只要你坚持相同的PHP版本。

如果您必须比较浮点数,通常比较相对误差更有意义。有关更多详细信息,请参阅Bruce Dawson's excellent blog