C言語で絶対値を計算する方法を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴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社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
絶対値
絶対値とは,0からの距離を表す値です.
例えば,3の絶対値は3ですが,-3の絶対値も3になります.
C言語で絶対値を計算する方法は大きく分けて以下の2つの方法がありますので,コードを含めて紹介していきます.
- 絶対値をC言語の標準ライブラリ関数で計算
- 絶対値をC言語の自作関数・マクロで計算
絶対値をC言語の標準ライブラリ関数で計算
絶対値をC言語の標準ライブラリ関数で計算する方法を紹介します.
- 整数と浮動小数点数(データ型)
- 複素数
C言語で整数と浮動小数点数(データ型)や複素数を知りたいあなたはこちらからどうぞ.
整数と浮動小数点数の絶対値を計算
整数の絶対値の計算は,stdlib.hでプロトタイプ宣言されているabs/labs/llabs関数を利用します.
1 2 3 |
int abs(int j); long labs(long j); long long llabs(long long j); |
また,intmax_t型の絶対値を計算するためには,stdint.hでプロトタイプ宣言されているimaxabs関数を利用します.
1 |
intmax_t imaxabs(intmax_t j); |
浮動小数点の絶対値の計算は,math.hでプロトタイプ宣言されているfabs/fabsf/fabsl関数を利用します.
GCCコンパイラでは,fabs/fabsf/fabsl関数はビルトイン関数のため,-lmオプションは不要です.
1 2 3 |
double fabs(double x); float fabsf(float x); long double fabsl(long double x); |
上記の関数を利用したコードは以下になります.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <math.h> #include <inttypes.h> int main(void) { int x = 3; int y = -4; long lx = 123; long ly = -456; long long llx = 123456789; long long lly = -987654321; intmax_t imx = INTMAX_C(12345); intmax_t imy = INTMAX_C(-56789); double dx = 3.14; double dy = -13.14; float fx = 6.28; float fy = -12.34; long double ldx = 34.56; long double ldy = -56.78; printf("|%d| = %d\n", x, abs(x)); printf("|%d| = %d\n", y, abs(y)); printf("|%ld| = %ld\n", lx, labs(lx)); printf("|%ld| = %ld\n", ly, labs(ly)); printf("|%lld| = %lld\n", llx, llabs(llx)); printf("|%lld| = %lld\n", lly, llabs(lly)); printf("|%ld| = %ld\n", imx, imaxabs(imx)); printf("|%ld| = %ld\n", imy, imaxabs(imy)); printf("|%lf| = %lf\n", dx, fabs(dx)); printf("|%lf| = %lf\n", dy, fabs(dy)); printf("|%f| = %f\n", fx, fabsf(fx)); printf("|%f| = %f\n", fy, fabsf(fy)); printf("|%Lf| = %Lf\n", ldx, fabsl(ldx)); printf("|%Lf| = %Lf\n", ldy, fabsl(ldy)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ gcc abs.c $ a.out |3| = 3 |-4| = 4 |123| = 123 |-456| = 456 |123456789| = 123456789 |-987654321| = 987654321 |12345| = 12345 |-56789| = 56789 |3.140000| = 3.140000 |-13.140000| = 13.140000 |6.280000| = 6.280000 |-12.340000| = 12.340000 |34.560000| = 34.560000 |-56.780000| = 56.780000 |
複素数の絶対値を計算
複素数の絶対値の計算は,complex.hでプロトタイプ宣言されているcabs/cabsf/cabsl関数を利用します.
また,複素数の実部を取得するためにはcreal/crealf/creall関数,虚部を取得するためにはcimag/cimagf/cimagl関数を利用します.
ここで,fabs/fabsf/fabsl関数とは異なり,これらの関数を利用するためには-lmオプションが必要なことに注意して下さい.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <complex.h> int main(void) { double complex z = 1.2 + 3.4I; float complex zf = 1.2 + 3.4I; long double complex zl = 1.2 + 3.4I; printf("cabs(%lf%+lfI) = %lf\n", creal(z), cimag(z), cabs(z)); printf("cabsf(%f%+fI) = %f\n", crealf(zf), cimagf(zf), cabsf(zf)); printf("cabsl(%Lf%+LfI) = %Lf\n", creall(zl), cimagl(zl), cabsl(zl)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc cabs.c -lm $ a.out cabs(1.200000+3.400000I) = 3.605551 cabsf(1.200000+3.400000I) = 3.605551 cabsl(1.200000+3.400000I) = 3.605551 |
絶対値をC言語の自作関数・マクロで計算
abs関数等の標準ライブラリ関数を使わないで,絶対値をC言語の自作関数・マクロで計算する方法を紹介します.
- if文で自作
- 3項演算子(条件演算子)で自作
- マクロで自作
- C11規格の総称選択(Generic Selection)で自作
- 複素数の絶対値の計算をニュートン法で自作
実行結果は同じなので省略します.
if文で自作
一番思いつきやすいのが,絶対値の計算をif文で自作する方法でしょう.
if文で自作するコードは以下になります.
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> #define MYINTMAX_C(v) (v ## LL) static inline int myabs(int j) { if (j < 0) { return -j; } return j; } static inline long mylabs(long j) { if (j < 0) { return -j; } return j; } static inline long long myllabs(long long j) { if (j < 0) { return -j; } return j; } static inline intmax_t myimaxabs(intmax_t j) { if (j < 0) { return -j; } return j; } static inline double myfabs(double x) { if (x < 0) { return -x; } return x; } static inline float myfabsf(float x) { if (x < 0) { return -x; } return x; } static inline long double myfabsl(long double x) { if (x < 0) { return -x; } return x; } int main(void) { int x = 3; int y = -4; long lx = 123; long ly = -456; long long llx = 123456789; long long lly = -987654321; intmax_t imx = MYINTMAX_C(12345); intmax_t imy = MYINTMAX_C(-56789); double dx = 3.14; double dy = -13.14; float fx = 6.28; float fy = -12.34; long double ldx = 34.56; long double ldy = -56.78; printf("|%d| = %d\n", x, myabs(x)); printf("|%d| = %d\n", y, myabs(y)); printf("|%ld| = %ld\n", lx, mylabs(lx)); printf("|%ld| = %ld\n", ly, mylabs(ly)); printf("|%lld| = %lld\n", llx, myllabs(llx)); printf("|%lld| = %lld\n", lly, myllabs(lly)); printf("|%ld| = %ld\n", imx, myimaxabs(imx)); printf("|%ld| = %ld\n", imy, myimaxabs(imy)); printf("|%lf| = %lf\n", dx, myfabs(dx)); printf("|%lf| = %lf\n", dy, myfabs(dy)); printf("|%f| = %f\n", fx, myfabsf(fx)); printf("|%f| = %f\n", fy, myfabsf(fy)); printf("|%Lf| = %Lf\n", ldx, myfabsl(ldx)); printf("|%Lf| = %Lf\n", ldy, myfabsl(ldy)); return 0; } |
3項演算子(条件演算子)で自作
if文は長いので3項演算子でシンプルに書くことができます.
3項演算子で自作するコードは以下になります.
if文のコードは110行ですが,3項演算子のコードは83行と短くなったことがわかります.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> #include <math.h> #define MYINTMAX_C(v) (v ## LL) static inline int myabs(int j) { return j < 0 ? -j : j; } static inline long mylabs(long j) { return j < 0 ? -j : j; } static inline long long myllabs(long long j) { return j < 0 ? -j : j; } static inline intmax_t myimaxabs(intmax_t j) { return j < 0 ? -j : j; } static inline double myfabs(double x) { return x < 0 ? -x : x; } static inline float myfabsf(float x) { return x < 0 ? -x : x; } static inline long double myfabsl(long double x) { return x < 0 ? -x : x; } int main(void) { int x = 3; int y = -4; long lx = 123; long ly = -456; long long llx = 123456789; long long lly = -987654321; intmax_t imx = MYINTMAX_C(12345); intmax_t imy = MYINTMAX_C(-56789); double dx = 3.14; double dy = -13.14; float fx = 6.28; float fy = -12.34; long double ldx = 34.56; long double ldy = -56.78; printf("|%d| = %d\n", x, myabs(x)); printf("|%d| = %d\n", y, myabs(y)); printf("|%ld| = %ld\n", lx, mylabs(lx)); printf("|%ld| = %ld\n", ly, mylabs(ly)); printf("|%lld| = %lld\n", llx, myllabs(llx)); printf("|%lld| = %lld\n", lly, myllabs(lly)); printf("|%ld| = %ld\n", imx, myimaxabs(imx)); printf("|%ld| = %ld\n", imy, myimaxabs(imy)); printf("|%lf| = %lf\n", dx, myfabs(dx)); printf("|%lf| = %lf\n", dy, myfabs(dy)); printf("|%f| = %f\n", fx, myfabsf(fx)); printf("|%f| = %f\n", fy, myfabsf(fy)); printf("|%Lf| = %Lf\n", ldx, myfabsl(ldx)); printf("|%Lf| = %Lf\n", ldy, myfabsl(ldy)); return 0; } |
マクロで自作
if文や3項演算子は,それぞれの型毎に関数を定義する必要があり,コードが長くなってしまいます.
そこで,マクロを利用することで,異なる型の絶対値をたった1行で計算することができます.
マクロで自作したコードは以下になります.
9行目のMYABSマクロで絶対値を3項演算子で計算しています.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> #include <math.h> #define MYABS(v) ((v) < 0 ? -(v) : (v)) #define MYINTMAX_C(v) (v ## LL) int main(void) { int x = 3; int y = -4; long lx = 123; long ly = -456; long long llx = 123456789; long long lly = -987654321; intmax_t imx = MYINTMAX_C(12345); intmax_t imy = MYINTMAX_C(-56789); double dx = 3.14; double dy = -13.14; float fx = 6.28; float fy = -12.34; long double ldx = 34.56; long double ldy = -56.78; printf("|%d| = %d\n", x, MYABS(x)); printf("|%d| = %d\n", y, MYABS(y)); printf("|%ld| = %ld\n", lx, MYABS(lx)); printf("|%ld| = %ld\n", ly, MYABS(ly)); printf("|%lld| = %lld\n", llx, MYABS(llx)); printf("|%lld| = %lld\n", lly, MYABS(lly)); printf("|%ld| = %ld\n", imx, MYABS(imx)); printf("|%ld| = %ld\n", imy, MYABS(imy)); printf("|%lf| = %lf\n", dx, MYABS(dx)); printf("|%lf| = %lf\n", dy, MYABS(dy)); printf("|%f| = %f\n", fx, MYABS(fx)); printf("|%f| = %f\n", fy, MYABS(fy)); printf("|%Lf| = %Lf\n", ldx, MYABS(ldx)); printf("|%Lf| = %Lf\n", ldy, MYABS(ldy)); return 0; } |
C11規格の総称選択(Generic Selection)で自作
C言語ではC11規格の総称選択(Generic Selection)で,型に応じて分岐する式を書くことができます.
総称選択で自作したコードは以下になります.
10~17行目のMYABSマクロでは,型を一つずつ指定して,適切な関数を呼び出します.
各々の関数では,3項演算子で絶対値を計算しています.
上記のマクロで自作するコードより長くなりますが,型をチェックできる利点があります.
※私の実行環境ではlongとintmax_tは同じ型になってしまうので除外しました.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <stdint.h> #define MYABS(v) _Generic((v), \ long: mylabs, \ long long: myllabs, \ double: myfabs, \ float: myfabsf, \ long double: myfabsl, \ default: myabs /* int */ \ ) (v) #define MYINTMAX_C(v) (v ## LL) static inline int myabs(int j) { return j < 0 ? -j : j; } static inline long mylabs(long j) { return j < 0 ? -j : j; } static inline long long myllabs(long long j) { return j < 0 ? -j : j; } static inline double myfabs(double x) { return x < 0 ? -x : x; } static inline float myfabsf(float x) { return x < 0 ? -x : x; } static inline long double myfabsl(long double x) { return x < 0 ? -x : x; } int main(void) { int x = 3; int y = -4; long lx = 123; long ly = -456; long long llx = 123456789; long long lly = -987654321; intmax_t imx = MYINTMAX_C(12345); intmax_t imy = MYINTMAX_C(-56789); double dx = 3.14; double dy = -13.14; float fx = 6.28; float fy = -12.34; long double ldx = 34.56; long double ldy = -56.78; printf("|%d| = %d\n", x, MYABS(x)); printf("|%d| = %d\n", y, MYABS(y)); printf("|%ld| = %ld\n", lx, MYABS(lx)); printf("|%ld| = %ld\n", ly, MYABS(ly)); printf("|%lld| = %lld\n", llx, MYABS(llx)); printf("|%lld| = %lld\n", lly, MYABS(lly)); printf("|%ld| = %ld\n", imx, MYABS(imx)); printf("|%ld| = %ld\n", imy, MYABS(imy)); printf("|%lf| = %lf\n", dx, MYABS(dx)); printf("|%lf| = %lf\n", dy, MYABS(dy)); printf("|%f| = %f\n", fx, MYABS(fx)); printf("|%f| = %f\n", fy, MYABS(fy)); printf("|%Lf| = %Lf\n", ldx, MYABS(ldx)); printf("|%Lf| = %Lf\n", ldy, MYABS(ldy)); return 0; } |
複素数の絶対値の計算の自作関数
複素数\(z = a + bi \)(a,bは実数)の絶対値は下式になります.
$$ |z| := \sqrt{a^2 + b^2} $$
なので,複素数の絶対値を計算するためには,平方根を計算するsqrt/sqrtf/sqrtl関数を利用する必要があります.
sqrt/sqrtf/sqrtl関数を知りたいあなたはこちらからどうぞ.
複素数の絶対値の計算の自作関数は以下になります.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <complex.h> double mycabs(double complex z) { return sqrt(creal(z) * creal(z) + cimag(z) * cimag(z)); } float mycabsf(float complex z) { return sqrtf(creal(z) * creal(z) + cimag(z) * cimag(z)); } long double mycabsl(long double complex z) { return sqrtl(creal(z) * creal(z) + cimag(z) * cimag(z)); } int main(void) { double complex z = 1.2 + 3.4I; float complex zf = 1.2 + 3.4I; long double complex zl = 1.2 + 3.4I; printf(" mycabs(%lf%+lfI) = %lf\n", creal(z), cimag(z), mycabs(z)); printf("mycabsf(%f%+fI) = %f\n", crealf(zf), cimagf(zf), mycabsf(zf)); printf("mycabsl(%Lf%+LfI) = %Lf\n", creall(zl), cimagl(zl), mycabsl(zl)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc mycabs.c -lm $ a.out mycabs(1.200000+3.400000I) = 3.605551 mycabsf(1.200000+3.400000I) = 3.605551 mycabsl(1.200000+3.400000I) = 3.605551 |
絶対値を計算する時の注意点
絶対値を計算する時の以下の3つの注意点を解説していきます.
- 整数の最小値の絶対値を計算する時
- 浮動小数点の最小値の絶対値を計算する時
- 複素数の絶対値を計算する時
整数の最小値の絶対値を計算する時
整数の最小値の絶対値を計算する時は,未定義の動作になります.(2の補数で表現する場合)
例えば,32ビットのint型の最小値INT_MINと最大値INT_MAXは以下になります(limits.hで定義).
- INT_MIN:-2147483648
- INT_MAX:2147483647
INT_MINの値-2147483648の絶対値は2147483648になりますが,INT_MAXの2147483647より大きいのでint型で表現できません.
※64ビットのlong型なら2147483648を表現可能ですが,long型の最小値LONG_MINの絶対値(-9223372036854775808L)も同様に最大値LONG_MAX(9223372036854775807L)より大きいのでlong型で表現できません.
整数の最小値の絶対値を計算するコードは以下になります.
比較のため,整数の最小値だけでなく,最小値+1と最大値の絶対値も計算しています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <limits.h> int main(void) { printf("INT_MIN: |%d| = %d\n", INT_MIN, abs(INT_MIN)); printf("INT_MIN + 1: |%d| = %d\n", INT_MIN + 1, abs(INT_MIN + 1)); printf("INT_MAX: |%d| = %d\n", INT_MAX, abs(INT_MAX)); printf("LONG_MIN: |%ld| = %ld\n", LONG_MIN, labs(LONG_MIN)); printf("LONG_MIN + 1: |%ld| = %ld\n", LONG_MIN + 1, labs(LONG_MIN + 1)); printf("LONG_MAX: |%ld| = %ld\n", LONG_MAX, labs(LONG_MAX)); printf("LLONG_MIN: |%lld| = %lld\n", LLONG_MIN, llabs(LLONG_MIN)); printf("LLONG_MIN + 1: |%lld| = %lld\n", LLONG_MIN + 1, llabs(LLONG_MIN + 1)); printf("LLONG_MAX: |%lld| = %lld\n", LLONG_MAX, llabs(LLONG_MAX)); return 0; } |
実行結果は以下になります.
整数の最小値の絶対値が負の値になり,正しく計算できていないことがわかります.
また,私の環境ではlong型とlong long型の最小値と最大値は同じになります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc min_max_abs.c $ a.out INT_MIN: |-2147483648| = -2147483648 INT_MIN + 1: |-2147483647| = 2147483647 INT_MAX: |2147483647| = 2147483647 LONG_MIN: |-9223372036854775808| = -9223372036854775808 LONG_MIN + 1: |-9223372036854775807| = 9223372036854775807 LONG_MAX: |9223372036854775807| = 9223372036854775807 LLONG_MIN: |-9223372036854775808| = -9223372036854775808 LLONG_MIN + 1: |-9223372036854775807| = 9223372036854775807 LLONG_MAX: |9223372036854775807| = 9223372036854775807 |
浮動小数点の最小値の絶対値を計算する時
浮動小数点数の最小値の絶対値を計算する時は,float.hに定義されているマクロの利用に注意しましょう.
例えば,double型の最小値の絶対値を計算する時は,DBL_MINではなく,-DBL_MAXを利用します.
ここで,DBL_MINはdouble型で表現できる最小値という意味で,数値の最小値ではないことに注意して下さい.
浮動小数点数はIEEE 754の規格で定義されていますので,興味があれば読みましょう!
浮動小数点の最小値の絶対値を計算するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> #include <float.h> int main(void) { printf("-DBL_MAX: |%le| = %le\n", -DBL_MAX, fabs(-DBL_MAX)); printf("DBL_MAX: |%le| = %le\n", DBL_MAX, fabs(DBL_MAX)); printf("DBL_MIN: %le\n", DBL_MIN); printf("-FLT_MAX: |%e| = %e\n", -FLT_MAX, fabsf(-FLT_MAX)); printf("FLT_MAX: |%e| = %e\n", FLT_MAX, fabsf(FLT_MAX)); printf("FLT_MIN: %e\n", FLT_MIN); printf("-LDBL_MAX: |%Le| = %Le\n", -LDBL_MAX, fabsl(-LDBL_MAX)); printf("LDBL_MAX: |%Le| = %Le\n", LDBL_MAX, fabsl(LDBL_MAX)); printf("LDBL_MIN: %Le\n", LDBL_MIN); return 0; } |
実行結果は以下になります.
-DBL_MAXでdouble型の最小値の絶対値を正しく計算できていることがわかります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc min_max_fabs.c $ a.out -DBL_MAX: |-1.797693e+308| = 1.797693e+308 DBL_MAX: |1.797693e+308| = 1.797693e+308 DBL_MIN: 2.225074e-308 -FLT_MAX: |-3.402823e+38| = 3.402823e+38 FLT_MAX: |3.402823e+38| = 3.402823e+38 FLT_MIN: 1.175494e-38 -LDBL_MAX: |-1.189731e+4932| = 1.189731e+4932 LDBL_MAX: |1.189731e+4932| = 1.189731e+4932 LDBL_MIN: 3.362103e-4932 |
複素数の絶対値を計算する時
複素数の絶対値を計算する時は,算術オーバーフロー(オーバーフロー)に注意しましょう.
複素数の絶対値を計算するコードは,以下になります.
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 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> #include <complex.h> #include <float.h> int main(void) { double complex z1 = DBL_MAX; double complex z2 = DBL_MAX * I; double complex z3 = DBL_MAX / sqrt(2.0) + DBL_MAX / sqrt(2.0) * I; double complex z4 = DBL_MAX / sqrt(1.9) + DBL_MAX / sqrt(1.9) * I; double complex z5 = DBL_MAX + DBL_MAX * I; printf("z1: %e%+eI = %e\n", creal(z1), cimag(z1), cabs(z1)); printf("z2: %e%+eI = %e\n", creal(z2), cimag(z2), cabs(z2)); printf("z3: %e%+eI = %e\n", creal(z3), cimag(z3), cabs(z3)); printf("z4: %e%+eI = %e\n", creal(z4), cimag(z4), cabs(z4)); printf("z5: %e%+eI = %e\n", creal(z5), cimag(z5), cabs(z5)); return 0; } |
実行結果は以下になります.
z4とz5の絶対値の計算で算術オーバーフローが発生して,結果がinf(∞)になっていることがわかります.
1 2 3 4 5 6 7 |
$ gcc overflow_complex.c -lm $ a.out z1: 1.797693e+308+0.000000e+00I = 1.797693e+308 z2: 0.000000e+00+1.797693e+308I = 1.797693e+308 z3: 1.271161e+308+1.271161e+308I = 1.797693e+308 z4: 1.304184e+308+1.304184e+308I = inf z5: 1.797693e+308+1.797693e+308I = inf |
オーバーフローと回避方法を知りたいあなたはこちらの記事を読みましょう!
まとめ
C言語で絶対値を標準ライブラリ関数と自作関数・マクロで計算する方法を紹介しました.
また,絶対値を計算する時の注意点を解説しました.
絶対値の計算方法をいくつか紹介しましたので,適切な方法を選びましょう.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!