0

我正在处理货币输入。只能使用小数点后两位数。我尝试将输入转换为浮点数并乘以 100,这可以正常工作,直到有人在小数点后输入超过两位数:

// Returns 6999.8 instead of 6999
$cents = floatval('69.998') * 100;

然后我尝试将结果转换为 int,因此小数点后的连续数字被忽略。它解决了上述问题('69.998' 变为 6999),但创建了一个具有浮点到整数转换的新问题:

// Returns 6998 instead of 6999
$cents = intval(floatval('69.99') * 100);

我也考虑过 floor(),但它会触发与 intval() 相同的浮动问题。

这就是我正在考虑使用的:

$cents = intval((string)(floatval('69.99') * 100));

它在这两种情况下都有效,但感觉就像一个黑客,而且已经很晚了,我的头很痛,所以也许我在这里遗漏了一些明显的东西。有一个更好的方法吗?

4

4 回答 4

4

$cents = intval(round(floatval('69.99') * 100));

你需要什么?

您还可以指定精度。例如,在您提到的情况下,您希望将原始数据四舍五入到小数点后两位:

$twodecimal = round(floatval('69.998'),2);//returns a float representation of 70

请务必查看这些文档中的红色大通知

于 2012-11-06T20:40:04.957 回答
2

这是因为69.99 * 100有一个浮点表示6998.9999999*(关闭:您也可以在 javascript 控制台上检查它)。如果你想要精确,你应该使用带有 php 扩展的定点数,比如BCMath - 或者,你可以为这个特定问题编写一个简单的正则表达式

$amount = '69.99';

if (preg_match('/^(-?\d+)(\.(\d{1,2}))?/', $amount, $matches))
{
    $amount = (int) ($matches[1] . (isset($matches[3]) ? str_pad($matches[3], 2, '0') : '00'));
}
else
{
    $amount = ((int) $amount) * 100;
}
于 2012-11-06T21:13:45.270 回答
0
$cents = intval(round(floatval('69.99') * 100));

这将正确地得到最接近的数字,这是因为浮动指针精度问题,因为69.99它可能在内存中表示为类似69.9899999

intval只是截断小数的其余部分,所以69.989999 * 100变成6998.9999并被截断为6998

于 2012-11-06T20:42:21.647 回答
0

我建议您使用整数来包含货币值。使用浮点数会迅速导致舍入错误。

在我看到的应用程序中,整数与假定的小数点一起使用。所有价值均以最接近的货币单位为准,例如美元或欧元的美分。有些货币没有小数点,有些货币不是两位小数,而是三位小数。

通过使用带有假定小数位的整数进行操作,您可以真正减少舍入误差和浮点可以看到的其他问题。

要进行转换,我建议使用字符串操作并使用字符串操作删除小数点,并执行检查以确保仅输入所需的位数。

于 2012-11-06T20:44:46.677 回答