0

次のコマンドを使用してコードをコンパイルしています。

icc -ltbb test.cxx -o test

次に、プログラムを実行すると、次のようになります。

time ./mp6 100 > output.modified
Floating exception
4.871u 0.405s 0:05.28 99.8%     0+0k 0+0io 0pf+0w

「フローティング例外」が発生します。以下は、例外の前と後のC++のコードです。

// before
if (j < E[i]) {
   temp += foo(0, trr[i], ex[i+j*N]);
}

// after
temp += (j < E[i])*foo(0, trr[i], ex[i+j*N]);

これはブール代数です...したがって、(j <E [i])は0または1になるため、乗算の結果は0またはfoo()の結果になります。なぜこれがフローティング例外を引き起こすのかわかりません。これはfoo()が行うことです:

int foo(int s, int t, int e) {
    switch(s % 4) {
        case 0:
            return abs(t - e)/e;
        case 1:
            return (t == e) ? 0 : 1;
        case 2:
            return (t < e) ? 5 : (t - e)/t;
        case 3:
            return abs(t - e)/t;
    }
    return 0;
}

foo()は私が書いた関数ではないので、それが何をするのかよくわかりません...しかし、問題は関数foo()にあるとは思いません。私が理解していないブール代数や、C ++で私が知っているものとは異なる動作をするものはありますか?これが例外を引き起こす理由はありますか?

ありがとう、Hristo

4

4 に答える 4

3

ほぼ確実にゼロ除算ですfoo

の簡単なプログラム

int main()
{
    int bad = 0;
    return 25/bad;
}

また、印刷します

Floating point exception

私のシステムで。

したがって、がゼロの場合は0であるか、が2または3の場合は0であるかを確認する必要がeありs % 4ますts % 4次に、ゼロで除算するのではなく、状況に適した値を返します。


@hristo:C ++は、左側がゼロの場合でも、乗算の右側を評価します。結果ゼロであることは問題ではありません。foo呼び出されて評価され、エラーが発生したことが重要です。

サンプルソース:

#include <iostream>
int maybe_cause_exception(bool cause_it)
{
    int divisor = cause_it ? 0 : 10;
    return 10 / divisor;
}

int main()
{
    std::cout << "Do not raise exception: " << maybe_cause_exception(false) << std::endl;

    int x = 0;

    std::cout << "Before 'if' statement..." << std::endl;

    if(x)
    {
        std::cout << "Inside if: " << maybe_cause_exception(true) << std::endl;
    }

    std::cout << "Past 'if' statement." << std::endl;

    std::cout << "Cause exception: " << x * maybe_cause_exception(true) << std::endl;

    return 0;
}

出力:

Do not raise exception: 1

Before 'if' statement...

Past 'if' statement.

Floating point exception

于 2010-05-02T05:09:18.480 に答える
1

0で除算することは可能ですか?0による整数除算が「フローティング例外」として浮上している可能性があります。

がある場合if、0による除算が発生した場合、計算は行われません。「ブール代数」を実行すると、計算は関係なく実行されるため、ゼロ除算エラーが発生します。

あなたはそうなると思っているtemp += 0*foo(...);ので、fooを呼び出す必要はありません(0回は常に0になるため)が、それはコンパイラーの動作方法ではありません。の両側を*評価する必要があります。

于 2010-05-02T05:10:45.230 に答える
1

浮動小数点例外の正確な原因については説明しませんが、将来の浮動小数点エラーの調査に役立つ可能性のある情報をいくつか提供できます。マークは、なぜあなたがこの特定の問題を抱えているのかについてすでにいくつかの光を当てていると思います。


浮動小数点例外条件が発生したかどうか、およびその原因を判別する最も移植性の高い方法は、fenv.hでC99によって提供される浮動小数点例外機能を使用することです。浮動小数点環境を操作するためにfenv.hで定義されている11の関数があります( fenv(3)のマニュアルページを参照)。また、この記事が興味深いと思うかもしれません。


POSIX準拠のシステムでSIGFPEは、inが誤った算術演算を実行すると、プロセスに送信されます。これには、必ずしも浮動小数点算術が含まれるとは限りません。SIGFPEシグナルが処理され、の呼び出しでSA_SIGINFO指定されている場合、構造体のメンバーは障害の理由を指定する必要があります。sa_flagssigaction(2)si_codesiginfo_t

ウィキペディアのSIGFPE記事から:

一般的な見落としは、ゼロ除算をSIGFPE条件の唯一の原因と見なすことです。一部のアーキテクチャ(IA-32を含む[要出典])では、表現可能な最小の負の整数値であるINT_MINを-1で除算すると、正の数である商が表現できないため、信号がトリガーされます。

于 2010-05-02T05:57:58.873 に答える
0

ブランチを1または0の乗算に置き換えることを提案したとき、ifステートメントが数値の例外を防ぐ可能性があるとは考えていませんでした。掛け算のトリックはまだ式を評価しますが、効果的にそれを捨てます。十分に小さい式の場合、このようなトリックは条件付きよりも優れていますが、式が評価できることを確認する必要があります。

分母を少し変換すれば、乗算トリックを使用できます。分母がゼロ以外の場合(ゼロを加算している場合)は何も影響を与えないが、分母を計算し、ゼロを掛けることによって破棄することを可能にx/tする使用の代わりに。x/(t + !t)t = 0

申し訳ありませんが、私の提案には注意してください。あなたのプログラムの詳細をすべて知っているわけではありません。さらに、ブランチを「賢い」ブール式に置き換えることに夢中になりがちです

于 2010-05-02T05:53:13.660 に答える