【C言語】fenv.hで浮動小数点の調整【標準ライブラリ】
C言語のfenv.hを使って出来ることと典型的な使い方
fenv.hとは
fenv.h
はC言語の標準ライブラリの一つで、浮動小数点演算に関する制御と例外処理を行うためのヘッダーファイルです。
このライブラリを使うことで、浮動小数点例外(ゼロ除算、オーバーフローなど)の検出や、丸めモードの変更が可能になります。
浮動小数点例外の検出と処理
C言語では、浮動小数点演算中にエラー(例外)が発生しても、通常はプログラムが自動的に停止しません。
しかし、fenv.h
を使うことで、特定の例外を検出し、適切に処理することができます。
使用可能な浮動小数点例外
FE_DIVBYZERO
: ゼロによる除算FE_INEXACT
: 精度の損失(丸め誤差)FE_INVALID
: 無効な演算(例えば 0/0 や sqrt(-1))FE_OVERFLOW
: オーバーフローFE_UNDERFLOW
: アンダーフロー
例: 例外を検出する
#include <stdio.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON // fenv.h の機能を有効化
int main() {
feclearexcept(FE_ALL_EXCEPT); // 例外フラグをクリア
double x = 1.0 / 0.0; // ゼロ除算を実行
if (fetestexcept(FE_DIVBYZERO)) {
printf("ゼロによる除算が発生しました\n");
}
return 0;
}
丸めモードの設定と変更
浮動小数点数の計算結果は、通常最も近い値に丸められますが、fenv.h
を使うと丸めモードを変更できます。
使用可能な丸めモード
FE_TONEAREST
: 最近接丸め(デフォルト)FE_DOWNWARD
: 負の無限大方向に丸めFE_UPWARD
: 正の無限大方向に丸めFE_TOWARDZERO
: ゼロ方向に丸め
例: 丸めモードを変更する
#include <stdio.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main() {
fesetround(FE_DOWNWARD); // 負の無限大方向に丸め
printf("現在の丸めモード: FE_DOWNWARD\n");
return 0;
}
浮動小数点例外フラグの操作
浮動小数点演算の結果として発生する例外フラグを明示的に設定・クリアできます。
例: 例外フラグの設定とクリア
#include <stdio.h>
#include <fenv.h>
int main() {
feclearexcept(FE_ALL_EXCEPT); // すべての例外フラグをクリア
feraiseexcept(FE_INVALID); // 無効な演算例外を発生させる
if (fetestexcept(FE_INVALID)) {
printf("無効な演算例外が発生しました\n");
}
return 0;
}
浮動小数点環境の保存と復元
一時的に浮動小数点の環境を変更し、後で元に戻すことも可能です。
例: 環境の保存と復元
#include <stdio.h>
#include <fenv.h>
int main() {
fenv_t env;
fegetenv(&env); // 現在の環境を保存
fesetround(FE_UPWARD);
printf("丸めモードを FE_UPWARD に変更\n");
fesetenv(&env); // 環境を復元
printf("元の環境に戻しました\n");
return 0;
}
実用的な使用例
例1: 浮動小数点演算のエラーをログに記録
#include <stdio.h>
#include <fenv.h>
void check_exceptions() {
if (fetestexcept(FE_DIVBYZERO)) printf("ゼロ除算エラー\n");
if (fetestexcept(FE_OVERFLOW)) printf("オーバーフロー発生\n");
if (fetestexcept(FE_UNDERFLOW)) printf("アンダーフロー発生\n");
feclearexcept(FE_ALL_EXCEPT); // フラグをクリア
}
int main() {
feclearexcept(FE_ALL_EXCEPT);
double x = 1.0 / 0.0; // ゼロ除算
check_exceptions();
return 0;
}
例2: 精度の損失を監視
#include <stdio.h>
#include <fenv.h>
int main() {
feclearexcept(FE_ALL_EXCEPT);
double x = 1.0 / 3.0 + 1e-20; // 精度の損失がある計算
if (fetestexcept(FE_INEXACT)) {
printf("精度の損失が発生しました\n");
}
return 0;
}