サードパーティのライブラリを使用せずに標準的な方法で浮動小数点アンダーフローを検出し、署名付きと未署名の両方の例外を検出する方法について、ヘルプとサンプル コードが必要です。私がグーグルで調べたところ、さまざまな著者が「段階的なアンダーフローがアンダーフローとしてカウントされるかどうか」について話していることがわかりましたか? 段階的なアンダーフローとは誰か説明できますか? 両方のシナリオを確認する必要があります
お時間をいただきありがとうございます。
サードパーティのライブラリを使用せずに標準的な方法で浮動小数点アンダーフローを検出し、署名付きと未署名の両方の例外を検出する方法について、ヘルプとサンプル コードが必要です。私がグーグルで調べたところ、さまざまな著者が「段階的なアンダーフローがアンダーフローとしてカウントされるかどうか」について話していることがわかりましたか? 段階的なアンダーフローとは誰か説明できますか? 両方のシナリオを確認する必要があります
お時間をいただきありがとうございます。
「段階的アンダーフロー」の上位の検索結果を見ても、明確で直接的な答えが表示されないため、次のようになります。
IEEE-754 2 進浮動小数点数には、その範囲のほとんどで規則的なパターンがあります。ビット数が設定された符号、指数、仮数があります (32 ビットの場合は 24、64 ビットのfloat
場合は 53 double
)。ただし、パターンは端で中断する必要があります。上限では、最大の指数に対して大きすぎる結果は無限大に変更されます。ローエンドでは、選択肢があります。
1 つの選択肢として、結果が最低指数よりも小さい場合、結果はゼロに丸められます。ただし、IEEE-754 では、段階的アンダーフローと呼ばれる別のスキームが使用されます。最小の指数は、通常の指数に使用される形式とは異なる形式用に予約されています。
通常の指数では、24 ビットの仮数部は「1」です。その後に仮数フィールドにエンコードされた 23 ビットが続きます。数値が非正規の場合、指数は最小の通常の指数と同じ値になりますが、24 ビットの仮数は「0」です。23 ビットが続きます。これは段階的なアンダーフローです。これは、数値が小さくなるにつれて、0 に到達する前に精度が低下する (仮数部の先行ビットが 0 になる) ためです。
段階的アンダーフローには、いくつかの優れた数学的特性があります。特に、a-b == 0
if and only ifa == b
です。突然のアンダーフローでは、が小さすぎて浮動小数点形式で表現できないため、とが異なっていてa-b == 0
も可能性があります。漸進的なオーバーフローでは、小さい指数と のすべての可能な値が表現可能です。a
b
a-b
a-b
a
b
浮動小数点アンダーフローが発生したかどうかを判断する際のもう 1 つの問題は、丸めの前後のテストに基づいてアンダーフローを報告することが (IEEE-754 標準によって) 実装で許可されていることです。結果を計算するとき、浮動小数点の実装は実質的に次の手順を実行する必要があります。
標準では、実装で次のいずれかを使用してアンダーフローを報告できます。
また:
したがって、浮動小数点の 2 つの異なる実装は、同じ計算のアンダーフローについて異なるレポートを返す場合があります。
(アンダーフローの処理にはいくつかの追加ルールがあります。上記により、アンダーフロー例外が通知されます。ただし、この例外からのトラップが有効になっておらず、結果が正確である場合 (丸めによって何も変更されなかった場合)、「アンダーフロー」は無視されます。 、およびアンダーフロー フラグは発生しません。結果が不正確な場合、アンダーフローが発生し、不正確な例外が通知されます。)
「アンダーフロー」ビットの浮動小数点ステータス ワードをチェックするか、アンダーフロー浮動小数点例外の信号をトラップします。見る:
http://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html
template <typename T>
class Real
{
public:
Real(T x) : x_(x) { }
Real& operator/=(T rhs)
{
if (x_)
{
x_ /= rhs;
if (!x_)
do whatever you want for underflow...
}
}
friend Real operator/(Real lhs, Real rhs)
{ return lhs /= rhs; }
// similar for -= etc.
private:
T x_;
}
まず、ビルドで浮動小数点例外の生成を有効にする必要があります。次に、コードでそれらをキャッチする必要があります。
私はこのようなことをしました(Visual Studioを使用)
void translateFPException( unsigned int u, EXCEPTION_POINTERS* pExp )
{
unsigned int fpuStatus = _clearfp(); // clear the exception
switch (u)
{
case STATUS_FLOAT_DENORMAL_OPERAND:
throw fe_denormal_operand(fpuStatus);
case STATUS_FLOAT_DIVIDE_BY_ZERO:
throw fe_divide_by_zero(fpuStatus);
case STATUS_FLOAT_INEXACT_RESULT:
throw fe_inexact_result(fpuStatus);
case STATUS_FLOAT_INVALID_OPERATION:
throw fe_invalid_operation(fpuStatus);
case STATUS_FLOAT_OVERFLOW:
throw fe_overflow(fpuStatus);
case STATUS_FLOAT_UNDERFLOW:
throw fe_underflow(fpuStatus);
case STATUS_FLOAT_STACK_CHECK:
throw fe_stack_check(fpuStatus);
default:
throw float_exception(fpuStatus);
};
}
void initializeFloatingPointExceptionHandling()
{
unsigned int fpControlWord = 0x00;
_clearfp(); // always call _clearfp before enabling/unmasking a FPU exception
// enabling an exception is done by clearing the respective bit in the control word
errno_t success = _controlfp_s( &fpControlWord,
0xffffffff^( _EM_INVALID
| _EM_ZERODIVIDE
| _EM_OVERFLOW
| _EM_DENORMAL
| _EM_UNDERFLOW
| _EM_INEXACT), _MCW_EM );
if (success != 0)
{
stringstream errStream;
errStream << success << " " << __FILE__ << ":" << __LINE__ << std::endl;
throw exception(errStream.str().c_str());
}
_se_translator_function old =_set_se_translator(translateFPException);
}
void enableAllFPUExceptions()
{
unsigned int oldMask = 0x00000000;
_clearfp();
// enabling is done by clearing the respective bit in the mask
_controlfp_s(&oldMask, 0x00, _MCW_EM);
}
void disableAllFPUExceptions()
{
unsigned int oldMask = 0x00000000;
_clearfp();
// disabling is done by setting the respective bit in the mask
_controlfp_s(&oldMask, 0xffffffff, _MCW_EM);
}
次に、独自の例外を作成する必要があります (これも単なる抜粋ですが、概念を理解する必要があります)。
class float_exception : public exception
{
public:
float_exception(unsigned int fpuStatus);
unsigned int getStatus();
protected:
unsigned int fpuStatus;
};
class fe_denormal_operand : public float_exception
{
public:
fe_denormal_operand(unsigned int fpuStatus);
};