C++における浮動小数点例外の徹底解説:発生原因と効果的な対処法
浮動小数点例外(Floating-Point Exception)は、ソフトウェアが数値に対して不適切な操作を実行しようとした際に発生するエラーです。具体的には、ゼロによる除算、負の数の平方根の計算、double型の表現範囲を超える演算など、無効な操作を試みたときに引き起こされます。
C++では、SIGFPEと呼ばれるシグナルハンドラが浮動小数点例外(FPE)を処理します。ユーザーが上記のような無効な操作を実行しようとすると、このシグナルハンドラが呼び出され、標準出力にエラーメッセージを出力した後、プログラムを停止させます。
浮動小数点例外が発生する理由とは?
浮動小数点例外は、プログラミング上のミスや、プログラムが仕様範囲外の値を処理しようとしたときに発生します。例えば、整数をゼロで割ろうとした場合や、負の数の平方根を求めようとした場合などが該当します。また、プロセッサの誤検知によって発生するケースもあります。
不適切な演算、オーバーフロー、アンダーフロー、ゼロ除算、精度の問題など、さまざまな要因によって浮動小数点例外が引き起こされる可能性があります。以下では、これらの要因を一つずつ詳しく見ていきましょう。
1. 不正な演算(Invalid Operation)
数学的に定義されていない操作を実行しようとすると、不正な演算により例外が発生します。代表的な例としては、負の数の平方根や対数の計算などが挙げられます。数学的には複素数の範囲で負の数の平方根を定義できますが、通常のコンピュータ上の仕組みではこれを直接表現できません。
また、整数専用のデータ領域に対して浮動小数点演算を実行しようとした場合にも、不正な演算エラーが発生します。これは、データに対して実行しようとしている操作(浮動小数点演算)と、実際に格納されているデータ(整数)との間に不一致があるために起こります。
2. ゼロ除算(Divide by Zero)
整数をゼロで割ろうとすると、浮動小数点例外がスローされます。NaN(非数)や無限大で割ろうとした場合も同様です。典型的な例としては、1/0 や log(0) などがあります。
3. オーバーフロー(Overflow)
演算結果がデータ型の表現可能な範囲を超えた場合に、オーバーフロー例外が発生します。つまり、結果の値が最大値を上回るか、最小値を下回った場合に起こる現象です。
4. アンダーフロー(Underflow)
アンダーフローは、計算結果がデータ型で表現できる最小値よりも小さくなってしまった場合に発生します。
5. 不正確(Inexact)
演算結果が期待値と異なる場合に、不正確(Inexact)例外が発生します。これは、演算を無限の精度と指数範囲で実行できない場合に起こるものです。
こうした状況の中には、適切に処理できるケースもあります。例えば、プログラムが数値をゼロで割ろうとした場合には、クラッシュを許すのではなく、エラーメッセージを返して安全に終了させるのが一般的に望ましい対応です。
#include <iostream>
#include <stdexcept>
using namespace std;
float Div(float num, float den)
{
if (den == 0) {
throw runtime_error("Math error: Attempted to divide by 0\n");
}
return (num / den);
}
int main()
{
float num, denom, result;
num = 10;
denom = 0;
try {
result = Div(num, denom);
cout << "The quotient is " << result << endl;
}
catch (runtime_error& e) {
cout << "Exception occurred" << endl << e.what();
}
}
このコードでは、main関数内のtryブロックからDiv関数を呼び出しています。引数denomがゼロでなければ、Div関数は商を返します。ゼロである場合は、runtime_error例外がスローされます。catchブロックはこの例外を受け取って「Exception occurred」を出力し、続いてruntime_errorオブジェクトeに対してwhat()関数を呼び出します。what()は、stdexceptヘッダファイルで定義されている標準例外クラスの仮想関数であり、例外の内容を識別するためのメッセージを取得できます。その結果、「Math error: Attempted to divide by 0」というメッセージが表示されます。
実行結果:

C++で浮動小数点例外を防ぐためには、関数に渡すすべてのパラメータを事前にチェックし、適切なデータ形式を使用し、除数がゼロでないことを明示的に確認することが重要です。さらに、double型を使用する場合に、プログラムがより大きな演算結果を必要とするのであれば、long doubleなど表現範囲の広いデータ型へ拡張することも有効です。
まとめ
C++における浮動小数点例外は、数値に対する無効な操作によって引き起こされ、プログラムの正常な実行を妨げる要因となります。こうしたエラーを回避するためには、関数に渡すパラメータの検証と、目的に合った適切なデータ型の選択が不可欠です。さらに、例外処理機構を活用して浮動小数点例外を捕捉しておくことで、プログラムの突然のクラッシュを防ぎ、より堅牢で信頼性の高いアプリケーションを構築できます。
-
C++でBSTをグレーターツリーに変換する方法
二分探索木(BST)が与えられたとき、それを「グレーターツリー(Greater Tree)」へ変換する問題を考えます。グレーターツリーとは、元のBSTの各キーを「元のキー + BST内にあるそのキーより大きいすべてのキーの合計」に書き換えた木のことです。 たとえば、次のような入力が与えられたとします。 このとき、期待される出力は次のとおりです。 解法のポイント:逆インオーダー走査 BSTを通常のインオーダー(左 → 根 → 右)で走査すると、キーは昇順に訪問されます。これに対して右 → 根 → 左の順で走査する「逆インオーダー走査」を行うと、キーは降順に訪問されます。この性質を利用し、訪
-
C++とOpenCVを使って長方形を描画する方法
OpenCVで長方形を描くには、4つの点(座標)が必要です。以下の図をご覧ください。この図には、x1、x2、y1、y2の4つの点があり、これらが長方形を構成する4つの座標を定義しています。OpenCVで長方形を描画するには、まずこれらの点を定義し、長方形を表示するためのマトリックス(行列)を用意する必要があります。さらに、線の色や線の太さといった関連する値も宣言しておきましょう。基本構文rectangle関数の基本的な構文は以下の通りです。rectangle(whiteMatrix, starting, ending, line_Color, thickness);サンプルコード次のプログラム