NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/49240: Some corner cases for pow() fail to work correctly
>Number: 49240
>Category: lib
>Synopsis: Some corner cases for pow() fail to work correctly
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Sep 28 16:25:01 +0000 2014
>Originator: Havard Eidnes
>Release: NetBSD 6.1_STABLE
>Organization:
>Environment:
System: NetBSD smistad.uninett.no 6.1_STABLE NetBSD 6.1_STABLE (MAANEN) #0: Mon Sep 1 14:42:18 CEST 2014 root%smistad.uninett.no@localhost:/usr/obj/sys/arch/i386/compile/MAANEN i386
Architecture: i386
Machine: i386
>Description:
While working on pkgsrc-wip/v8's test suite, I found one of
them which failed which excercise the pow() function, by
first doing some simple sanity checking and then trying out
various corner cases.
The v8 test bails out on the first test failure. I've
translated the tests into C, which runs through all the tests
counting up the successes and failures, displaying the result
of each test, with details for the failing tests.
Mostly, the failing tests on NetBSD appear also to contradict
the comments about the "Special cases" near the top of our
lib/libm/src/e_pow.c. The test failures and the special case
confirming the test is OK and our code is not are:
Test failure: NaN == pow(1, Infinity)
a == nan
b == 1.000000
Test failure: NaN == pow(1, -Infinity)
a == nan
b == 1.000000
* 9. +-1 ** +-INF is NAN
Test failure: Infinity == pow(+0.0, -1.1)
a == inf
b == -inf
Test failure: Infinity == pow(+0.0, -2)
a == inf
b == -inf
* 12. +0 ** (-anything except 0, NAN) is +INF
Test failure: Infinity == pow(-0.0, -3.1)
a == inf
b == -inf
Test failure: Infinity == pow(-0.0, -2)
a == inf
b == -inf
Test failure: +Infinity == pow(-0.0, -0.5)
a == inf
b == -inf
Test failure: +Infinity == pow(-0.0, -0.6)
a == inf
b == -inf
* 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
>How-To-Repeat:
Compile and run this program, and watch it fail 8 of our tests
on netbsd-6 and netbsd-7.
(The meat of the code is (c) Google with a 3-clause BSD-like
license, but this is a translation into C by myself.)
------------------------------ snip
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define Infinity INFINITY
#define NaN NAN
#define assertEquals(a, b) \
do { \
if ((a) != (b)) { \
char s1[64], s2[64]; \
sprintf(s1, "%f", (double)(a)); \
sprintf(s2, "%f", (double)(b)); \
if ((strcmp(s1, "nan") == 0) || \
(strcmp(s2, "nan") == 0)) { \
if (strcmp(s1, s2) != 0) { \
printf("Test failure: %s == %s\n", #a, #b); \
printf(" a == %s\n", s1); \
printf(" b == %s\n", s2); \
failures++; \
} else { \
printf("Test OK : %s == %s\n", #a, #b); \
ok++; \
} \
} else { \
printf("Test failure: %s == %s\n", #a, #b); \
printf(" a == %f\n", (double)(a)); \
printf(" b == %f\n", (double)(b)); \
failures++; \
} \
} else { \
printf("Test OK : %s == %s\n", #a, #b); \
ok++; \
} \
} while(0)
int
main(int argc, char **argv)
{
int failures = 0;
int ok = 0;
// These two need to work for the tests to work
// Verify the "nan" dance in the assertEquals macro...
assertEquals(NaN, NaN);
assertEquals(Infinity, Infinity);
// Spec tests
assertEquals(NaN, pow(2, NaN));
assertEquals(NaN, pow(+0.0, NaN));
assertEquals(NaN, pow(-0.0, NaN));
assertEquals(NaN, pow(Infinity, NaN));
assertEquals(NaN, pow(-Infinity, NaN));
assertEquals(1, pow(NaN, +0.0));
assertEquals(1, pow(NaN, -0.0));
assertEquals(NaN, pow(NaN, NaN));
assertEquals(NaN, pow(NaN, 2.2));
assertEquals(NaN, pow(NaN, 1));
assertEquals(NaN, pow(NaN, -1));
assertEquals(NaN, pow(NaN, -2.2));
assertEquals(NaN, pow(NaN, Infinity));
assertEquals(NaN, pow(NaN, -Infinity));
assertEquals(Infinity, pow(1.1, Infinity));
assertEquals(Infinity, pow(-1.1, Infinity));
assertEquals(Infinity, pow(2, Infinity));
assertEquals(Infinity, pow(-2, Infinity));
// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity
assertEquals(+Infinity, 1/pow(1.1, -Infinity));
assertEquals(+Infinity, 1/pow(-1.1, -Infinity));
assertEquals(+Infinity, 1/pow(2, -Infinity));
assertEquals(+Infinity, 1/pow(-2, -Infinity));
assertEquals(NaN, pow(1, Infinity));
assertEquals(NaN, pow(1, -Infinity));
assertEquals(NaN, pow(-1, Infinity));
assertEquals(NaN, pow(-1, -Infinity));
assertEquals(+0.0, pow(0.1, Infinity));
assertEquals(+0.0, pow(-0.1, Infinity));
assertEquals(+0.0, pow(0.999, Infinity));
assertEquals(+0.0, pow(-0.999, Infinity));
assertEquals(Infinity, pow(0.1, -Infinity));
assertEquals(Infinity, pow(-0.1, -Infinity));
assertEquals(Infinity, pow(0.999, -Infinity));
assertEquals(Infinity, pow(-0.999, -Infinity));
assertEquals(Infinity, pow(Infinity, 0.1));
assertEquals(Infinity, pow(Infinity, 2));
assertEquals(+Infinity, 1/pow(Infinity, -0.1));
assertEquals(+Infinity, 1/pow(Infinity, -2));
assertEquals(-Infinity, pow(-Infinity, 3));
assertEquals(-Infinity, pow(-Infinity, 13));
assertEquals(Infinity, pow(-Infinity, 3.1));
assertEquals(Infinity, pow(-Infinity, 2));
assertEquals(-Infinity, 1/pow(-Infinity, -3));
assertEquals(-Infinity, 1/pow(-Infinity, -13));
assertEquals(+Infinity, 1/pow(-Infinity, -3.1));
assertEquals(+Infinity, 1/pow(-Infinity, -2));
assertEquals(+Infinity, 1/pow(+0.0, 1.1));
assertEquals(+Infinity, 1/pow(+0.0, 2));
assertEquals(Infinity, pow(+0.0, -1.1));
assertEquals(Infinity, pow(+0.0, -2));
assertEquals(-Infinity, 1/pow(-0.0, 3));
assertEquals(-Infinity, 1/pow(-0.0, 13));
assertEquals(+Infinity, 1/pow(-0.0, 3.1));
assertEquals(+Infinity, 1/pow(-0.0, 2));
assertEquals(-Infinity, pow(-0.0, -3));
assertEquals(-Infinity, pow(-0.0, -13));
assertEquals(Infinity, pow(-0.0, -3.1));
assertEquals(Infinity, pow(-0.0, -2));
assertEquals(NaN, pow(-0.00001, 1.1));
assertEquals(NaN, pow(-0.00001, -1.1));
assertEquals(NaN, pow(-1.1, 1.1));
assertEquals(NaN, pow(-1.1, -1.1));
assertEquals(NaN, pow(-2, 1.1));
assertEquals(NaN, pow(-2, -1.1));
assertEquals(NaN, pow(-1000, 1.1));
assertEquals(NaN, pow(-1000, -1.1));
assertEquals(+Infinity, 1/pow(-0.0, 0.5));
assertEquals(+Infinity, 1/pow(-0.0, 0.6));
assertEquals(-Infinity, 1/pow(-0.0, 1));
assertEquals(-Infinity, 1/pow(-0.0, 10000000001.0));
assertEquals(+Infinity, pow(-0.0, -0.5));
assertEquals(+Infinity, pow(-0.0, -0.6));
assertEquals(-Infinity, pow(-0.0, -1));
assertEquals(-Infinity, pow(-0.0, -10000000001.0));
assertEquals(4, pow(16, 0.5));
assertEquals(NaN, pow(-16, 0.5));
assertEquals(0.25, pow(16, -0.5));
assertEquals(NaN, pow(-16, -0.5));
// Test detecting and converting integer value as double.
assertEquals(8, pow(2, sqrt(9)));
// Tests from Mozilla 15.8.2.13.
assertEquals(Infinity, pow(-Infinity, Infinity));
assertEquals(0, pow(-Infinity, -Infinity));
assertEquals(1, pow(0, 0));
assertEquals(0, pow(0, Infinity));
assertEquals(NaN, pow(NaN, 0.5));
assertEquals(NaN, pow(NaN, -0.5));
// Tests from Sputnik S8.5_A13_T1.
assertEquals(
(1*((pow(2,53))-1)*(pow(2,-1074))),
4.4501477170144023e-308);
assertEquals(
(1*(pow(2,52))*(pow(2,-1074))),
2.2250738585072014e-308);
assertEquals(
(-1*(pow(2,52))*(pow(2,-1074))),
-2.2250738585072014e-308);
printf("\n");
printf("Failed tests: %d\n", failures);
printf("Successful tests: %d\n", ok);
exit(failures != 0);
}
------------------------------ snip
>Fix:
Sorry, no fix proposed.
The pcc maintainer tested this with pcc on netbsd-6, and
interestingly these two tests succeed with pcc but fail with
gcc (with the same libm!):
Test OK : NaN == pow(1, Infinity)
Test OK : NaN == pow(1, -Infinity)
Also of interest is that there's been a regression between
netbsd-5 and netbsd-6 on the number of test failures: these
two succeed on netbsd-5:
Test OK : Infinity == pow(-0.0, -2)
Test OK : Infinity == pow(+0.0, -2)
but fail on netbsd-6 or netbsd-7:
Test failure: Infinity == pow(+0.0, -2)
a == inf
b == -inf
Test failure: Infinity == pow(-0.0, -2)
a == inf
b == -inf
This is seen both for macppc and amd64.
Home |
Main Index |
Thread Index |
Old Index