如何使用 PHP 的模數運算子
Chinese (Traditional) (中文(繁體)) translation by BinotaLiu (you can also view the original English article)
PHP 中總共有八個算數運算子。最常見的是加法 (+)、減法 (-)、乘法 (*)、與除法 (/)。 還有一個比較少人知道的,但也很重要的運算子——模數 (%)。在這篇教學裡,我們會將重點放在於介紹模數運算子。我們會討論它能做什麼以及幾個實際用途。
模數運算子是做什麼的呢?
若你有兩個變數 $a 與 $b,計算 $a % $b——通常唸作「a 模數 b (a modulo b)」或「a 模 b (a mod b)」——會回傳 $a 除以 $b 後的餘數。 模數是整數運算子,所以它會在計算餘數前先將兩邊的運算元轉換為整數。基本上模數就是計算整數除法並將無法整除的部分回傳。
模數運算子回傳值的正負號取決於被除數。在除法運算中,兩個負數相除得一個正數。 然而,這不適用於模數運算子。除數的正負號並不影響最終的結果。(譯註:除法運算系 被除數 ÷ 除數 = 商 … 餘)
來看看幾個例子:
1 |
<?php
|
2 |
|
3 |
echo 1089 % 37; |
4 |
// Output: 16
|
5 |
|
6 |
echo 1089 % -37; |
7 |
// Output: 16
|
8 |
|
9 |
echo -1089 % 37; |
10 |
// Output: -16
|
11 |
|
12 |
echo -1089 % -37; |
13 |
// Output: -16
|
14 |
|
15 |
echo -55.4 % -4.2; |
16 |
// Output: -3
|
17 |
|
18 |
echo -55.9 % -4.8; |
19 |
// Output: -3
|
20 |
|
21 |
echo -55 % -4; |
22 |
// Output: -3
|
23 |
|
24 |
?>
|
浮點數模數運算
若你想計算兩個浮點數的餘數,你可以用 fmod($dividend, $divisor) 函數。 這個函數會回傳浮點數除法後的餘數。餘數的正負號會與被除數相同,且其值將小於除數。三個數字的關聯如下:
1 |
$dividend = i*$divisor + $remainder |
在這個例子中,i 爲一整數。
你應該還記得因爲以二進位或十進位表現的限制,浮點數運算的結果不一定精確。例如,1/3 無法被精確地以十進位形式表現。 你可以一直寫 0.33333… 但你總不可能永遠寫下去。每當你多寫一個 3,這個十進位值就與它原本的數值更接近了一點,但這個數字並不會剛剛好就是 1/3。
這種類型的不精確性就導致了 fmod() 函數的問題:回傳值並不完全可信。
來看看幾個 fmod() 函數的範例:
1 |
<?php |
2 |
|
3 |
echo fmod(18.8, 2); |
4 |
// Output: 0.8 |
5 |
|
6 |
echo fmod(18.8, 0.2); |
7 |
// Output: 0.2 |
8 |
|
9 |
?> |
因爲 0.2 可以整除 18.8,我們會發現第二個值並不准。這就是電腦在進行浮點計算時使用的格式的缺點。
使用模數運算子
在這篇教學中,我們只會使用整數模數。因其較常見且有較多的應用。
確認一個數字是否是另一個數字的倍數
若第一個數字可以被第二個數字整除則模數運算的結果會是 0。這可以用來檢查一組數字中一個數字是否爲另一個的倍數。 另一個可能是更常見的用途是用來檢查一個數字是奇數還是偶數。來看看這個例子:
1 |
<?php
|
2 |
|
3 |
$colors = ['violet', 'indigo', 'blue', 'green', 'yellow', 'orange', 'red']; |
4 |
$color_count = count($colors); |
5 |
|
6 |
if($color_count % 2 == 0) { |
7 |
echo 'We have created some color pairs for you.'; |
8 |
} else { |
9 |
echo 'Please specify one more or one less color to make pairing possible.'; |
10 |
}
|
11 |
|
12 |
?>
|
在上述範例中,我們檢查了一組可能是從使用者傳來的列表,並要求使用者只可提供偶數個的顏色。
下列的範例基於類似的原因將學生分成五個一組。在實際的生活上,你需要寫更多的程式碼來給學生分組。但檢查學生總數是否是 5 的倍數的概念是相同的。
1 |
<?php
|
2 |
|
3 |
$total_students = 25; |
4 |
|
5 |
if($total_students % 5 == 0) { |
6 |
echo 'Each group of five students has been given an assignment.'; |
7 |
} else { |
8 |
echo 'Sorry, it is impossible to create groups of five students right now. Please get more students.'; |
9 |
}
|
10 |
|
11 |
?>
|
將數字改爲另一個數字的倍數
在上一節中我們使用了模數運算子來提示使用者只可提供特定倍數的輸入值。若不能這麼做的話,我們可以強制將輸入值改爲 5 或其它數字的倍數。
模數運算子提供了第一個數字處以第二個數字的餘數。這表示第一個數字減去餘數的值即是第二個數字的倍數。 舉例來說,我們可以把 28 通過減去 28 % 5 來變爲 5 的倍數。在此例中,模數會是 3。現在我們可以從原本的數字上減去 3 來讓它成爲 5 的倍數。 下面這行程式透過減去特定的值來強制把任何的正數 x 變成另一個正數 y 的倍數。
1 |
x = x - (x % y) |
前面那個 28 個學生的例子中,我們可以留下 3 個學生並把其它學生分組在一起。
1 |
<?php
|
2 |
|
3 |
$total_students = 28; |
4 |
|
5 |
if($total_students % 5 == 0) { |
6 |
echo 'Each group of five students has been given an assignment.'; |
7 |
} else { |
8 |
$removed_students = $total_students % 5; |
9 |
$total_students -= $removed_students; |
10 |
echo 'We have created groups of five students by removing the last '.$removed_students.' students from the list.'; |
11 |
}
|
12 |
|
13 |
?>
|
在輸入中加上限制
就如同我一開始在這篇文章提到的,遇到正數時模數運算子會回傳介於 0 與 N - 1 的數,N 爲除數。 這表示你可以給任何輸入值設定上限,並重複且按步執行一些操作。來看看這個例子:
1 |
<?php
|
2 |
|
3 |
$colors = ['violet', 'indigo', 'blue', 'green', 'yellow']; |
4 |
|
5 |
$color_count = count($colors); |
6 |
$total_images = 180; |
7 |
$background_color = ''; |
8 |
|
9 |
for($i = 0; $i < $total_images; $i++) { |
10 |
$background_color = $colors[$i % $color_count]; |
11 |
echo "Setting image background color to $background_color."; |
12 |
}
|
13 |
|
14 |
?>
|
在上面這個例子中,我們只有五個顏色但有 180 張圖片。這表示我們必須在五個顏色中循環並將其分配給全部的圖片。 模數運算子恰巧符合這個需求。$i % $color_count 的值會被限制在 0 到 (5 - 1) ,也就是 4,之間。這樣一來,我們就可以輕鬆地依序抓取陣列中所有的顏色。
在迴圈中每循環 N 次時執行特定任務
在迴圈中循環時,我們可以通過檢查傳進迴圈中的增值變數值來在每 n 次迭代時執行特定任務。 我想到了一個實際的用途:在需要長時間執行的程式中提示使用者。假設你需要使用 PHP 來修改 1,000 張不同的圖片。若改動很明顯的話,這個程式會需要跑一段時間來更新所有的圖片。
這時,使用者不會知道程式是當掉了還是真的有在跑。此時我們可以在每編輯 10 張圖片後提示使用者目前的進度。
1 |
<?php
|
2 |
|
3 |
$total_images = 1000; |
4 |
|
5 |
for($i = 1; $i <= $total_images; $i++) { |
6 |
update_images($image_resource); |
7 |
if($i % 10 == 0) { |
8 |
$percent = $i*100/$total_images; |
9 |
echo 'Already processed '.$percent.'% images.'; |
10 |
}
|
11 |
}
|
12 |
|
13 |
?>
|
上述例子中,我們假設有一個 update_images() 函數。你可以用其它程式碼來取代它,例如縮放圖片、加上浮水印、變成灰階……等。(如果你想學學自己用 PHP 來編輯圖片,你可以看看我的 PHP GD 圖片編輯教學)
在不同度量單位間轉換
模數運算子也可以轉換不同度量單位時使用。例如,你可以用它來將時長從秒轉換爲小時、分鐘、與秒。 同樣地,你也可以將一個大數字的公分轉換爲公里、公尺、與公分。來看看這個例子:
1 |
<?php
|
2 |
|
3 |
$total_seconds = 32987; |
4 |
|
5 |
$hours = (int)($total_seconds / 3600); |
6 |
$minutes = (int)(($total_seconds - 3600 * $hours )/60); |
7 |
$seconds = $total_seconds % 60; |
8 |
|
9 |
echo 'Hours:'.$hours.' Minutes:'.$minutes.' Seconds:'.$seconds.''; |
10 |
|
11 |
?>
|
一開始我們把總秒數除以 3,600 並將其轉換爲整數。如此一來我們得到了小時數,因爲每個小時有 3,600 秒。
接下來,我們將原本的秒數減去 3600 * $hours,來去掉我們已經轉換爲小時的秒數。 現在將它除以 60 就得到了分鐘數。最後,我們使用模數運算子來取得剩下的秒數。
結語
如同你在這篇教學例看到的,模數運算子不僅簡單,且可廣泛引用。 一開始我們展示了正數、負數、以及浮點數的模數。之後,我們看了一些模數常見的使用場景。
若你對於這篇教學有任何問題,請在留言中告訴我。你有想到其它可以使用模數的場景嗎?請在下方跟其它讀者分享。



