php - 选择什么常数来比较 fmod 函数的结果
问题描述
我需要检查一个浮点数/双精度数是否是另一个浮点数/双精度数的倍数。整数很容易
$isMultiple = $x % $y == 0;
但在浮点数/双打中却没有。第一个问题是浮点数没有 % 运算符,所以我们必须使用 fmod 函数,第二个更大的问题是我们不能与零进行比较,但我们必须比较该数字小于某个常数,我不知道如何选择正确的常数,因为我总是可以选择它不起作用的数字。例如,如果我选择 0.00001,那么它仍然不适用于某些数字:
$C = 0.00001;
$isMultiple1 = fmod(3.0, 2.0) < $C; // = false, which is correct
$isMultiple2 = fmod(1.39, 0.0001) < $C; // = false, which is not correct
事实上,问题是 (0.000099999999999836) 的结果fmod(1.39, 0.0001)
对于9.9999999999836E-5
小常数来说太高了,但是如果我选择高常数,它对于其他一些数字就不起作用了。
如何$C
正确选择或如何以不同的方式解决该问题,这将普遍适用于 PHP 中的任何数字?
解决方案
此函数检查浮点值是否是浮点因子的整数倍。
function isMultiple($product, $factor){
$eps = 1.E-12;
$rest = abs(fmod($product, $factor));
if($rest < $eps) return true;
return abs($rest-$factor) < $eps;
}
var_dump( isMultiple(3.0,2.0) ); //false
var_dump( isMultiple(1.39, 0.0001) ); //true
var_dump( isMultiple(1.39, 0.02) ); //false
由于浮点值计算的准确性有限,该函数只能在一定的范围内工作。例如,因子必须是浮点精度和变量 $eps 的倍数。
结果错误的例子
var_dump( isMultiple(1.1e-11, 0.2e-11) ); //bool(true)
var_dump( isMultiple(1.39, 0.00010000000000001) ); //bool(true)
更新
以下函数不使用 fmod,因此可以更好地利用 float 的准确性。
function isMultiple($value, $factor){
$quot = $value/$factor;
return abs(round($quot)-$quot)/$quot < 1.e-14;
}
所有这些测试都给出了正确的结果
var_dump( isMultiple(3.0,2.0) ); //false
var_dump( isMultiple(1.39, 0.0001) ); //true
var_dump( isMultiple(1.39, 0.02) ); //false
var_dump( isMultiple(1.39, 0.0001000000000001) ); //bool(false)
var_dump( isMultiple(56185.047, 0.123) ); //bool(true)
var_dump( isMultiple(56185.04701, 0.123) ); //bool(false)
推荐阅读
- javascript - 如何更改在可排序 JQuery 中拖动的元素
- spring - Spring Boot - 映射
- r - 问题在小标题列表上进行变异和选择
- react-native - React Native Navigation 允许在部分屏幕材质顶部导航器上滑动
- azure-cosmosdb - GetItemLinqQueryable 不返回任何项目
- c - 内联汇编后指针取消引用 (SIGSEGV) 失败
- mysql - 从 3 个表中获取值到汇总表 SQL
- html - 如何使用golang连接锚标记的href属性中的变量值
- docker - Kubernetes 中部署的 Apache 气流中的 Kubernetes 执行程序和私有 Docker 映像无法正常工作
- wordpress - 如果用户未登录,Wordpress 重定向到登录页面