Bug 6776 - pow() pole error sets errno to EDOM, should be ERANGE
Summary: pow() pole error sets errno to EDOM, should be ERANGE
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: math (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Andreas Jaeger
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-07-30 10:49 UTC by Michael Kerrisk
Modified: 2014-07-04 05:47 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Kerrisk 2008-07-30 10:49:47 UTC
The POSIX.1 specification of pow says for a pole error:

==
Pole Error
    The value of x is zero and y is negative.

    If the integer expression (math_errhandling & MATH_ERRNO) is non-zero, then
errno shall be set to [ERANGE]. If the integer expression (math_errhandling &
MATH_ERREXCEPT) is non-zero, then the divide-by-zero floating-point exception
shall be raised. 
==

glibc 2.8's pow() does raise the divide-by-zero, as expected.

It also sets errno, but to the wrong value: errno is set to EDOM, when it should
instead be ERANGE.
Comment 1 mtk.manpages@googlemail.com 2008-07-30 20:20:40 UTC
Subject: Re:  New: pow() pole error sets errno to EDOM, should
 be ERANGE

Test program below.  Sample run demonstrating the problem:

$ /tmp/mt_pow -- 0 -4
errno == EDOM
fetestexcept() says:  FE_DIVBYZERO
pow(0.00000000000000000e+00,-4.00000000000000000e+00)=inf
EDOM FE_DIVBYZERO +inf



/* /tmp/mt_pow.c (auto-generated at 2008-07-30 22:06:05) */
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fenv.h>
#include <limits.h>
#include <math.h>
#include <float.h>
#include <ctype.h>

#define EXIT_test_setup_failed 2

static int verbose = 1;

/* Convert a string to a double, but allow a few special cases
    in the form of non-numeric strings */

static double
string_to_d(char *str)
{
     char *p;
     char *s;
     double retval;

     s = strdup(str);
     if (s == NULL) {
         perror("strdup");
         exit(EXIT_test_setup_failed);
     }

     for (p = s; *p; p++)
         *p = toupper(*p);

     if (strcmp(s, "-INF") == 0)
         retval = -HUGE_VAL;
     else if (strcmp(s, "INF") == 0 || strcmp(s, "+INF") == 0)
         retval = HUGE_VAL;
     else if (strcmp(s, "NAN") == 0)
         retval = nan("");

     else if (strcmp(s, "MIN") == 0 || strcmp(s, "+MIN") == 0)
         retval = DBL_MIN;
     else if (strcmp(s, "-MIN") == 0)
         retval = -DBL_MIN;
     else if (strcmp(s, "MAX") == 0 || strcmp(s, "+MAX") == 0)
         retval = DBL_MAX;
     else if (strcmp(s, "-MAX") == 0)
         retval = -DBL_MAX;

     else if (strcmp(s, "DBL_MIN") == 0)
         retval = DBL_MIN;
     else if (strcmp(s, "-DBL_MIN") == 0)
         retval = -DBL_MIN;
     else if (strcmp(s, "DBL_MAX") == 0)
         retval = DBL_MAX;
     else if (strcmp(s, "-DBL_MAX") == 0)
         retval = -DBL_MAX;

     else if (strcmp(s, "FLT_MIN") == 0)
         retval = FLT_MIN;
     else if (strcmp(s, "-FLT_MIN") == 0)
         retval = -FLT_MIN;
     else if (strcmp(s, "FLT_MAX") == 0)
         retval = FLT_MAX;
     else if (strcmp(s, "-FLT_MAX") == 0)
         retval = -FLT_MAX;

     else if (strcmp(s, "LDBL_MIN") == 0)
         retval = LDBL_MIN;
     else if (strcmp(s, "-LDBL_MIN") == 0)
         retval = -LDBL_MIN;
     else if (strcmp(s, "LDBL_MAX") == 0)
         retval = LDBL_MAX;
     else if (strcmp(s, "-LDBL_MAX") == 0)
         retval = -LDBL_MAX;

     else if (strncmp(s, "SUBNORMAL", 9) == 0 ||
              strncmp(s, "-SUBNORMAL", 10) == 0) {
         char *h;
         int d, j;

         h = strchr(s, ':');
         if (h == NULL)
             d = 4;
         else
             d = atoi(h + 1);
         retval = DBL_MIN;
         for (j = 0; j < d; j++)
             retval /= 2.0;
         if (s[0] == '-')
             retval = -retval;
     } else if (strchr("+-0123456789", s[0]) == NULL) {
         fprintf(stderr, "Bad argument: %s\n", s);
         exit(EXIT_test_setup_failed);
     } else
         retval = strtod(s, NULL);

     free(s);
     return retval;
}

static void
clearErrors(void)
{
     errno = 0;
     feclearexcept(FE_ALL_EXCEPT);
}

static void
checkErrors(int *r_errno, int *r_except)
{
     *r_errno = errno;

     if (verbose) {
         if (*r_errno == 0) {
             fprintf(stderr, "errno == 0\n");
         } else {
             if (*r_errno == EDOM)
                 fprintf(stderr, "errno == EDOM\n");
             else if (*r_errno == ERANGE)
                 fprintf(stderr, "errno == ERANGE\n");
             else
                 fprintf(stderr, "errno == %d\n", *r_errno);
         }
     }

     *r_except = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW |
                          FE_UNDERFLOW | FE_INEXACT);

     if (verbose) {
         printf("fetestexcept() says: ");
         if (*r_except & FE_INVALID)
             printf(" FE_INVALID");
         if (*r_except & FE_DIVBYZERO)
             printf(" FE_DIVBYZERO");
         if (*r_except & FE_OVERFLOW)
             printf(" FE_OVERFLOW");
         if (*r_except & FE_UNDERFLOW)
             printf(" FE_UNDERFLOW");
         if (*r_except & FE_INEXACT)
             printf(" FE_INEXACT");
         printf("\n");
     }
}

static void
usage(char *pname, char *msg)
{
     if (msg != NULL)
         fprintf(stderr, "%s\n", msg);
     fprintf(stderr, "Usage: %s [-q] [-e errno,except,class] <args>\n",
                     pname);
     fprintf(stderr, "-q  quiet\n");
     fprintf(stderr, "-e  expected results, expressed via errno, exception,"
                     "and class of function result\n");
     fprintf(stderr, "    errno can be EDOM, ERANGE, or 0\n");
     fprintf(stderr, "    except can be FP_INVALID, FE_DIVBYZERO, "
                     "FP_OVERFLOW, FP_UNDERFLOW, or 0\n");
     fprintf(stderr, "    class can be +0, -0, +inf, -inf, nan, normal, "
                     "or subnormal\n");
     exit(EXIT_test_setup_failed);
}

int
main(int argc, char *argv[])
{
     int opt;
     int e_errno, e_except, e_class, e_sign;
     int dont_check_errno = 0, dont_check_except = 0, dont_check_class = 0;
     int e_opt_present;
     int r_errno, r_except;
     int exit_status = EXIT_SUCCESS;
     int value_expected = 0;
     char *perrno, *pexcept, *pclass;

     double x;
     double y;
     double result;
     double e_value;
     int int_value_expected = 0;

     e_opt_present = 0;
     while ((opt = getopt(argc, argv, "qe:")) != -1) {
         //printf("opt=%c\n", opt);
         switch (opt) {
         case 'q':
             verbose = 0;
             break;

         case 'e':
             {
             char *c1, *c2, *p;

             e_opt_present = 1;

             for (p = optarg; *p != '\0'; p++)
                 *p = toupper(*p);

             c1 = strchr(optarg, ',');
             if (c1 == NULL)
                 usage(argv[0], "bad -e spec");
             *c1 = '\0';

             c2 = strchr(c1 + 1, ',');
             if (c2 == NULL)
                 usage(argv[0], "bad -e spec");
             *c2 = '\0';

             perrno = optarg;
             pexcept = c1 + 1;
             pclass = c2 + 1;

             if (strcmp(perrno, "*") == 0)
                 dont_check_errno = 1;
             else if (strcmp(perrno, "0") == 0)
                 e_errno = 0;
             else if (strcmp(perrno, "EDOM") == 0)
                 e_errno = EDOM;
             else if (strcmp(perrno, "ERANGE") == 0)
                 e_errno = ERANGE;
             else
                 usage(argv[0], "Bad errno in -e spec");

             if (strcmp(pexcept, "*") == 0)
                 dont_check_except = 1;
             else if (strcmp(pexcept, "0") == 0)
                 e_except = 0;
             else if (strcmp(pexcept, "FE_DIVBYZERO") == 0)
                 e_except = FE_DIVBYZERO;
             else if (strcmp(pexcept, "FE_INVALID") == 0)
                 e_except = FE_INVALID;
             else if (strcmp(pexcept, "FE_OVERFLOW") == 0)
                 e_except = FE_OVERFLOW;
             else if (strcmp(pexcept, "FE_UNDERFLOW") == 0)
                 e_except = FE_UNDERFLOW;
             else
                 usage(argv[0], "Bad except in -e spec");


             if (strcmp(pclass, "*") == 0)
                 dont_check_class = 1;
             else if (strcmp(pclass, "+0") == 0) {
                 e_class = FP_ZERO;
                 e_sign = +1;
             } else if (strcmp(pclass, "-0") == 0) {
                 e_class = FP_ZERO;
                 e_sign = -1;
             } else if (strcmp(pclass, "+INF") == 0) {
                 e_class = FP_INFINITE;
                 e_sign = +1;
             } else if (strcmp(pclass, "-INF") == 0) {
                 e_class = FP_INFINITE;
                 e_sign = -1;
             } else if (strcmp(pclass, "NORMAL") == 0) {
                 e_class = FP_NORMAL;
             } else if (strcmp(pclass, "SUBNORMAL") == 0) {
                 e_class = FP_SUBNORMAL;
             } else if (strcmp(pclass, "NAN") == 0) {
                 e_class = FP_NAN;
             } else {
                 char *ep;
                 value_expected = 1;
                 int_value_expected = 1;
                 if (strcmp(pclass, "FP_ILOGB0") == 0) {
                     e_value = FP_ILOGB0;
                 } else if (strcmp(pclass, "FP_ILOGBNAN") == 0) {
                     e_value = FP_ILOGBNAN;
                 } else if (strcmp(pclass, "INT_MAX") == 0) {
                     e_value = INT_MAX;
                 } else {
                     e_value = strtod(pclass, &ep);
                     if (*ep != '\0') {
                         fprintf(stderr, "ep=%s\n", ep);
                         usage(argv[0], "Unrecognized class value");
                     }
                     if (islessgreater(remainder(e_value, 1.0), 0.0))
                         int_value_expected = 0;
                 }
             }
             }
             break;

         default:
             usage(argv[0], NULL);
             exit(EXIT_test_setup_failed);
         }
     }

     assert(argc == optind - 1 + 3);
     x = string_to_d(argv[optind]);
     y =  string_to_d(argv[optind+1]) ;

     clearErrors();

     result = pow(x, y);
     checkErrors(&r_errno, &r_except);
     printf("pow(%.17e,%.17e)=%.17e\n", x, y, result);

     printf("%s ", (r_errno == 0) ? "0" :
                   (r_errno == EDOM) ? "EDOM" :
                   (r_errno == ERANGE) ? "ERANGE" : "???errno???");

     printf("%s ", ((r_except & (FE_DIVBYZERO | FE_UNDERFLOW |
                         FE_OVERFLOW | FE_INVALID)) == 0) ? "0" :
                    (r_except & FE_DIVBYZERO) ? "FE_DIVBYZERO" :
                    (r_except & FE_UNDERFLOW) ? "FE_UNDERFLOW" :
                    (r_except & FE_OVERFLOW)  ? "FE_OVERFLOW" :
                    (r_except & FE_INVALID)   ? "FE_INVALID" : "???except???");

     int r_class = fpclassify(result);
     int r_sign = signbit(result) ? -1 : 1;

     if (r_class == FP_INFINITE || r_class == FP_ZERO)
         printf("%s", signbit(result) ? "-" : "+");
     printf("%s", (r_class == FP_ZERO) ? "0" :
                   (r_class == FP_NAN) ? "nan" :
                   (r_class == FP_INFINITE) ? "inf" :
                   (r_class == FP_NORMAL) ? "normal" :
                   (r_class == FP_SUBNORMAL) ? "subnormal" : "???class???");


     if (e_opt_present) {
         printf("; ");
         int errno_passed, except_passed, class_passed, all_passed;

         errno_passed = dont_check_errno || (r_errno == e_errno);
         except_passed = dont_check_except ||
                 (e_except == 0 && (r_except & ~FE_INEXACT) == 0) ||
                 ((r_except & e_except) != 0);
         class_passed = dont_check_class ||
                        (value_expected && int_value_expected &&
                         !isnan(result) && result == e_value) ||
                        (value_expected && !isnan(result) &&
                         fabsl((result - e_value) / e_value) < 1e-5) ||
                        (r_class == e_class &&
                         ((r_class == FP_NAN || r_class == FP_NORMAL ||
                           r_class == FP_SUBNORMAL) ||
                          r_sign == e_sign));

         printf("%s ", (r_errno == e_errno) ? "ok" : "fail-errno");
         printf("%s ", except_passed ? "ok" : "fail-except");
         printf("%s", class_passed ? "ok" : "fail-result");

         all_passed = errno_passed && except_passed && class_passed;

         if (!all_passed)
             exit_status = EXIT_FAILURE;

         printf("; %s", all_passed ? "PASS" : "FAIL");
         if (!all_passed) {
             printf(" (expected: ");
             if (e_errno == 0 && e_except == 0) {
                 printf("no-error");
             } else if (e_errno == EDOM && e_except == FE_INVALID) {
                 printf("domain-error");
             } else if (e_errno == ERANGE && e_except == FE_OVERFLOW) {
                 printf("range-error-overflow");
             } else if (e_errno == ERANGE && e_except == FE_UNDERFLOW) {
                 printf("range-error-underflow");
             } else if (e_errno == ERANGE && e_except == FE_DIVBYZERO) {
                 printf("pole-error");
             }
             printf(" (%s, %s); %s", perrno, pexcept, pclass);

             printf(")");
         }
     }

     printf("\n\n");
     exit(exit_status);
}

/* /tmp/mt_pow.c (auto-generated at 2008-07-30 22:06:05) */
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fenv.h>
#include <limits.h>
#include <math.h>
#include <float.h>
#include <ctype.h>

#define EXIT_test_setup_failed 2

static int verbose = 1;

/* Convert a string to a double, but allow a few special cases
   in the form of non-numeric strings */

static double
string_to_d(char *str)
{
    char *p;
    char *s;
    double retval;

    s = strdup(str);
    if (s == NULL) {
        perror("strdup");
        exit(EXIT_test_setup_failed);
    }

    for (p = s; *p; p++)
        *p = toupper(*p);

    if (strcmp(s, "-INF") == 0) 
        retval = -HUGE_VAL; 
    else if (strcmp(s, "INF") == 0 || strcmp(s, "+INF") == 0) 
        retval = HUGE_VAL;
    else if (strcmp(s, "NAN") == 0) 
        retval = nan("");

    else if (strcmp(s, "MIN") == 0 || strcmp(s, "+MIN") == 0) 
        retval = DBL_MIN;
    else if (strcmp(s, "-MIN") == 0) 
        retval = -DBL_MIN;
    else if (strcmp(s, "MAX") == 0 || strcmp(s, "+MAX") == 0) 
        retval = DBL_MAX;
    else if (strcmp(s, "-MAX") == 0) 
        retval = -DBL_MAX;

    else if (strcmp(s, "DBL_MIN") == 0) 
        retval = DBL_MIN;
    else if (strcmp(s, "-DBL_MIN") == 0) 
        retval = -DBL_MIN;
    else if (strcmp(s, "DBL_MAX") == 0) 
        retval = DBL_MAX;
    else if (strcmp(s, "-DBL_MAX") == 0) 
        retval = -DBL_MAX;

    else if (strcmp(s, "FLT_MIN") == 0) 
        retval = FLT_MIN;
    else if (strcmp(s, "-FLT_MIN") == 0) 
        retval = -FLT_MIN;
    else if (strcmp(s, "FLT_MAX") == 0) 
        retval = FLT_MAX;
    else if (strcmp(s, "-FLT_MAX") == 0) 
        retval = -FLT_MAX;

    else if (strcmp(s, "LDBL_MIN") == 0) 
        retval = LDBL_MIN;
    else if (strcmp(s, "-LDBL_MIN") == 0) 
        retval = -LDBL_MIN;
    else if (strcmp(s, "LDBL_MAX") == 0) 
        retval = LDBL_MAX;
    else if (strcmp(s, "-LDBL_MAX") == 0) 
        retval = -LDBL_MAX;

    else if (strncmp(s, "SUBNORMAL", 9) == 0 ||
             strncmp(s, "-SUBNORMAL", 10) == 0) {
        char *h;
        int d, j;

        h = strchr(s, ':');
        if (h == NULL)
            d = 4;
        else
            d = atoi(h + 1);
        retval = DBL_MIN;
        for (j = 0; j < d; j++)
            retval /= 2.0;
        if (s[0] == '-')
            retval = -retval;
    } else if (strchr("+-0123456789", s[0]) == NULL) {
        fprintf(stderr, "Bad argument: %s\n", s);
        exit(EXIT_test_setup_failed);
    } else
        retval = strtod(s, NULL);

    free(s);
    return retval;
}

static void
clearErrors(void)
{
    errno = 0;
    feclearexcept(FE_ALL_EXCEPT);
}

static void
checkErrors(int *r_errno, int *r_except)
{
    *r_errno = errno;

    if (verbose) {
        if (*r_errno == 0) {
            fprintf(stderr, "errno == 0\n");
        } else {
            if (*r_errno == EDOM)
                fprintf(stderr, "errno == EDOM\n");
            else if (*r_errno == ERANGE)
                fprintf(stderr, "errno == ERANGE\n");
            else
                fprintf(stderr, "errno == %d\n", *r_errno);
        }
    }

    *r_except = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW |
                         FE_UNDERFLOW | FE_INEXACT);

    if (verbose) {
        printf("fetestexcept() says: ");
        if (*r_except & FE_INVALID)
            printf(" FE_INVALID");
        if (*r_except & FE_DIVBYZERO)
            printf(" FE_DIVBYZERO");
        if (*r_except & FE_OVERFLOW)
            printf(" FE_OVERFLOW");
        if (*r_except & FE_UNDERFLOW)
            printf(" FE_UNDERFLOW");
        if (*r_except & FE_INEXACT)
            printf(" FE_INEXACT");
        printf("\n");
    }
}

static void
usage(char *pname, char *msg)
{
    if (msg != NULL)
        fprintf(stderr, "%s\n", msg);
    fprintf(stderr, "Usage: %s [-q] [-e errno,except,class] <args>\n",
                    pname);
    fprintf(stderr, "-q  quiet\n");
    fprintf(stderr, "-e  expected results, expressed via errno, exception,"
                    "and class of function result\n");
    fprintf(stderr, "    errno can be EDOM, ERANGE, or 0\n");
    fprintf(stderr, "    except can be FP_INVALID, FE_DIVBYZERO, "
                    "FP_OVERFLOW, FP_UNDERFLOW, or 0\n");
    fprintf(stderr, "    class can be +0, -0, +inf, -inf, nan, normal, "
                    "or subnormal\n");
    exit(EXIT_test_setup_failed);
}

int
main(int argc, char *argv[])
{
    int opt;
    int e_errno, e_except, e_class, e_sign;
    int dont_check_errno = 0, dont_check_except = 0, dont_check_class = 0;
    int e_opt_present;
    int r_errno, r_except;
    int exit_status = EXIT_SUCCESS;
    int value_expected = 0;
    char *perrno, *pexcept, *pclass;

    double x; 
    double y;
    double result;
    double e_value;
    int int_value_expected = 0;

    e_opt_present = 0;
    while ((opt = getopt(argc, argv, "qe:")) != -1) {
        //printf("opt=%c\n", opt);
        switch (opt) {
        case 'q':
            verbose = 0;
            break;

        case 'e':
            {
            char *c1, *c2, *p;

            e_opt_present = 1;

            for (p = optarg; *p != '\0'; p++)
                *p = toupper(*p);

            c1 = strchr(optarg, ',');
            if (c1 == NULL) 
                usage(argv[0], "bad -e spec");
            *c1 = '\0';

            c2 = strchr(c1 + 1, ',');
            if (c2 == NULL) 
                usage(argv[0], "bad -e spec");
            *c2 = '\0';

            perrno = optarg;
            pexcept = c1 + 1;
            pclass = c2 + 1;

            if (strcmp(perrno, "*") == 0)
                dont_check_errno = 1;
            else if (strcmp(perrno, "0") == 0)
                e_errno = 0;
            else if (strcmp(perrno, "EDOM") == 0)
                e_errno = EDOM;
            else if (strcmp(perrno, "ERANGE") == 0)
                e_errno = ERANGE;
            else
                usage(argv[0], "Bad errno in -e spec");

            if (strcmp(pexcept, "*") == 0)
                dont_check_except = 1;
            else if (strcmp(pexcept, "0") == 0)
                e_except = 0;
            else if (strcmp(pexcept, "FE_DIVBYZERO") == 0)
                e_except = FE_DIVBYZERO;
            else if (strcmp(pexcept, "FE_INVALID") == 0)
                e_except = FE_INVALID;
            else if (strcmp(pexcept, "FE_OVERFLOW") == 0)
                e_except = FE_OVERFLOW;
            else if (strcmp(pexcept, "FE_UNDERFLOW") == 0)
                e_except = FE_UNDERFLOW;
            else
                usage(argv[0], "Bad except in -e spec");


            if (strcmp(pclass, "*") == 0)
                dont_check_class = 1;
            else if (strcmp(pclass, "+0") == 0) {
                e_class = FP_ZERO;
                e_sign = +1;
            } else if (strcmp(pclass, "-0") == 0) {
                e_class = FP_ZERO;
                e_sign = -1;
            } else if (strcmp(pclass, "+INF") == 0) {
                e_class = FP_INFINITE;
                e_sign = +1;
            } else if (strcmp(pclass, "-INF") == 0) {
                e_class = FP_INFINITE;
                e_sign = -1;
            } else if (strcmp(pclass, "NORMAL") == 0) {
                e_class = FP_NORMAL;
            } else if (strcmp(pclass, "SUBNORMAL") == 0) {
                e_class = FP_SUBNORMAL;
            } else if (strcmp(pclass, "NAN") == 0) {
                e_class = FP_NAN;
            } else {
                char *ep;
                value_expected = 1;
                int_value_expected = 1;
                if (strcmp(pclass, "FP_ILOGB0") == 0) {
                    e_value = FP_ILOGB0;
                } else if (strcmp(pclass, "FP_ILOGBNAN") == 0) {
                    e_value = FP_ILOGBNAN;
                } else if (strcmp(pclass, "INT_MAX") == 0) {
                    e_value = INT_MAX;
                } else {
                    e_value = strtod(pclass, &ep);
                    if (*ep != '\0') {
                        fprintf(stderr, "ep=%s\n", ep);
                        usage(argv[0], "Unrecognized class value");
                    }
                    if (islessgreater(remainder(e_value, 1.0), 0.0))
                        int_value_expected = 0;
                }
            }
            }
            break;

        default:
            usage(argv[0], NULL);
            exit(EXIT_test_setup_failed);
        }
    }

    assert(argc == optind - 1 + 3);
    x = string_to_d(argv[optind]);
    y =  string_to_d(argv[optind+1]) ;

    clearErrors();

    result = pow(x, y);
    checkErrors(&r_errno, &r_except);
    printf("pow(%.17e,%.17e)=%.17e\n", x, y, result);

    printf("%s ", (r_errno == 0) ? "0" :
                  (r_errno == EDOM) ? "EDOM" :
                  (r_errno == ERANGE) ? "ERANGE" : "???errno???");

    printf("%s ", ((r_except & (FE_DIVBYZERO | FE_UNDERFLOW |
                        FE_OVERFLOW | FE_INVALID)) == 0) ? "0" :
                   (r_except & FE_DIVBYZERO) ? "FE_DIVBYZERO" :
                   (r_except & FE_UNDERFLOW) ? "FE_UNDERFLOW" :
                   (r_except & FE_OVERFLOW)  ? "FE_OVERFLOW" :
                   (r_except & FE_INVALID)   ? "FE_INVALID" : "???except???");

    int r_class = fpclassify(result);
    int r_sign = signbit(result) ? -1 : 1;

    if (r_class == FP_INFINITE || r_class == FP_ZERO) 
        printf("%s", signbit(result) ? "-" : "+");
    printf("%s", (r_class == FP_ZERO) ? "0" :
                  (r_class == FP_NAN) ? "nan" :
                  (r_class == FP_INFINITE) ? "inf" :
                  (r_class == FP_NORMAL) ? "normal" :
                  (r_class == FP_SUBNORMAL) ? "subnormal" : "???class???");


    if (e_opt_present) {
        printf("; ");
        int errno_passed, except_passed, class_passed, all_passed;

        errno_passed = dont_check_errno || (r_errno == e_errno);
        except_passed = dont_check_except ||
                (e_except == 0 && (r_except & ~FE_INEXACT) == 0) ||
                ((r_except & e_except) != 0);
        class_passed = dont_check_class ||
                       (value_expected && int_value_expected &&
                        !isnan(result) && result == e_value) ||  
                       (value_expected && !isnan(result) &&
                        fabsl((result - e_value) / e_value) < 1e-5) ||
                       (r_class == e_class && 
                        ((r_class == FP_NAN || r_class == FP_NORMAL || 
                          r_class == FP_SUBNORMAL) ||
                         r_sign == e_sign));

        printf("%s ", (r_errno == e_errno) ? "ok" : "fail-errno");
        printf("%s ", except_passed ? "ok" : "fail-except");
        printf("%s", class_passed ? "ok" : "fail-result");

        all_passed = errno_passed && except_passed && class_passed;

        if (!all_passed)
            exit_status = EXIT_FAILURE;

        printf("; %s", all_passed ? "PASS" : "FAIL");
        if (!all_passed) {
            printf(" (expected: ");
            if (e_errno == 0 && e_except == 0) {
                printf("no-error");
            } else if (e_errno == EDOM && e_except == FE_INVALID) {
                printf("domain-error");
            } else if (e_errno == ERANGE && e_except == FE_OVERFLOW) {
                printf("range-error-overflow");
            } else if (e_errno == ERANGE && e_except == FE_UNDERFLOW) {
                printf("range-error-underflow");
            } else if (e_errno == ERANGE && e_except == FE_DIVBYZERO) {
                printf("pole-error");
            }
            printf(" (%s, %s); %s", perrno, pexcept, pclass);

            printf(")");
        }
    }

    printf("\n\n");
    exit(exit_status);
}
Comment 2 Michael Kerrisk 2010-09-12 06:00:17 UTC
This bug has been fixed in glibc 2.10.1 (or possibly 2.9, I haven't found the
source code change and I don't have a 2.9 system to test). man-pages-2.37 is
updated accordingly.
Comment 3 Jackie Rosen 2014-02-16 19:36:44 UTC Comment hidden (spam)