閉じる

C言語のisinfとisnanで無限大やNaN(非数)を判定する

数値計算の途中で想定外の値が出ると、プログラムは一気に不安定になります。

そこで役立つのが、無限大(infinity)やNaN(非数)を検出するisinfisnanです。

C言語初心者でも安全に判定できるよう、仕組みや戻り値、実用的なサンプルコードまで丁寧に解説します

また、正負の無限大の見分け方や注意点も併せて学びます。

isinfとisnanとは

無限大(infinity)とNaN(非数)の基礎

浮動小数点演算では、桁あふれや不正な演算の結果として無限大(+∞や−∞)やNaN(Not a Number)が生じることがあります。

たとえば非常に大きな数の演算で範囲を超えた場合は無限大、0除算や未定義の数学操作(例: 0/0、√−1)ではNaNが発生します。

NaNはどの値とも等しくない(自分自身とも等しくない)という性質を持ちます

浮動小数点の振る舞いは多くの環境でIEEE 754に準拠します。

この規格に基づき、Cの標準ライブラリは無限大やNaNを扱うための定数や判定マクロを提供しています

判定に使う標準ライブラリ

<math.h>にはisinfisnanが用意されており、引数が無限大NaNかをそれぞれ判定できます。

これらはC99以降では型に依らず(float/double/long double)使えるマクロとして実装されています。

基本はmath.hをインクルードして、条件分岐で利用します

加えて、INFINITYNANといった定数マクロ、isfiniteisnormalなどの関連マクロも同じヘッダにあります。

戻り値と使いどころ

isinf(x)isnan(x)条件が真なら非0、偽なら0を返します。

戻り値の具体的な数値(1や−1など)には依存せず、!= 0で扱うのが安全です。

演算結果や外部入力に対して「異常値フィルタ」を掛ける用途で特に有用です

ログ出力や再計算、デフォルト値への置換などの分岐に活用できます。

以下に主な関数と判定対象の概要を表にまとめます。

関数(マクロ)真になる条件備考
isinf(x)xが+∞または−∞符号はsignbit(x)で判別
isnan(x)xがNaNNaNは比較演算に向きません
isfinite(x)xが有限値無限大とNaNを除外
isnormal(x)xが正規化数0と非正規化数、無限大、NaNは偽

無限大かNaNかの一次判定にisinfisnan、さらに「普通の数か」まで含めた品質チェックにisfinite/isnormalを足す、という使い分けが基本です。

isinfとisnanの基本の使い方

includeとリンク方法

使うヘッダは#include <math.h>です。

多くのUNIX系環境(GCC/Clang)では、数学ライブラリの関数を使うときリンク時に-lmが必要になります。

判定マクロ自体は関数呼び出しを伴わないこともありますが、慣習的に-lmを付けておくと安心です

  • GCC/Clangの例: gcc main.c -std=c11 -Wall -Wextra -lm
  • MSVCの例: cl /W4 /std:c11 main.c(Windowsでは通常-lmは不要)

if文での判定パターン

基本的な流れは、isnanを最初に確認し、次にisinf、最後に通常の値の処理にフォールバックします。

NaNは他の判定を不安定にすることがあるため、最初に弾くのが実務的です。

  • 例: if (isnan(x)) { /* NaNの処理 / } else if (isinf(x)) { / 無限大の処理 / } else { / 有限の通常処理 */ }

正負の無限大を分けたいときはsignbit(x)を併用します。

戻り値を1や−1に期待せずsignbitで符号を取るのが移植性の高い書き方です。

float/double/long doubleの扱い

C99以降のisinf/isnan型に依存しないマクロなので、floatでもdoubleでもlong doubleでも同じように呼べます。

printfで出力する際は書式指定子に注意し、double%flong double%Lfを使います

リテラルは1.0f(float)、1.0(double)、1.0L(long double)のように後置のサフィックスで型を表します。

サンプルコードの流れ

以下のサンプルでは、さまざまな値に対してisnan/isinf/isfinite/isnormal/signbitを確認し、結果を見やすく表示します。

無限大やNaNの生成には安全な定数INFINITYNANを用います

C言語
// 判定: isinf, isnan の使い方デモ
// コンパイル例:
//   gcc main.c -std=c11 -Wall -Wextra -lm
#include <stdio.h>
#include <math.h>     // isinf, isnan, isfinite, isnormal, INFINITY, NAN, signbit
#include <float.h>    // 参考用の定数(今回は未使用でも可)

// 真偽を "true"/"false" で表示するユーティリティ
static const char* tf(int cond) { return cond ? "true" : "false"; }

// 値の分類結果を表示
static void print_fp_info(const char* name, double x) {
    // 値の表示は参考程度。NaNやinfは実装により "nan", "inf" 等で出ます。
    printf("[%s] value=%g\n", name, x);
    printf("  isnan    : %s\n", tf(isnan(x)));
    printf("  isinf    : %s\n", tf(isinf(x)));
    printf("  isfinite : %s\n", tf(isfinite(x)));
    printf("  isnormal : %s\n", tf(isnormal(x)));
    // 符号は signbit で取得。負のゼロ(-0.0)でも真になります。
    printf("  signbit  : %s\n", tf(signbit(x)));
    // 無限大の符号を報告(参考)
    if (isinf(x)) {
        printf("  -> infinity sign: %s\n", signbit(x) ? "negative (-inf)" : "positive (+inf)");
    }
    puts("");
}

int main(void) {
    double a = 1.5;          // 通常の有限値
    double b = INFINITY;     // 正の無限大
    double c = -INFINITY;    // 負の無限大
    double d = NAN;          // NaN(非数)
    double e = 0.0;          // ゼロ(有限、正規/非正規かは値次第)
    double f = -0.0;         // 負のゼロ(符号ありゼロ)

    print_fp_info("finite", a);
    print_fp_info("+inf  ", b);
    print_fp_info("-inf  ", c);
    print_fp_info("NaN   ", d);
    print_fp_info("+0.0  ", e);
    print_fp_info("-0.0  ", f);
    return 0;
}

出力例(環境により表記が変わることがあります)。

[finite] value=1.5
  isnan    : false
  isinf    : false
  isfinite : true
  isnormal : true
  signbit  : false

[+inf  ] value=inf
  isnan    : false
  isinf    : true
  isfinite : false
  isnormal : false
  signbit  : false
  -> infinity sign: positive (+inf)

[-inf  ] value=-inf
  isnan    : false
  isinf    : true
  isfinite : false
  isnormal : false
  signbit  : true
  -> infinity sign: negative (-inf)

[NaN   ] value=nan
  isnan    : true
  isinf    : false
  isfinite : false
  isnormal : false
  signbit  : false

[+0.0  ] value=0
  isnan    : false
  isinf    : false
  isfinite : true
  isnormal : false
  signbit  : false

[-0.0  ] value=-0
  isnan    : false
  isinf    : false
  isfinite : true
  isnormal : false
  signbit  : true

isnanはNaNだけを検出し、isinfは符号と無関係に無限大を検出するため、signbitと組み合わせれば+∞/−∞まで区別できます

無限大とNaNを用意する方法

無限大を作る

最も安全で移植性が高いのはINFINITY定数(および+/-での符号付け)を使う方法です。

演算で無理に作らずINFINITYを直接使うのが初心者にはおすすめです。

用途に応じて以下の定数も使えます。

  • INFINITY: 正の無限大のfloat定数
  • HUGE_VAL, HUGE_VALF, HUGE_VALL: 無限大相当の定数(主にエラー戻り値で使われます)

マイナスを付ければ-INFINITYで負の無限大になります

NaNを作る

NAN定数を使うのが簡単で安全です。

計算式で0/0を作るなどの手段は避け、定数NANnan("")系の関数を使うのがよいでしょう。

C99以降ではNaNのペイロードを指定できるnan/nanf/nanlも用意されています。

C言語
#include <math.h>

float       nf = NAN;          // floatのNaN
double      nd = NAN;          // doubleのNaN(プロモーションされても可)
long double nl = NAN;          // long doubleへ代入も可

// ペイロード付きNaN(空文字で汎用的にNaNを得る)
double nd2 = nan("");

NaNは演算に混ざると結果をNaNに伝播させることが多いため、早めの検出とハンドリングが重要です

正の無限大と負の無限大の区別

isinf(x)は符号を返しません。

符号判定にはsignbit(x)を使います

C言語
#include <math.h>
#include <stdio.h>

int main(void) {
    double x = -INFINITY;
    if (isinf(x)) {
        // signbit(x) は x が負なら true
        printf("x is %s infinity\n", signbit(x) ? "negative" : "positive");
    }
    return 0;
}
実行結果
x is negative infinity

正負の無限大を明示的に生成したい場合はINFINITYに符号を付けるか、copysign(INFINITY, -1.0)のように符号だけを移す関数を使えます

初心者が知っておきたい注意点

NaNは==で比較しない

NaNはどの値とも等しくありません

したがってx == x通常は真ですがNaNでは偽になります。

NaN判定にはisnan(x)を必ず使い、比較演算で代用しないでください。

C言語
#include <stdio.h>
#include <math.h>

int main(void) {
    double x = NAN;
    printf("x == x ? %s\n", (x == x) ? "true" : "false");   // false になる
    printf("isnan(x) ? %s\n", isnan(x) ? "true" : "false"); // true になる
    return 0;
}
実行結果
x == x ? false
isnan(x) ? true

0除算で作らない

浮動小数点の0除算は多くの実装で+∞やNaNを作りますが、実行時に浮動小数点例外を発生させたり、最適化やプラットフォーム差で挙動が変わる可能性があります。

教材目的以外で0除算による生成は避けINFINITY/NANの定数を使うのが安全です。

関連関数(isfinite, isnormal)の簡単な違い

isfinite(x)有限であることを確認し、無限大とNaNを除外します。

isnormal(x)正規化数(十分な桁を持つ通常の浮動小数点数)かどうかを判定し、0や非正規化数、無限大、NaNを偽にします。

「計算を続行してよい通常の値か」を厳しめに見たいときはisnormal、緩めに「有限ならOK」ならisfiniteという使い分けです。

判定対象isfiniteisnormal備考
通常の有限値例: 1.0, 1.5
非正規化数非正規はごく小さい数(環境依存)
+0.0, −0.00は正規ではない
+∞, −∞無限大
NaN非数

入力の妥当性チェックにはisfinite、数値的に信頼できる範囲に絞るならisnormalという段階的なチェックが実務で便利です。

まとめ

isinfとisnanは、浮動小数点計算の健全性を守るための第一関門です。

math.hをインクルードし、isnanでNaNを最初に排除、isinfで無限大を検知し、必要に応じてsignbitで符号を判断すると、安全で移植性の高いコードになります。

無限大やNaNを作る際はINFINITYNANなどの定数を使い、0除算で無理に生成しない方針が肝要です。

さらにisfiniteisnormalを組み合わせれば、入力検証やエラー処理の精度を高められます。

初心者の段階から「異常値をまず疑い、正しく判定する」習慣を身につけることで、後の不具合を大幅に減らせます

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!