确定$ x是否可以在PHP中均衡地被$ y整除

bil*_*oah 9 php floating-point modulus

我只是想知道$ x是否可被$ y整除.例如,假设:

$x = 70;
$y = .1;
Run Code Online (Sandbox Code Playgroud)

我尝试的第一件事是:

$x % $y
Run Code Online (Sandbox Code Playgroud)

这似乎在两个数字都是整数时有效,但如果它们不是则失败,如果$y是小于1的小数返回"除以零"错误,那么我尝试:

fmod($x,$y)
Run Code Online (Sandbox Code Playgroud)

哪个返回同样令人困惑的结果,"0.099999999999996".

php.net说fmod():

返回除数(x)除以除数(y)的浮点余数

好吧根据我的计算器70 / .1 = 700.这意味着余数为0.有人可以解释一下我做错了什么吗?

Tim*_*lla 10

一种解决方案是进行正常除法,然后将值与下一个整数进行比较.如果结果是整数或非常接近该整数,则结果可以被整除:

$x = 70;
$y = .1;

$evenlyDivisable = abs(($x / $y) - round($x / $y, 0)) < 0.0001;
Run Code Online (Sandbox Code Playgroud)

这会减去两个数字并检查绝对差值是否小于某个舍入误差.这是比较浮点数的常用方法,因为根据浮点数的方式,表示可能会有所不同:

php> 0.1 + 0.1 + 0.1 == 0.3
bool(false)
php> serialize(.3)
'd:0.29999999999999999;'
php> serialize(0.1 + 0.1 + 0.1)
'd:0.30000000000000004;'
Run Code Online (Sandbox Code Playgroud)

看这个演示:

php> $x = 10;
int(10)
php> $y = .1;
double(0.1)
php> abs(($x / $y) - round($x / $y, 0)) < 0.0001;
bool(true)
php> $y = .15;
double(0.15)
php> abs(($x / $y) - round($x / $y, 0)) < 0.0001;
bool(false)
Run Code Online (Sandbox Code Playgroud)


Tyl*_*ler 6

.1在二进制浮点中没有精确表示,这是导致错误结果的原因.您可以将它们乘以足够大的10的幂,这样它们就是整数,然后使用%,然后转换回来.这依赖于它们不会因为一个足够大的因素而不同,乘以10的幂会导致其中一个溢出/丢失精度.像这样:

$x = 70;
$y = .1;
$factor = 1.0;
while($y*$factor != (int)($y*$factor)){$factor*=10;}
echo ($x*$factor), "\n";
echo ($y*$factor), "\n";
echo (double)(($x*$factor) % ($y*$factor))/$factor;
Run Code Online (Sandbox Code Playgroud)