26

私は次の変数を持っています:

double dblVar1;
double dblVar2;

それらは大きな値を持っているかもしれませんが、double最大値よりも小さいかもしれません。

私は、足し算、掛け算、累乗など、上記の変数についてさまざまな算術演算を行っています。

double dblVar3 = dblVar1 * dblVar2; 
double dblVar4 = dblVar1 + dblVar2;
double dblVar5 = pow(dblVar1, 2);

上記のすべてで、オーバーフローとアンダーフローをチェックする必要があります。どうすればC++でこれを達成できますか?

4

4 に答える 4

17

多くは文脈に依存します。完全にポータブルにするには、操作のに確認する必要があります。例:(追加の場合):

if ( (a < 0.0) == (b < 0.0)
    && std::abs( b ) > std::numeric_limits<double>::max() - std::abs( a ) ) {
    //  Addition would overflow...
}

同様のロジックを4つの基本的な演算子に使用できます。

ターゲットとするすべてのマシンがIEEEをサポートしている場合(メインフレームを考慮する必要がない場合はおそらくそうです)、操作を実行してから、isfiniteまたはisinf結果を使用できます。

アンダーフローの場合、最初の質問は、段階的なアンダーフローがアンダーフローとしてカウントされるかどうかです。そうでない場合は、結果がゼロであるかどうかを確認するだけで、a != -bうまくいきます。段階的なアンダーフロー(IEEEを使用している場合にのみ存在する可能性があります)を検出する場合は、次を使用できますisnormal。結果が段階的なアンダーフローに対応している場合、これはfalseを返します。(オーバーフローとは異なり、操作にアンダーフローをテストします。)

于 2013-03-27T09:36:00.307 に答える
10

POSIX、C99、C ++ 11には<fenv.h>(および<cfenv>C ++ 11の場合)IEEE754例外フラグをテストする機能があります(C ++例外とは関係がないため、簡単すぎます)。

int  feclearexcept(int);
int  fegetexceptflag(fexcept_t *, int);
int  feraiseexcept(int);
int  fesetexceptflag(const fexcept_t *, int);
int  fetestexcept(int);

フラグは、次のビットが定義されたビットフィールドです。

FE_DIVBYZERO
FE_INEXACT
FE_INVALID
FE_OVERFLOW
FE_UNDERFLOW

したがって、操作の前にそれらをクリアし、後でそれらをテストすることができます。ライブラリ関数がそれらに与える影響については、ドキュメントを確認する必要があります。

于 2013-03-27T09:43:39.970 に答える
9

適切なコンパイラ(最新のC ++標準をサポート)を使用すると、次の関数を使用できます

#include <cfenv>
#include <iostream>

int main() {
    std::feclearexcept(FE_OVERFLOW);
    std::feclearexcept(FE_UNDERFLOW);

    double overflowing_var = 1000;
    double underflowing_var = 0.01;

    std::cout << "Overflow flag before: " << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl;
    std::cout << "Underflow flag before: " << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl;

    for(int i = 0; i < 20; ++i) {
        overflowing_var *= overflowing_var;
        underflowing_var *= underflowing_var;
    }

    std::cout << "Overflow flag after: " << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl;
    std::cout << "Underflow flag after: " << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl;
}

/** Output:
  Overflow flag before: 0
  Underflow flag before: 0
  Overflow flag after: 1
  Underflow flag after: 1
 */
于 2013-03-27T09:52:15.893 に答える
7

ISO C99は、浮動小数点ステータスワードを照会および操作するための関数を定義しています。これらの関数を使用すると、計算の途中で例外を気にするのではなく、都合のよいときにトラップされていない例外をチェックできます。

それは提供します

FE_INEXACT
FE_DIVBYZERO
FE_UNDERFLOW
FE_OVERFLOW
FE_INVALID

例えば

   {
       double f;
       int raised;
       feclearexcept (FE_ALL_EXCEPT);
       f = compute ();
       raised = fetestexcept (FE_OVERFLOW | FE_INVALID);
       if (raised & FE_OVERFLOW) { /* ... */ }
       if (raised & FE_INVALID) { /* ... */ }
       /* ... */
     }

http://www.gnu.org/software/libc/manual/html_node/Status-bit-operations.html

于 2013-03-27T09:46:58.147 に答える