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.
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); }
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.
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.