C言語の非数(nan)と無限大(inf)を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
非数(nan:Not a Number)と無限大(inf:∞)
非数(nan:Not a Number)とは,に浮動小数点数の演算結果で不正な値を表します.
C言語では正の非数の場合はnan,負の非数の場合は-nanになります.
無限大(inf:∞)とは,浮動小数点数のオーバーフローを表します.
正のオーバーフローの場合は正の無限大「inf:∞」,負のオーバーフローの場合は負の無限大「-inf:-∞」になります.
オーバーフローについて知りたいあなたはこちらからどうぞ.
IEEE 754で浮動小数点数の非数と無限大は下表になります.
種類 | 符号 | 指数部(exponent) | 仮数部(fraction) |
---|---|---|---|
非数 | 最上位ビットが0なら正,1なら負 | 全て1 | 0以外の値 |
無限大 | 最上位ビットが0なら正,1なら負 | 全て1 | 0 |
1 2 |
int isnan(x); int isinf(x); |
isnan/isinf関数は,それぞれ非数か無限大であるかを判定して返す関数で,C99からマクロで実装されています.
isnan/isinf関数を利用して非数と無限大のコードを解説します.
C言語で非数になるコード
C言語で非数になるコードを紹介します.
コードで利用するsqrt/log関数を知りたいあなたはこちらからどうぞ.
isnan関数の使い方
C言語のisnan関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> int main(void) { double d = 0.0 / 0.0; printf("%lf / %lf = %lf\n", 0.0, 0.0, d); printf("isnan(%lf) = %d\n", d, isnan(d)); printf("%lf - %lf = %lf\n", INFINITY, INFINITY, INFINITY - INFINITY); printf("%lf / %lf = %lf\n", INFINITY, INFINITY, INFINITY / INFINITY); printf("sqrt(%lf) = %lf\n", -1.0, sqrt(-1.0)); printf("log(%lf) = %lf\n", -1.0, log(-1.0)); printf("(%lf == %lf) = %d\n", NAN, NAN, NAN == NAN); printf("(%lf != %lf) = %d\n", NAN, NAN, NAN != NAN); printf("(%lf < %lf) = %d\n", NAN, NAN, NAN < NAN); printf("(%lf <= %lf) = %d\n", NAN, NAN, NAN <= NAN); printf("(%lf > %lf) = %d\n", NAN, NAN, NAN > NAN); printf("(%lf >= %lf) = %d\n", NAN, NAN, NAN >= NAN); printf("(%lf == %lf) = %d\n", NAN, -NAN, NAN == -NAN); printf("(%lf != %lf) = %d\n", NAN, -NAN, NAN != -NAN); printf("(%lf < %lf) = %d\n", NAN, -NAN, NAN < -NAN); printf("(%lf <= %lf) = %d\n", NAN, -NAN, NAN <= -NAN); printf("(%lf > %lf) = %d\n", NAN, -NAN, NAN > -NAN); printf("(%lf >= %lf) = %d\n", NAN, -NAN, NAN >= -NAN); return 0; } |
実行結果は以下になります.
非数の演算結果が得られていることがわかります.
非数同士による等値演算子と関係演算子の比較結果は,通常の演算とは異なる結果になっていることに注意して下さい.
例えば,(nan == nan)の返り値は0なので,異なる値という判定になります.
また,nan != nanの返り値は1になっています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ gcc nan.c -lm $ a.out 0.000000 / 0.000000 = -nan isnan(-nan) = 1 inf - inf = nan inf / inf = nan sqrt(-1.000000) = -nan log(-1.000000) = -nan (nan == nan) = 0 (nan != nan) = 1 (nan < nan) = 0 (nan <= nan) = 0 (nan > nan) = 0 (nan >= nan) = 0 (nan == -nan) = 0 (nan != -nan) = 1 (nan < -nan) = 0 (nan <= -nan) = 0 (nan > -nan) = 0 (nan >= -nan) = 0 |
isnan関数の自作関数
isnan関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define DBL_EXPONENT_MASK 0x7ff0000000000000ULL #define DBL_FRACTION_MASK 0x000fffffffffffffULL #define FLT_EXPONENT_MASK 0x7f800000ULL #define FLT_FRACTION_MASK 0x007fffffULL #define LDBL_EXPONENT_MASK 0x7fffULL #define LDBL_FRACTION_MASK 0xffffffffffff0000ULL int myisnan(double x) { union { double d; long l; } y = {x}; if ((y.l & DBL_EXPONENT_MASK) == DBL_EXPONENT_MASK && (y.l & DBL_FRACTION_MASK) != 0) { return 1; } return 0; } int myisnanf(float x) { union { float f; int i; } y = {x}; if ((y.i & DBL_EXPONENT_MASK) == DBL_EXPONENT_MASK && (y.i & DBL_FRACTION_MASK) != 0) { return 1; } return 0; } int myisnanl(long double x) { union { long double ld; long l[2]; } y = {x}; if ((y.l[1] & LDBL_EXPONENT_MASK) == LDBL_EXPONENT_MASK && ((y.l[0] != 0) && (y.l[1] & LDBL_FRACTION_MASK) != 0)) { return 1; } return 0; } int main(void) { long double ld; double d; float f; d = f = ld = 0.0 / 0.0; printf(" myisnan(%lf) = %d\n", d, myisnan(d)); printf("myisnanf(%f) = %d\n", f, myisnanf(f)); printf("myisnanl(%Lf) = %d\n", ld, myisnanl(ld)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc mynan.c -lm $ a.out myisnan(-nan) = 1 myisnanf(-nan) = 1 myisnanl(-nan) = 1 |
C言語で無限大になるコード
C言語で無限大になるコードを紹介します.
コードで利用するexp/log関数を知りたいあなたはこちらからどうぞ.
isinf関数の使い方
isinf関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> #include <float.h> int main(void) { double d = 1.0 / 0.0; printf("%lf / %lf = %lf\n", 1.0, 0.0, d); printf("%lf / %lf = %lf\n", -1.0, 0.0, -1.0 / 0.0); printf("isinf(%lf) = %d\n", INFINITY, isinf(INFINITY)); printf("%lf + %lf = %lf\n", INFINITY, INFINITY, INFINITY + INFINITY); printf("%lf * %lf = %lf\n", INFINITY, INFINITY, INFINITY * INFINITY); printf("%le * %le = %le\n", DBL_MAX, 2.0, DBL_MAX * 2.0); printf("%le * %le = %le\n", -DBL_MAX, 2.0, -DBL_MAX * 2.0); printf("exp(%lf) = %le\n", 65536.0, exp(65536.0)); printf("log(%lf) = %lf\n", 0.0, log(0.0)); printf("(%lf == %lf) = %d\n", INFINITY, INFINITY, INFINITY == INFINITY); printf("(%lf != %lf) = %d\n", INFINITY, INFINITY, INFINITY != INFINITY); printf("(%lf < %lf) = %d\n", INFINITY, INFINITY, INFINITY < INFINITY); printf("(%lf <= %lf) = %d\n", INFINITY, INFINITY, INFINITY <= INFINITY); printf("(%lf > %lf) = %d\n", INFINITY, INFINITY, INFINITY > INFINITY); printf("(%lf >= %lf) = %d\n", INFINITY, INFINITY, INFINITY >= INFINITY); printf("(%lf == %lf) = %d\n", INFINITY, -INFINITY, INFINITY == -INFINITY); printf("(%lf != %lf) = %d\n", INFINITY, -INFINITY, INFINITY != -INFINITY); printf("(%lf < %lf) = %d\n", INFINITY, -INFINITY, INFINITY < -INFINITY); printf("(%lf <= %lf) = %d\n", INFINITY, -INFINITY, INFINITY <= -INFINITY); printf("(%lf > %lf) = %d\n", INFINITY, -INFINITY, INFINITY > -INFINITY); printf("(%lf >= %lf) = %d\n", INFINITY, -INFINITY, INFINITY >= -INFINITY); return 0; } |
実行結果は以下になります.
非数同士とは異なり,無限大同士による等値演算子と関係演算子の評価結果は,通常の演算と同様の結果になっていることに注意して下さい.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ gcc inf.c -lm $ a.out 1.000000 / 0.000000 = inf -1.000000 / 0.000000 = -inf isinf(inf) = 1 inf + inf = inf inf * inf = inf 1.797693e+308 * 2.000000e+00 = inf -1.797693e+308 * 2.000000e+00 = -inf exp(65536.000000) = inf log(0.000000) = -inf (inf == inf) = 1 (inf != inf) = 0 (inf < inf) = 0 (inf <= inf) = 1 (inf > inf) = 0 (inf >= inf) = 1 (inf == -inf) = 0 (inf != -inf) = 1 (inf < -inf) = 0 (inf <= -inf) = 0 (inf > -inf) = 1 (inf >= -inf) = 1 |
isinf関数の自作関数
isinf関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> #include <math.h> #include <float.h> #define DBL_SIGN_MASK 0x8000000000000000ULL #define DBL_EXPONENT_MASK 0x7ff0000000000000ULL #define DBL_FRACTION_MASK 0x000fffffffffffffULL #define FLT_SIGN_MASK 0x80000000ULL #define FLT_EXPONENT_MASK 0x7f800000ULL #define FLT_FRACTION_MASK 0x007fffffULL #define LDBL_SIGN_MASK 0x8000ULL #define LDBL_EXPONENT_MASK 0x7fffULL #define LDBL_FRACTION_MASK 0xffffffffffff0000ULL int myisinf(double x) { union { double d; long l; } y = {x}; if ((y.l & DBL_EXPONENT_MASK) == DBL_EXPONENT_MASK && (y.l & DBL_FRACTION_MASK) == 0) { if ((y.l & DBL_SIGN_MASK) == DBL_SIGN_MASK) { return -1; } else { return 1; } } return 0; } int myisinff(float x) { union { float f; int i; } y = {x}; if ((y.i & FLT_EXPONENT_MASK) == FLT_EXPONENT_MASK && (y.i & FLT_FRACTION_MASK) == 0) { if ((y.i & FLT_SIGN_MASK) == FLT_SIGN_MASK) { return -1; } else { return 1; } } return 0; } int myisinfl(long double x) { union { long double ld; long l[2]; } y = {x}; if ((y.l[1] & LDBL_EXPONENT_MASK) == LDBL_EXPONENT_MASK && (y.l[0] == 0x8000000000000000ULL)) { if ((y.l[1] & LDBL_SIGN_MASK) == LDBL_SIGN_MASK) { return -1; } else { return 1; } } return 0; } int main(void) { long double ld; double d; float f; d = f = ld = 1.0 / 0.0; printf(" myisinf(%lf) = %d\n", d, myisinf(d)); printf("myisinff(%f) = %d\n", f, myisinff(f)); printf("myisinfl(%Lf) = %d\n", ld, myisinfl(ld)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc myinf.c $ a.out myisinf(inf) = 1 myisinff(inf) = 1 myisinfl(inf) = 1 |
まとめ
C言語の非数(nan:Not a Number)と無限大(inf:∞)を紹介しました.
具体的には,非数や無限大になる演算と,非数や無限大同士の比較をしました.
非数と無限大が発生する条件はデバッグに有用ですので覚えておきましょう!
本記事で学んだisnan/isinf関数は以下になります.
関数 | 説明 | 返り値 |
---|---|---|
isnan関数 | 非数かどうか判定 | 非数なら0以外の値(例えば1),それ以外は0 |
isinf関数 | 無限大かどうか判定 | 正の無限大なら1,負の無限大なら-1,それ以外は0 |
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!