php intval()和floor()返回的值太低了吗? [英] php intval() and floor() return value that is too low?

查看:133
本文介绍了php intval()和floor()返回的值太低了吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于PHP中的float数据类型不准确,而MySQL中的FLOAT比INT占用更多的空间(并且不准确),因此我始终将价格存储为INT,在存储之前乘以100以确保我们的小数点后2位精确的地方.但是我相信PHP的行为不正确.示例代码:

Because the float data type in PHP is inaccurate, and a FLOAT in MySQL takes up more space than an INT (and is inaccurate), I always store prices as INTs, multipling by 100 before storing to ensure we have exactly 2 decimal places of precision. However I believe PHP is misbehaving. Example code:

echo "<pre>";

$price = "1.15";
echo "Price = ";
var_dump($price);

$price_corrected = $price*100;
echo "Corrected price = ";
var_dump($price_corrected);


$price_int = intval(floor($price_corrected));
echo "Integer price = ";
var_dump($price_int);

echo "</pre>";

产生的输出:

Price = string(4) "1.15"
Corrected price = float(115)
Integer price = int(114)

我很惊讶.当最终结果比预期的低1时,我期望测试的输出看起来像:

I was surprised. When the final result was lower than expected by 1, I was expecting the output of my test to look more like:

Price = string(4) "1.15"
Corrected price = float(114.999999999)
Integer price = int(114)

这将证明浮点类型的不准确性.但是为什么floor(115)返回114?

which would demonstrate the inaccuracy of the float type. But why is floor(115) returning 114??

推荐答案

尝试一下作为快速解决方案:

Try this as a quick fix:

$price_int = intval(floor($price_corrected + 0.5));

您遇到的问题不是PHP的错,所有使用带浮点运算的实数的编程语言都存在类似的问题.

The problem you are experiencing is not PHP's fault, all programming languages using real numbers with floating point arithmetics have similar issues.

货币计算的一般经验法则是从不使用浮点数(无论在数据库中还是在脚本中).您可以通过始终存储美分而不是美元来避免各种问题.分是整数,您可以将它们自由地加在一起,然后乘以其他整数.每当显示数字时,请确保在最后两位数字前插入一个点.

The general rule of thumb for monetary calculations is to never use floats (neither in the database nor in your script). You can avoid all kinds of problems by always storing the cents instead of dollars. The cents are integers, and you can freely add them together, and multiply by other integers. Whenever you display the number, make sure you insert a dot in front of the last two digits.

为什么得到114而不是115的原因是floor向下舍入到最接近的整数,因此floor(114.999999999)变为114.更有趣的问题是为什么1.15 * 100是114.999999999而不是115.原因是1.15并非完全等于115/100,但略小于115/100,因此如果乘以100,您得到的数字会比115小一点.

The reason why you are getting 114 instead of 115 is that floor rounds down, towards the nearest integer, thus floor(114.999999999) becomes 114. The more interesting question is why 1.15 * 100 is 114.999999999 instead of 115. The reason for that is that 1.15 is not exactly 115/100, but it is a very little less, so if you multiply by 100, you get a number a tiny bit smaller than 115.

这是echo 1.15 * 100;的作用的更详细说明:

Here is a more detailed explanation what echo 1.15 * 100; does:

  • 它将1.15解析为二进制浮点数.这涉及到四舍五入,它碰巧会四舍五入以使二进制浮点数最接近1.15.无法获得准确数字(没有舍入误差)的原因是1.15在2的底数中有无限数量的数字.
  • 它将100解析为二进制浮点数.这涉及到舍入,但是由于100是一个小整数,舍入误差为零.
  • 它计算前两个数字的乘积.这还涉及一些舍入,以找到最接近的二进制浮点数.在此操作中,舍入误差恰好为零.
  • 它将二进制浮点数转换为带点的以10为底的十进制数,并打印此表示形式.这还涉及一些舍入.

PHP打印出令人惊讶的Corrected price = float(115)(而不是114.999 ...)的原因是var_dump不会打印确切的数字(!),而是打印四舍五入到n - 2的数字(或n - 1)位,其中n位是计算精度.您可以轻松地验证这一点:

The reason why PHP prints the surprising Corrected price = float(115) (instead of 114.999...) is that var_dump doesn't print the exact number (!), but it prints the number rounded to n - 2 (or n - 1) digits, where n digits is the precision of the calculation. You can easily verify this:

echo 1.15 * 100;  # this prints 115
printf("%.30f", 1.15 * 100);  # you 114.999....
echo 1.15 * 100 == 115.0 ? "same" : "different";  # this prints `different'
echo 1.15 * 100 < 115.0 ? "less" : "not-less";    # this prints `less'

如果要打印浮子,请记住:打印浮子时,并非总是能看到所有数字.

If you are printing floats, remember: you don't always see all digits when you print the float.

另请参阅 PHP浮动文档开头附近的警告.

See also the big warning near the beginning of the PHP float docs.

这篇关于php intval()和floor()返回的值太低了吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆