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++ 中的工作方式与我所知道的不同?任何想法为什么这会导致异常?

谢谢, 赫里斯托

4

4 回答 4

3

您几乎可以肯定在 中除以零foo

一个简单的程序

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

也打印

Floating point exception

在我的系统上。

因此,您应该检查es % 4为零时是否t为 0,或者当s % 4为 2 或 3 时是否为 0。然后返回对您的情况有意义的任何值,而不是尝试除以零。


@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

虽然我没有告诉您浮点异常的确切原因,但我可以提供一些您可能会发现对调查未来的浮点错误有用的信息。我相信马克已经阐明了您为什么会遇到这个特殊问题。


确定是否发生浮点异常条件及其原因的最便携方法是使用 C99 在fenv.h中提供的浮点异常工具。在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 回答
1

你有可能被0除吗?整数除以 0 可能会显示为“浮动异常”。

当您拥有 时if,如果发生除以 0,则不会完成计算。当您执行“布尔代数”时,无论如何都会完成计算,从而导致除以 0 错误。

你认为它temp += 0*foo(...);不需要调用 foo (因为 0 次总是 0),但这不是编译器的工作方式。a 的双方*都必须进行评估。

于 2010-05-02T05:10:45.230 回答
0

当我建议用乘以 1 或 0 来替换分支时,我没有考虑 if 语句可能会防范数值异常。乘法技巧仍然计算表达式,但有效地将其丢弃。对于足够小的表达式,这种技巧比条件更好,但你必须确保表达式可以评估。

如果您稍微变换分母,您仍然可以使用乘法技巧。如果分母为非零(然后添加零),而不是x/t使用x/(t + !t)不会影响任何内容,但允许t = 0计算分母,然后通过乘以零来丢弃。

抱歉,但请注意我的建议,我不知道您程序的所有细节。另外,我倾向于用“聪明的”布尔表达式替换分支

于 2010-05-02T05:53:13.660 回答