8

executing

double result = pow(base, exponent);

with arbitrary base and exponent

may result in an attempt to compute a value too big or complex.

For example with base=-2, exponent=.5 (square root of -2)

Should I just check if result==NAN or result==HUGE_VAL ?

Would that code be C99 compliant and cross platform ?

Paolo
  • 15,233
  • 27
  • 70
  • 91
  • If you want to catch that case, consider enabling floating point exceptions and catch them. – fuz Feb 07 '16 at 12:51
  • 1
    @FUZxxl: I didn't know about floating point exceptions. Could you point me to some reference or post a code snippet as answer? Thank you – Paolo Feb 07 '16 at 12:54
  • No exceptions on C. You will have to check errno. – Cecilio Pardo Feb 07 '16 at 12:55
  • @CecilioPardo C has floating point exceptions. Please read the standard before making incorrect comments. – fuz Feb 07 '16 at 12:57
  • @Paolo Sorry, I don't know any reference on that. It's a rarely used feature. Read the standard for more details. – fuz Feb 07 '16 at 12:57
  • @fuzxxl: By using terms such as catch you may mislead someone to believe that common try/catch structure is available on C. Better to check errno. – Cecilio Pardo Feb 07 '16 at 13:20
  • 2
    You wouldn't mislead anyone that knew C, @cecilio. And the handling of floating point exceptions is configurable. They may not even be reported via `errno`. – Cody Gray - on strike Feb 07 '16 at 13:22
  • For details, you can also consult the glibc man page math_error(7). – fuz Feb 07 '16 at 14:03
  • My bad, I didn't know that. It seems that the solid answer is to check the parameters before making the call. – Cecilio Pardo Feb 07 '16 at 15:13

1 Answers1

3

Catch SIGFPE and die noisily. There is something worse than a crashed program: one that quietly gives incorrect answers.

Sample code below is taken from a random site about SIGFPE

/* demo_SIGFPE.c

   Demonstrate the generation of the SIGFPE signal.

   Usage: demo_SIGFPE [optstr]

   The main program executes code the generates a SIGFPE signal. Before doing
   so, the program optionally ignores and/or blocks SIGFPE. If 'optstr'
   contains 'i', then SIGFPE is ignored, otherwise it is caught by a handler.
   If 'optstr' contains 'b', then SIGFPE is blocked before it is delivered.
   The behavior that occurs when SIGFPE is generated depends on the kernel
   version (Linux 2.6 is different from Linux 2.4 and earlier).

   NOTE: Don't compile this program with optimization, as the arithmetic
   below is likely to be optimized away completely, with the result that
   we don't get SIGFPE at all.
*/
#define _GNU_SOURCE     /* Get strsignal() declaration from <string.h> */
#include <string.h>
#include <signal.h>

static void
sigfpeCatcher(int sig)
{
    printf("Caught signal %d (%s)\n", sig, strsignal(sig));
                                /* UNSAFE (see Section 21.1.2) */
    sleep(1);                   /* Slow down execution of handler */
}

int
main(int argc, char *argv[])
{
    int x, y;
    sigset_t blockSet, prevMask;
    Boolean blocking;
    struct sigaction sa;

    /* If no command-line arguments specified, catch SIGFPE, else ignore it */

    if (argc > 1 && strchr(argv[1], 'i') != NULL) {
        printf("Ignoring SIGFPE\n");
        if (signal(SIGFPE, SIG_IGN) == SIG_ERR)
            errExit("signal");
    } else {
        printf("Catching SIGFPE\n");
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
        sa.sa_handler = sigfpeCatcher;
        if (sigaction(SIGFPE, &sa, NULL) == -1)
            errExit("sigaction");
    }

    blocking = argc > 1 && strchr(argv[1], 'b') != NULL;
    if (blocking) {
        printf("Blocking SIGFPE\n");
        sigemptyset(&blockSet);
        sigaddset(&blockSet, SIGFPE);
        if (sigprocmask(SIG_BLOCK, &blockSet, &prevMask) == -1)
            errExit("sigprocmask");
    }

    printf("About to generate SIGFPE\n");
    y = 0;
    x = 1 / y;
    y = x;      /* Avoid complaints from "gcc -Wunused-but-set-variable" */


    if (blocking) {
        printf("Sleeping before unblocking\n");
        sleep(2);
        printf("Unblocking SIGFPE\n");
        if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1)
            errExit("sigprocmask");
    }

    printf("Shouldn't get here!\n");
    exit(EXIT_FAILURE);
}
msw
  • 42,753
  • 9
  • 87
  • 112
  • thank you for your answer; I'll consider signal handling as an option. I spent some time reading about that... the problem is that I don't want to abort the whole process in case of exception. Instead I need the exception to be handled "softly" and the function (that contains the offending `pow()`) to just return an error value on a specific parameter. For this I need a global variable where the signal handler would write that an exception occurred but this approach would make my function no more multithread safe. Please, correct me if I'm missing something... – Paolo Feb 08 '16 at 17:21