PHPで数値計算を行う際、計算結果が無限大(infinity)になることがあります。このような無限値を適切に検出し処理するために使用されるのがis_infinite()
関数です。この記事では、is_infinite()
関数の基本的な使い方から実践的な活用法まで、詳しく解説していきます。
is_infinite関数とは?
is_infinite()
は、指定された値が無限大(正の無限大または負の無限大)かどうかを判定するPHPの組み込み関数です。数値計算でオーバーフローが発生した場合や、ゼロ除算が行われた場合などに発生する無限値を検出できます。
基本的な構文
is_infinite(float $value): bool
- 引数:
$value
– 判定したい値(float型) - 戻り値: 無限値の場合は
true
、有限値やNaNの場合はfalse
具体的な使用例
基本的な使用例
<?php
// 正の無限大
var_dump(is_infinite(INF)); // bool(true)
var_dump(is_infinite(1/0)); // bool(true)
// 負の無限大
var_dump(is_infinite(-INF)); // bool(true)
var_dump(is_infinite(-1/0)); // bool(true)
// 有限値
var_dump(is_infinite(42)); // bool(false)
var_dump(is_infinite(3.14)); // bool(false)
var_dump(is_infinite(-10.5)); // bool(false)
// NaN(Not a Number)
var_dump(is_infinite(NAN)); // bool(false)
var_dump(is_infinite(0/0)); // bool(false)
?>
計算結果の検証
<?php
function safeDivision($numerator, $denominator) {
$result = $numerator / $denominator;
if (is_infinite($result)) {
if ($result > 0) {
return "正の無限大";
} else {
return "負の無限大";
}
} elseif (is_nan($result)) {
return "計算不可能(NaN)";
} else {
return $result;
}
}
echo safeDivision(10, 2); // 5
echo safeDivision(10, 0); // 正の無限大
echo safeDivision(-10, 0); // 負の無限大
echo safeDivision(0, 0); // 計算不可能(NaN)
?>
実践的な活用場面
1. 数学的計算の安全性チェック
<?php
function calculateGrowthRate($initialValue, $finalValue, $periods) {
if ($periods <= 0) {
throw new InvalidArgumentException("期間は正の数である必要があります");
}
if ($initialValue == 0) {
throw new InvalidArgumentException("初期値は0にできません");
}
$growthRate = pow(($finalValue / $initialValue), (1 / $periods)) - 1;
if (is_infinite($growthRate)) {
throw new OverflowException("成長率の計算で無限値が発生しました");
}
return $growthRate;
}
try {
$rate = calculateGrowthRate(100, 200, 5);
echo "成長率: " . ($rate * 100) . "%";
} catch (Exception $e) {
echo "エラー: " . $e->getMessage();
}
?>
2. 統計計算での無限値処理
<?php
class StatisticsCalculator {
public static function calculateZScore($value, $mean, $stdDev) {
if ($stdDev == 0) {
throw new InvalidArgumentException("標準偏差は0にできません");
}
$zScore = ($value - $mean) / $stdDev;
if (is_infinite($zScore)) {
return null; // 無限値の場合はnullを返す
}
return $zScore;
}
public static function processDataSet($data) {
$mean = array_sum($data) / count($data);
$variance = 0;
foreach ($data as $value) {
$variance += pow($value - $mean, 2);
}
$stdDev = sqrt($variance / count($data));
$zScores = [];
foreach ($data as $value) {
$zScore = self::calculateZScore($value, $mean, $stdDev);
if ($zScore !== null && !is_infinite($zScore)) {
$zScores[] = $zScore;
}
}
return $zScores;
}
}
// 使用例
$dataset = [10, 20, 30, 40, 50];
$zScores = StatisticsCalculator::processDataSet($dataset);
print_r($zScores);
?>
3. APIレスポンスの検証とクリーニング
<?php
function validateAndCleanNumericData($apiResponse) {
$cleanedData = [];
foreach ($apiResponse as $key => $value) {
if (is_numeric($value)) {
$floatValue = (float)$value;
if (is_infinite($floatValue)) {
// 無限値の場合は適切なデフォルト値を設定
$cleanedData[$key] = [
'value' => null,
'status' => 'infinite',
'original' => $value
];
} elseif (is_nan($floatValue)) {
$cleanedData[$key] = [
'value' => null,
'status' => 'nan',
'original' => $value
];
} else {
$cleanedData[$key] = [
'value' => $floatValue,
'status' => 'valid',
'original' => $value
];
}
} else {
$cleanedData[$key] = [
'value' => null,
'status' => 'invalid',
'original' => $value
];
}
}
return $cleanedData;
}
// 使用例
$apiData = [
'temperature' => '25.5',
'humidity' => 'INF',
'pressure' => '-INF',
'windSpeed' => 'NAN',
'visibility' => '10.0'
];
$cleanedData = validateAndCleanNumericData($apiData);
foreach ($cleanedData as $key => $data) {
echo "{$key}: {$data['status']} (value: {$data['value']})\n";
}
?>
無限値の種類と判定
正の無限大と負の無限大の区別
<?php
function analyzeInfinity($value) {
if (is_infinite($value)) {
if ($value > 0) {
return "正の無限大 (+∞)";
} else {
return "負の無限大 (-∞)";
}
} else {
return "有限値または非数値";
}
}
// テスト
$testValues = [INF, -INF, 1/0, -1/0, 42, NAN];
foreach ($testValues as $value) {
echo "値: " . var_export($value, true) . " → " . analyzeInfinity($value) . "\n";
}
?>
無限値の生成パターン
<?php
function demonstrateInfinityCreation() {
$examples = [
'ゼロ除算(正)' => 1/0,
'ゼロ除算(負)' => -1/0,
'大きすぎる数値' => pow(10, 400),
'log(0)' => log(0),
'INF定数' => INF,
'-INF定数' => -INF,
'INF + 1' => INF + 1,
'INF * 2' => INF * 2
];
foreach ($examples as $description => $value) {
printf("%-20s: %s (is_infinite: %s)\n",
$description,
var_export($value, true),
is_infinite($value) ? 'true' : 'false'
);
}
}
demonstrateInfinityCreation();
?>
類似関数との比較と使い分け
is_infinite() vs is_finite() vs is_nan()
<?php
function compareNumericFunctions() {
$testValues = [42, 3.14, INF, -INF, NAN, 0, '123'];
echo "値\t\tis_infinite\tis_finite\tis_nan\n";
echo str_repeat("-", 50) . "\n";
foreach ($testValues as $value) {
printf("%-10s\t%-10s\t%-10s\t%-10s\n",
var_export($value, true),
is_infinite($value) ? 'true' : 'false',
is_finite($value) ? 'true' : 'false',
is_nan($value) ? 'true' : 'false'
);
}
}
compareNumericFunctions();
?>
実用的なユーティリティ関数
数値状態判定クラス
<?php
class NumericValidator {
const STATUS_FINITE = 'finite';
const STATUS_POSITIVE_INFINITE = 'positive_infinite';
const STATUS_NEGATIVE_INFINITE = 'negative_infinite';
const STATUS_NAN = 'nan';
const STATUS_INVALID = 'invalid';
public static function analyzeNumber($value) {
if (!is_numeric($value)) {
return self::STATUS_INVALID;
}
$floatValue = (float)$value;
if (is_nan($floatValue)) {
return self::STATUS_NAN;
}
if (is_infinite($floatValue)) {
return $floatValue > 0 ? self::STATUS_POSITIVE_INFINITE : self::STATUS_NEGATIVE_INFINITE;
}
return self::STATUS_FINITE;
}
public static function isCalculationSafe($value) {
$status = self::analyzeNumber($value);
return $status === self::STATUS_FINITE;
}
public static function sanitizeNumber($value, $defaultValue = 0) {
if (self::isCalculationSafe($value)) {
return (float)$value;
}
return $defaultValue;
}
}
// 使用例
$testValues = [42, INF, -INF, NAN, '123', 'abc'];
foreach ($testValues as $value) {
$status = NumericValidator::analyzeNumber($value);
$safe = NumericValidator::isCalculationSafe($value);
$sanitized = NumericValidator::sanitizeNumber($value, 999);
echo "値: " . var_export($value, true) .
" → 状態: {$status}, 安全: " . ($safe ? 'Yes' : 'No') .
", 正規化: {$sanitized}\n";
}
?>
エラーハンドリングとログ出力
無限値検出時の適切な処理
<?php
class CalculationLogger {
private static $logFile = 'calculation_errors.log';
public static function logInfinityError($operation, $operands, $result) {
$message = sprintf(
"[%s] 無限値検出 - 演算: %s, オペランド: %s, 結果: %s",
date('Y-m-d H:i:s'),
$operation,
json_encode($operands),
var_export($result, true)
);
error_log($message . "\n", 3, self::$logFile);
}
public static function safeCalculation($callback, $operands, $operationName) {
try {
$result = call_user_func_array($callback, $operands);
if (is_infinite($result)) {
self::logInfinityError($operationName, $operands, $result);
throw new OverflowException("計算結果が無限値になりました: {$operationName}");
}
return $result;
} catch (Exception $e) {
self::logInfinityError($operationName, $operands, $e->getMessage());
throw $e;
}
}
}
// 使用例
try {
$result = CalculationLogger::safeCalculation(
function($a, $b) { return $a / $b; },
[10, 0],
'division'
);
echo "結果: {$result}";
} catch (Exception $e) {
echo "エラー: " . $e->getMessage();
}
?>
パフォーマンスと最適化
大量データ処理時の効率的な実装
<?php
function filterInfiniteValues(array $data): array {
return array_filter($data, function($value) {
return is_numeric($value) && !is_infinite((float)$value);
});
}
function countInfiniteValues(array $data): array {
$counts = [
'finite' => 0,
'positive_infinite' => 0,
'negative_infinite' => 0,
'nan' => 0,
'invalid' => 0
];
foreach ($data as $value) {
if (!is_numeric($value)) {
$counts['invalid']++;
} else {
$floatValue = (float)$value;
if (is_nan($floatValue)) {
$counts['nan']++;
} elseif (is_infinite($floatValue)) {
$counts[$floatValue > 0 ? 'positive_infinite' : 'negative_infinite']++;
} else {
$counts['finite']++;
}
}
}
return $counts;
}
// 使用例
$largeDataset = [1, 2, INF, 3, -INF, NAN, 4, 5, 'invalid', 6];
$cleanData = filterInfiniteValues($largeDataset);
$statistics = countInfiniteValues($largeDataset);
echo "元のデータ数: " . count($largeDataset) . "\n";
echo "有効なデータ数: " . count($cleanData) . "\n";
print_r($statistics);
?>
まとめ
is_infinite()
関数は、PHPで数値計算における無限値を検出する重要な関数です。主な活用場面は以下の通りです:
- 数学的計算の検証: 除算やべき乗計算で発生する無限値の検出
- データ検証: APIレスポンスやユーザー入力の無限値チェック
- エラーハンドリング: 計算エラーの適切な処理
- 統計処理: 大量データから無効な値の除外
- ログ出力: 計算異常の記録と分析
is_finite()
やis_nan()
と組み合わせることで、より堅牢な数値処理システムを構築できます。無限値が発生する可能性がある数値計算では、積極的にis_infinite()
を活用して安全性を確保しましょう。