PHP和MySQL中浮点数精度问题,用于存储偶尔出现的小数值

3
我希望在MySQL数据库中存储偶尔出现的小数值,并在我的PHP应用程序中显示它们。让我解释一下,我所说的偶尔小数值是什么意思。这些数字大多数时候都是整数,例如160或170等等。但有时我需要保存像98.6这样的值。
起初,我在数据库中使用了DECIMAL(4,1)数据类型,但我发现我总是得到像160.0、170.0和98.6等数字。因此,我改为使用FLOAT。在我的本地环境中,我在PHP应用程序和phpMyAdmin上都可以看到数字为160、170、98.6等等。但在生产环境中,我在phpMyAdmin上看到这些数字是160、170、98.6等等。但在PHP应用程序上,我看到的数字是160、170、98.599998474121等等。
现在我需要决定是切换回decimal还是继续使用float。无论哪种方式,我都需要找到一种解决方案来将数字转换为如160、170和98.6等格式。
你认为对于这个目的,使用decimal还是float更好?如果数字的小数部分为零(使用decimal),将数字转换为整数的最佳方法是什么?将类似于98.599998474121的浮点值转换为98.6的最佳方法是什么?
如果数字的小数部分为零,将数字转换为整数的最佳方法是:
```php $number = 98.0; if ($number == (int)$number) { $number = (int)$number; } ```
对于将类似于98.599998474121的浮点值转换为98.6的最佳方法是:
```php $number = 98.599998474121; $number = round($number, 1); ```
至于使用decimal还是float更好,这取决于您的具体需求。如果您需要高精度的小数计算,则应该选择decimal。如果您需要更快的计算速度并且可以接受一定的舍入误差,则应该选择float。
<?php
if (fmod($number, 1) == 0) {
    $number = intval($number)
}

有没有更好的方法?

在MySQL中使用float数据类型,在PHP中保存时使用:$foo = "105"; echo number_format((float)$foo, 2, '.', ''); // 输出 -> 105.00 - Pratik Joshi
FLOAT(1)似乎是正确的选择,对吗? - Strawberry
@Strawberry,你是指FLOAT(1)作为链接吗?这与PHP或MySQL有关吗?"互联网搜索"并不具体。我误解了你的意思 - 只是感到困惑。 - Ryan Vincent
我是指在MySQL中使用FLOAT(1)数据类型。 - Strawberry
@Strawberry,感谢您的澄清。 - Ryan Vincent
2个回答

0

理解浮点数并不是精确的十进制数,而是接近它的值。它的存储方式非常高效,但代价是不精确。如果不知道您确切的需求,一种可能的解决方案是将数字作为浮点数存储,并将它们四舍五入到一位小数。

// the casts are there just for the demonstration, you probably don't need them
$number = "170";
echo round((float)$number, 1); // gives 170
$number = "98.6";
echo round((float)$number, 1); // gives 98.6

浮点数以你期望的方式代表整数,只有在存储特定小数时才会失去精度。


我不知道 round 函数会在小数位为零时将其删除。这个函数在使用 decimal 数据类型时效果很好。 - Debiprasad

0

我认为获取子字符串不是一个好的解决方案,因为98.599998474121会变成98.5而不是98.6。 - Debiprasad
我也尝试在php.ini中更改precision,但这也没有起作用。 - Debiprasad
你应该意识到我建议的函数返回的是长度而不是子字符串,对吧?它仅仅计算小数点后面的数字个数。 - Alex Tartan
那个函数只能帮助你识别浮点误差出现的情况。 - Alex Tartan
抱歉,我错过了。无论如何,那不是一个完整的解决方案。 - Debiprasad
除了检测问题之外,我没有看到需要另一个解决方案的必要,因为您的'round'调用恰好可以解决这个问题。无论如何,希望这些内容将在某一天派上用场。 - Alex Tartan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接