C LANGUAGE TECHNOLOGY

【C言語】絶対値を標準ライブラリ関数と自作関数・マクロで計算

悩んでいる人

C言語で絶対値を計算する方法を教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOSの授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2021年の世界大学学術ランキングで20位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発
  • プログラミング歴15年以上,習得している言語: C/C++Solidity,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開

こういった私から学べます.

絶対値

絶対値とは,0からの距離を表す値です.

例えば,3の絶対値は3ですが,-3の絶対値も3になります.

C言語で絶対値を計算する方法は大きく分けて以下の2つの方法がありますので,コードを含めて紹介していきます.

  • 絶対値をC言語の標準ライブラリ関数で計算
  • 絶対値をC言語の自作関数・マクロで計算

絶対値をC言語の標準ライブラリ関数で計算

絶対値をC言語の標準ライブラリ関数で計算する方法を紹介します.

  • 整数と浮動小数点数
  • 複素数

整数と浮動小数点数の絶対値を計算

整数の絶対値の計算は,stdlib.hでプロトタイプ宣言されているabs/labs/llabs関数を利用します.

また,intmax_t型の絶対値を計算するためには,stdint.hでプロトタイプ宣言されているimaxabs関数を利用します.

浮動小数点の絶対値の計算は,math.hでプロトタイプ宣言されているfabs/fabsf/fabsl関数を利用します.

GCCコンパイラでは,fabs/fabsf/fabsl関数はビルトイン関数のため,-lmオプションは不要です.

上記の関数を利用したコードは以下になります.

実行結果は以下になります.

複素数の絶対値を計算

複素数の絶対値の計算は,complex.hでプロトタイプ宣言されているcabs/cabsf/cabsl関数を利用します.

また,複素数の実部を取得するためにはcreal/crealf/creall関数,虚部を取得するためにはcimag/cimagf/cimagl関数を利用します.

ここで,fabs/fabsf/fabsl関数とは異なり,これらの関数を利用するためには-lmオプションが必要なことに注意して下さい.

実行結果は以下になります.

絶対値をC言語の自作関数・マクロで計算

abs関数等の標準ライブラリ関数を使わないで,絶対値をC言語の自作関数・マクロで計算する方法を紹介します.

  • if文で自作
  • 3項演算子(条件演算子)で自作
  • マクロで自作
  • C11規格の総称選択(Generic Selection)で自作
  • 複素数の絶対値の計算をニュートン法で自作

実行結果は同じなので省略します.

if文で自作

一番思いつきやすいのが,絶対値の計算をif文で自作する方法でしょう.

if文で自作するコードは以下になります.

3項演算子(条件演算子)で自作

if文は長いので3項演算子でシンプルに書くことができます.

3項演算子で自作するコードは以下になります.

if文のコードは110行ですが,3項演算子のコードは83行と短くなったことがわかります.

マクロで自作

if文や3項演算子は,それぞれの型毎に関数を定義する必要があり,コードが長くなってしまいます.

そこで,マクロを利用することで,異なる型の絶対値をたった1行で計算することができます.

マクロで自作したコードは以下になります.

9行目のMYABSマクロで絶対値を3項演算子で計算しています.

C11規格の総称選択(Generic Selection)で自作

C言語ではC11規格の総称選択(Generic Selection)で,型に応じて分岐する式を書くことができます.

総称選択で自作したコードは以下になります.

10~17行目のMYABSマクロでは,型を一つずつ指定して,適切な関数を呼び出します.

各々の関数では,3項演算子で絶対値を計算しています.

上記のマクロで自作するコードより長くなりますが,型をチェックできる利点があります.

※私の実行環境ではlongとintmax_tは同じ型になってしまうので除外しました.

複素数の絶対値の計算をニュートン法で自作

複素数\(z = a + bi \)(a,bは実数)の絶対値は下式になります.

$$ |z| := \sqrt{a^2 + b^2} $$

なので,複素数の絶対値を計算するためには,平方根を求める必要があります.

平方根を求めるためには,math.hのsqrt関数を利用すれば可能ですが,ニュートン法で自作します.

ニュートン法とは,方程式の解を近似的に求めることができる方法です.

複素数の絶対値の計算をニュートン法で自作したコードは以下になります.

絶対値を計算する時の注意点

絶対値を計算する時の以下の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と最大値の絶対値も計算しています.

実行結果は以下になります.

整数の最小値の絶対値が負の値になり,正しく計算できていないことがわかります.

また,私の環境ではlong型とlong long型の最小値と最大値は同じになります.

浮動小数点の最小値の絶対値を計算する時

浮動小数点数の最小値の絶対値を計算する時は,float.hに定義されているマクロの利用に注意しましょう.

例えば,double型の最小値の絶対値を計算する時は,DBL_MINではなく,-DBL_MAXを利用します.

ここで,DBL_MINはdouble型で表現できる最小値という意味で,数値の最小値ではないことに注意して下さい.

浮動小数点数はIEEE 754の規格で定義されていますので,興味があれば読みましょう!

浮動小数点の最小値の絶対値を計算するコードは以下になります.

実行結果は以下になります.

-DBL_MAXでdouble型の最小値の絶対値を正しく計算できていることがわかります.

複素数の絶対値を計算する時

複素数の絶対値を計算する時は,算術オーバーフロー(オーバーフロー)に注意しましょう.

複素数の絶対値を計算するコードは,以下になります.

実行結果は以下になります.

z4とz5の絶対値の計算で算術オーバーフローが発生して,結果がinf(∞)になっていることがわかります.

まとめ

C言語で絶対値を標準ライブラリ関数と自作関数・マクロで計算する方法を紹介しました.

また,絶対値を計算する時の注意点を解説しました.

絶対値の計算方法をいくつか紹介しましたので,適切な方法を選びましょう.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

友だち追加

独学が難しいあなたは,C言語を学べるおすすめのオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , , , , , ,