2014-02-20 45 views
9

我只是想知道$ x是否可以被$ y整除。例如起見假設:

$x = 70; 
$y = .1; 

我想的第一件事是:

$x % $y 

這似乎當這兩個數字都是整數的工作,但如果他們沒有失敗,如果$y是一個十進制小於1倍的回報一個「零除」的錯誤,所以然後我試過:

fmod($x,$y) 

這返回同樣令人困惑的結果,「0.099999999999996」。

php.net指出fmod()

返回除數(Y)除以股息(X)的浮點餘

那麼根據我的計算器70/.1 = 700。這意味着餘數是0.有人可以解釋我做錯了什麼嗎?

+0

並非所有值都具有一個確切的浮點數的表示:這是因此沒有「[完美]均勻地」(除了整數的情況外)就像「足夠接近」一樣。 – user2864740

+0

[這也發生在bcmod()上。](http://codepad.viper-7.com/ztb1Y2) –

回答

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) 
+0

我對這個解決方案很感興趣。一個問題,爲什麼使用減法和'<0.0001'而不是簡單的'($ x/$ y)== round($ x/$ y)'? – billynoah

+0

@billynoah我修改了我的答案,解釋了爲什麼花車應該這樣比較。 – TimWolla

+0

謝謝蒂姆,我想我明白了,但是在上面的評論中,我建議的方法會在什麼情況下返回與您不同的結果? – billynoah

6

0.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; 
+0

這些數字基於表單中的用戶輸入。它們可以是任何數字。 – billynoah

+0

我修正了它,以便唯一的基於int的大小限制是y的最終大小,而不是x和y之間的差異。允許的差異僅限於花車的限制。 – Tyler

+1

+1爲「.1在二進制浮點中沒有確切的表示」(請參閱​​愛國者錯誤:http://sydney.edu.au/engineering/it/~alum/patriot_bug.html) – dognose

0

浮點表示因機器而異。謝天謝地有標準。 PHP通常使用IEEE 754雙精度格式進行浮點表示,這是最常見的標準之一。 See here瞭解更多信息。有鑑於此,請參閱this calculator以便更好地瞭解爲什麼。至於如何我喜歡蒂姆的解決方案,特別是如果你正在處理用戶輸入。

4

有一個純數學庫中到位桶: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測試

幣:http://www.php.net/manual/en/function.bcmod.php#111276

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); 
相關問題