views:

191

answers:

4

I'm compiling my code via the following command:

icc -ltbb test.cxx -o test

Then when I run the program:

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

I get a "Floating exception". This following is code in C++ that I had before the exception and after:

// 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]);

This is boolean algebra... so (j < E[i]) is either going to be a 0 or a 1 so the multiplication would result either in 0 or the foo() result. I don't see why this would cause a floating exception. This is what foo() does:

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() isn't a function I wrote so I'm not too sure as to what it does... but I don't think the problem is with the function foo(). Is there something about boolean algebra that I don't understand or something that works differently in C++ than I know of? Any ideas why this causes an exception?

Thanks, Hristo

+2  A: 

You are almost certainly dividing by zero in foo.

A simple program of

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

also prints

Floating point exception

on my system.

So, you should check whether e is 0 when s % 4 is zero, or whether t is 0 when s % 4 is 2 or 3. Then return whatever value makes sense for your situation instead of trying to divide by zero.


@hristo: C++ will still evaluate the right-hand-side of a multiplication even if the left-hand-side is zero. It doesn't matter that the result should be zero; it matters that foo was called and evaluated and caused an error.

Sample source:

#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;
}

Output:

Do not raise exception: 1

Before 'if' statement...

Past 'if' statement.

Floating point exception

Mark Rushakoff
Then why would it work the first time compare to the second... the arguments to foo() are exactly the same?
Hristo
@Hristo: The first time, `foo` was not called with the argument causing the crash.
Mark Rushakoff
Because in the first variant the function is only called when `j < E[i]`, but in your "after" code it's called in all cases.
Nikolai N Fetissov
@ Mark. Well, if it didn't go inside the `if` statement in the first version of the code, then (j < E[i]) would be 0 so then the multiplication would result in 0. This isn't sequential code... the "before" is on version, and the "after" replaces what it was before.
Hristo
@Hristo: The multiplication by zero *does not matter*. `foo` is still evaluated, even when multiplied by zero. I've posted some code to demonstrate this.
Mark Rushakoff
Ok. Thanks. I understand that foo() is still evaluated, now I just have to figure out why it is causing a division by 0 when it has the same parameters as before. Thanks.
Hristo
I understand now... before I was not doing a certain iteration because the if statement will evaluate to false.. but now I will do that iteration which would cause the exception. Thanks!
Hristo
+1  A: 

Is it possible you are dividing by 0? It could be that an integer division by 0 is surfacing as a "Floating exception".

When you have the if, the computation isn't done if a division by 0 would happen. When you do the "Boolean algebra", the computation is done regardless, resulting in a divide by 0 error.

You're thinking that it will be temp += 0*foo(...); so it doesn't need to call foo (because 0 times anything will always be 0), but that's not how the compiler works. Both sides of a * have to be evaluated.

Gabe
It is possible, but the only thing that was changed was that I multiplied by `(j < E[i])`... foo() isn't changed nor are its parameters.
Hristo
No... I wasn't thinking that foo() won't be called, I was thinking that this will evaluate to 0. I didn't think foo() would cause an exception because the parameters are the same.
Hristo
A: 

hello.

When I suggested replacing branch with multiplication by one or zero, I did not consider that if statements may be guarding against numerical exception. multiplication trick still evaluates expression, but effectively throws it away. for small enough expression, such trick is better than conditional, but you have to make sure expression can evaluate.

You can still use multiplication trick, if you slightly transform denominator. instead of x/t use x/(t + !t) which does not affect anything if denominator is nonzero (you are adding zero then)but allows denominator t = 0 to be compute, and then thrown away by multiplying by zero.

And sorry, but be careful with my suggestions, I do not know all details of your program. plus, I tend to go wild about replacing branches with "clever" Boolean expressions

aaa
Yes I tried your suggestion with the multiplication trick, but the problem was that the `if` was preventing foo() from causing exceptions and when I used multiplication, foo() was no longer being protected and that resulted in floating exceptions. I can't edit foo(), so I am forced to keep the `if` statement. Thanks for your suggestions!
Hristo
A: 

While I do not tell you the exact cause of your floating-point exception, I can provide some information you might find useful in investigating future floating-point errors. I believe Mark has already shed some light on why you are having this particular problem.


The most portable way of determining if a floating-point exception condition has occurred and its cause is to use the floating-point exception facilities provided by C99 in fenv.h. There are 11 functions defined in fenv.h for manipulating the floating-point environment (see fenv(3) man page). You may also find this article to be of interest.


On POSIX compliant systems, SIGFPE is sent to a process when in performs an erroneous arithmetic operation and this does not necessarily involve floating-point arithmetic. If the SIGFPE signal is handled and SA_SIGINFO is specified in the sa_flags for the call to sigaction(2), the si_code member of the siginfo_t structure should specify the reason for the fault.

From the wikipedia SIGFPE article:

A common oversight is to consider division by zero the only source of SIGFPE conditions. On some architectures (IA-32 included[citation needed]), integer division of INT_MIN, the smallest representable negative integer value, by −1 triggers the signal because the quotient, a positive number, is not representable.

jschmier