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位整数的是不是一种选择这里☹️
编辑:澄清;请假定我的问题是关于处理任意大小的花车;我给出的示例代码是针对最近的一个案例,我在有限的范围内处理浮动内容,因此手动设置错误边界是很好的,但我希望能够处理将来任何大小的浮动内容。
正如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。
我们需要更多关于如何转换为字符串(和后面)的信息。有了正确的转换,你根本不需要任何的错误余地。例如,如果使用有限的IEEE 754二进制64位浮点数并使用至少17位有效数字(使用某种形式的转换的最近距离)将其转换为十进制数,则会得到一个十进制字符串,该字符串将转换回你开始的_exact_ float,没有错误。 –
不幸的是,我认为我仅限于PHP的默认浮点到字符串转换;实际上,我现在将值存储在memcached中,但这似乎是PHP的memcached模块处理浮动的方式。 – Haravikk