PHPで浮動小数点数の剰余(余り)を計算するための重要な関数であるfmod()
について、基本から応用まで詳しく解説します。
fmod関数の基本
fmod()
関数は、2つの数値の剰余(余り)を計算します。特に浮動小数点数に対応している点が通常の%
演算子と異なります。
基本構文
float fmod ( float $x , float $y )
$x
: 被除数(割られる数)$y
: 除数(割る数)- 戻り値:
$x
を$y
で割った余り(浮動小数点数)
基本的な使用例
<?php
echo fmod(5.7, 1.3); // 出力: 0.5
echo "\n";
echo 5.7 % 1.3; // 通常の%演算子では警告が出る可能性あり
echo "\n";
echo fmod(10.5, 2.5); // 出力: 0.5
echo "\n";
echo fmod(-10.5, 2.5); // 出力: -0.5 (符号は被除数に依存)
%演算子との違い
PHP の %
演算子は主に整数に対して使用されます。浮動小数点数に使うとPHPバージョンによっては警告が出たり、整数にキャストされることがあります。
<?php
// %演算子とfmodの比較
$a = 10.5;
$b = 3.2;
// fmod - 浮動小数点数のまま計算
$result1 = fmod($a, $b);
echo "fmod($a, $b) = $result1\n"; // 出力: fmod(10.5, 3.2) = 0.9
// %演算子 - 整数にキャストされる可能性あり
$result2 = $a % $b;
echo "$a % $b = $result2\n"; // PHPバージョンによって結果が異なる
実践的な使用例
例1: 周期的な値の計算
<?php
// 時計の針の角度計算
function clock_angle($hours, $minutes) {
// 時針の角度: 1時間 = 30度, 1分 = 0.5度
$hour_angle = ($hours % 12) * 30 + $minutes * 0.5;
// 分針の角度: 1分 = 6度
$minute_angle = $minutes * 6;
// 針の間の角度差
$angle = abs($hour_angle - $minute_angle);
// 最小角を返す(180度以下)
return min($angle, 360 - $angle);
}
// 3時15分の時計の針の角度
$angle = clock_angle(3, 15);
echo "3時15分の時針と分針の角度差: {$angle}度\n";
例2: 循環パターンの生成
<?php
// 日付に基づく循環パターンの生成
function get_rotation_pattern($date, $patterns) {
$timestamp = strtotime($date);
$days_since_epoch = floor($timestamp / 86400); // 1970年からの日数
$pattern_count = count($patterns);
$index = (int)fmod($days_since_epoch, $pattern_count);
return $patterns[$index];
}
// 3パターンのローテーション
$patterns = ['A班', 'B班', 'C班'];
$today = date('Y-m-d');
$assigned_team = get_rotation_pattern($today, $patterns);
echo "今日({$today})の担当: {$assigned_team}\n";
例3: 金融計算での端数処理
<?php
// 端数を特定の単位に合わせる(例: 10円単位)
function round_to_nearest($amount, $unit) {
$remainder = fmod($amount, $unit);
if ($remainder >= $unit / 2) {
return $amount + ($unit - $remainder);
} else {
return $amount - $remainder;
}
}
$price = 1234.56;
echo "元の価格: {$price}円\n";
echo "10円単位に四捨五入: " . round_to_nearest($price, 10) . "円\n";
echo "100円単位に四捨五入: " . round_to_nearest($price, 100) . "円\n";
特殊なケースと注意点
負の数での動作
<?php
echo "正の数の例:\n";
echo "fmod(7.5, 2.5) = " . fmod(7.5, 2.5) . "\n"; // 出力: 0
echo "fmod(7.5, 2.0) = " . fmod(7.5, 2.0) . "\n"; // 出力: 1.5
echo "負の数の例:\n";
echo "fmod(-7.5, 2.5) = " . fmod(-7.5, 2.5) . "\n"; // 出力: -0
echo "fmod(-7.5, 2.0) = " . fmod(-7.5, 2.0) . "\n"; // 出力: -1.5
echo "fmod(7.5, -2.5) = " . fmod(7.5, -2.5) . "\n"; // 出力: 0
echo "fmod(-7.5, -2.5) = " . fmod(-7.5, -2.5) . "\n";// 出力: -0
fmod()
の結果の符号は常に被除数(最初のパラメータ)の符号に従います。
ゼロ除算の扱い
<?php
// ゼロ除算
try {
$result = fmod(10.5, 0);
echo "結果: $result\n";
} catch (DivisionByZeroError $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
PHP 7以降では、ゼロで除算するとDivisionByZeroError
例外が発生します。
浮動小数点数の精度問題
<?php
// 浮動小数点数の精度問題
$result = fmod(0.1 + 0.7, 0.1);
echo "fmod(0.1 + 0.7, 0.1) = $result\n"; // 期待: 0、実際: 小さな値
// より安全な比較方法
function is_multiple_of($number, $divisor, $epsilon = 0.0000001) {
return abs(fmod($number, $divisor)) < $epsilon ||
abs(fmod($number, $divisor) - $divisor) < $epsilon;
}
if (is_multiple_of(0.1 + 0.7, 0.1)) {
echo "0.8は0.1の倍数です\n";
} else {
echo "0.8は0.1の倍数ではありません\n";
}
数学的な応用例
例4: 数学的周期性の実装
<?php
// 角度を0-360度の範囲に正規化
function normalize_angle($angle) {
return fmod($angle, 360.0) + ($angle < 0 ? 360 : 0);
}
// 異なる角度の正規化
$angles = [-450, -90, 0, 90, 180, 450, 810];
foreach ($angles as $angle) {
$normalized = normalize_angle($angle);
echo "角度 {$angle}° は 0-360°の範囲内では {$normalized}°\n";
}
例5: 周期関数の実装
<?php
// 三角波関数の実装
function triangle_wave($x, $period = 1.0) {
$normalized = fmod($x, $period) / $period;
if ($normalized < 0) $normalized += 1.0;
return $normalized < 0.5 ?
$normalized * 2 :
2 - $normalized * 2;
}
// 三角波関数の値をプロット
echo "三角波関数の値:\n";
for ($x = 0; $x <= 2; $x += 0.25) {
$value = triangle_wave($x);
$bar = str_repeat("*", (int)($value * 40));
echo sprintf("x=%.2f: [%-40s] %.2f\n", $x, $bar, $value);
}
まとめ
fmod()
関数は以下の場面で特に有用です:
- 浮動小数点数の余りを正確に計算する必要がある場合
- 循環パターンや周期性を持つプログラムの実装
- 金融計算などの高精度な数値演算
- グラフィックプログラミングでの角度や座標の計算
他の言語との互換性も高く、C言語の同名関数と同様の動作をするため、アルゴリズムを移植する際にも便利です。浮動小数点数を扱う際の精度の問題には注意が必要ですが、適切に使用することで多くの数学的処理を効率的に実装できます。