php fmod 返回不可用的结果
php fmod returning unusable result
fmod(floatval("314.6"), floatval("1.3"))
=> 1.1990408665952E-14
我或多或少地理解以二进制形式表示数字的潜在问题以及 IEEE-754 的某些内容。但是:我怎样才能得到在实践中可用的结果?
举个我想要实现的例子:商家可以定义他的产品的价格P,但是价格必须是x的倍数:
if (fmod(P, x) != 0) { echo "price must be a multiple of " . x; }
它会如此简单,但是每当我得到像 1234E-18 这样的东西作为 fmod()
的 return 值时,该方法就会失败。
现实生活中如何不用自定义代码轻松查看价格区间?
这个或类似的问题一直存在,但我能找到的只是解释为什么 fmod()
的行为如此。从来没有答案如何解决这个现实生活中的问题...
这里的问题是 314.6
正好是 1.3 * 242
,所以浮点数余数为零,但由于您很清楚 IEEE 754 的不准确性,您得到 0.00000000000001199041
。
但是不要忘记浮点数学的规则之一:你不能粗心地 compare floats 求相等。如果您的参数有一位小数,则您的结果不需要 14 位精度。你有价格:多少小数点在你的货币中有意义?如果您正在使用例如欧元你不太可能使用超过两个(美分)并且 1.1990408665952E-14
对所有效果都是零:
var_dump(round(1.1990408665952E-14, 2));
double(0)
有些人建议使用整数(例如美分而不是欧元)进行所有价格计算以避免舍入错误,但大多数现实生活中的问题都来自非常具体的错误:
- 向用户显示原始浮点数(而不是对其进行舍入和格式化)。
- 进行原始比较(
if ($foo == $bar)
)。
… 无论如何,整数并不能防止所有舍入错误(例如,个别项目的税收计算与发票总额的计算不匹配)。
fmod(floatval("314.6"), floatval("1.3"))
=> 1.1990408665952E-14
我或多或少地理解以二进制形式表示数字的潜在问题以及 IEEE-754 的某些内容。但是:我怎样才能得到在实践中可用的结果?
举个我想要实现的例子:商家可以定义他的产品的价格P,但是价格必须是x的倍数:
if (fmod(P, x) != 0) { echo "price must be a multiple of " . x; }
它会如此简单,但是每当我得到像 1234E-18 这样的东西作为 fmod()
的 return 值时,该方法就会失败。
现实生活中如何不用自定义代码轻松查看价格区间?
这个或类似的问题一直存在,但我能找到的只是解释为什么 fmod()
的行为如此。从来没有答案如何解决这个现实生活中的问题...
这里的问题是 314.6
正好是 1.3 * 242
,所以浮点数余数为零,但由于您很清楚 IEEE 754 的不准确性,您得到 0.00000000000001199041
。
但是不要忘记浮点数学的规则之一:你不能粗心地 compare floats 求相等。如果您的参数有一位小数,则您的结果不需要 14 位精度。你有价格:多少小数点在你的货币中有意义?如果您正在使用例如欧元你不太可能使用超过两个(美分)并且 1.1990408665952E-14
对所有效果都是零:
var_dump(round(1.1990408665952E-14, 2));
double(0)
有些人建议使用整数(例如美分而不是欧元)进行所有价格计算以避免舍入错误,但大多数现实生活中的问题都来自非常具体的错误:
- 向用户显示原始浮点数(而不是对其进行舍入和格式化)。
- 进行原始比较(
if ($foo == $bar)
)。
… 无论如何,整数并不能防止所有舍入错误(例如,个别项目的税收计算与发票总额的计算不匹配)。