我只是想知道$ x是否可被$ y整除。例如,假设:
$x = 70;
$y = .1;
我尝试的第一件事是:
$x % $y
当这两个数字都是整数时似乎有效,但如果它们不是整数就会失败,如果$y
是小于1的小数则返回“除以零”错误,那么我尝试了:
fmod($x,$y)
返回同样令人困惑的结果,“0.099999999999996”。
php.net声明fmod()
:
返回除数(x)除以除数(y)
的浮点余数
根据我的计算器70 / .1 = 700
。这意味着余数为0.有人可以解释一下我做错了吗?
答案 0 :(得分:10)
一种解决方案是进行正常的除法,然后将该值与下一个整数进行比较。如果结果是整数或非常接近该整数,则结果可以被整除:
$x = 70;
$y = .1;
$evenlyDivisable = abs(($x / $y) - round($x / $y, 0)) < 0.0001;
这会减去两个数字并检查绝对差值是否小于某个舍入误差。这是比较浮点数的常用方法,因为根据浮点数的不同,表示可能会有所不同:
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;'
参见此演示:
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)
答案 1 :(得分: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;
答案 2 :(得分:4)
bitbucket中有一个纯数学库:https://bitbucket.org/zdenekdrahos/bn-php
解决方案将是:
php > require_once 'bn-php/autoload.php';
php > $eval = new \BN\Expression\ExpressionEvaluator();
php > $operators = new \BN\Expression\OperatorsFactory();
php > $eval->setOperators($operators->getOperators(array('%')));
php > echo $eval->evaluate('70 % 0.1'); // 0
0.00000000000000000000
在php5.3上测试
答案 3 :(得分:0)
浮点表示因机器而异。值得庆幸的是有标准。 PHP通常使用IEEE 754双精度格式进行浮点表示,这是最常见的标准之一。 See here了解更多相关信息。有了这个,请看看this calculator,以便更好地理解为什么。至于如何我喜欢Tim的解决方案,特别是如果你正在处理用户输入。
答案 4 :(得分:0)
正如你所说,使用模数运算符在它是一个整数时工作正常,所以为什么不设置它以便它对整数运算。在我的情况下,我需要检查0.25:
的可分性$input = 5.251
$x = round($input, 3); // round in case $input had more decimal places
$y = .25;
$result = ($x * 1000) % ($y * 1000);
在你的情况下:
$input = 70.12
$x = round($input, 2);
$y = .1;
$result = ($x * 100) % ($y * 100);