diff options
author | Tanner Gooding <tannergooding@users.noreply.github.com> | 2016-06-02 11:29:59 -0700 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2016-06-02 20:29:59 +0200 |
commit | 3d53df24c366c8f0c44196039279d34f78f72b3e (patch) | |
tree | 476e0625d8e0c62bc8ebcafb78605d073688b7eb | |
parent | 7ba374cb4950e0c2ea8db5b982061dde99aef45a (diff) | |
download | coreclr-3d53df24c366c8f0c44196039279d34f78f72b3e.tar.gz coreclr-3d53df24c366c8f0c44196039279d34f78f72b3e.tar.bz2 coreclr-3d53df24c366c8f0c44196039279d34f78f72b3e.zip |
Fixing an error in PAL_pow that caused it to return an incorrect value for a couple scenarios. (#5399)
* Fixing an error in PAL_pow that caused it to return an incorrect value for a couple scenarios.
* Adding additional PAL_pow tests.
-rw-r--r-- | src/pal/src/configure.cmake | 20 | ||||
-rw-r--r-- | src/pal/src/cruntime/math.cpp | 24 | ||||
-rw-r--r-- | src/pal/tests/palsuite/c_runtime/pow/test1/test1.c | 47 |
3 files changed, 70 insertions, 21 deletions
diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index 4f1aabdbe6..24ed60e151 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -775,7 +775,25 @@ check_cxx_source_runs(" int main(void) { double infinity = 1.0 / 0.0; - if (!isnan(pow(1.0, infinity))) { + if (pow(1.0, infinity) != 1.0 || pow(1.0, -infinity) != 1.0) { + exit(1) + } + if (!isnan(pow(-1.0, infinity)) || !isnan(pow(-1.0, -infinity))) { + exit(1); + } + if (pow(0.0, infinity) != 0.0) { + exit(1); + } + if (pow(0.0, -infinity) != infinity) { + exit(1); + } + if (pow(-1.1, infinity) != infinity || pow(1.1, infinity) != infinity) { + exit(1); + } + if (pow(-1.1, -infinity) != 0.0 || pow(1.1, infinity) != 0.0) { + exit(1); + } + if (pow(-0.0, -1) != -infinity) { exit(1); } if (pow(0.0, -1) != infinity) { diff --git a/src/pal/src/cruntime/math.cpp b/src/pal/src/cruntime/math.cpp index dd45110d2f..7075fd60f9 100644 --- a/src/pal/src/cruntime/math.cpp +++ b/src/pal/src/cruntime/math.cpp @@ -33,6 +33,8 @@ Abstract: #define PAL_POSINF_DBL -log(0.0) #define PAL_NEGINF_DBL log(0.0) +#define IS_DBL_NEGZERO(x) (((*((INT64*)((void*)&x))) & I64(0xFFFFFFFFFFFFFFFF)) == I64(0x8000000000000000)) + SET_DEFAULT_DEBUG_CHANNEL(CRT); /*++ @@ -331,9 +333,13 @@ PALIMPORT double __cdecl PAL_pow(double x, double y) ENTRY("pow (x=%f, y=%f)\n", x, y); #if !HAVE_COMPATIBLE_POW - if (y == PAL_POSINF_DBL && !isnan(x)) // +Inf + if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf { - if ((x == 1.0) || (x == -1.0)) + if (x == 1.0) + { + ret = x; + } + else if (x == -1.0) { ret = PAL_NAN_DBL; // NaN } @@ -348,7 +354,11 @@ PALIMPORT double __cdecl PAL_pow(double x, double y) } else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf { - if ((x == 1.0) || (x == -1.0)) + if (x == 1.0) + { + ret = x; + } + else if (x == -1.0) { ret = PAL_NAN_DBL; // NaN } @@ -361,6 +371,10 @@ PALIMPORT double __cdecl PAL_pow(double x, double y) ret = 0.0; } } + else if (IS_DBL_NEGZERO(x) && (y == -1.0)) + { + ret = PAL_NEGINF_DBL; // -Inf + } else if ((x == 0.0) && (y < 0.0)) { ret = PAL_POSINF_DBL; // +Inf @@ -377,9 +391,9 @@ PALIMPORT double __cdecl PAL_pow(double x, double y) } else { - ret = pow(x, y); + ret = pow(x, y); } - + #if !HAVE_VALID_NEGATIVE_INF_POW if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2))) { diff --git a/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c index 690ae947ac..0a05cd5a47 100644 --- a/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c @@ -91,26 +91,37 @@ int __cdecl main(int argc, char **argv) struct test tests[] = { /* x y expected variance */ - { PAL_NEGINF, PAL_NEGINF, 0, PAL_EPSILON }, - { PAL_NEGINF, PAL_POSINF, PAL_POSINF, 0 }, - - { -10, PAL_NEGINF, 0, PAL_EPSILON }, - { -10, -1, -0.1, PAL_EPSILON }, - { -10, 0, 1, PAL_EPSILON * 10 }, - { -10, 1, -10, PAL_EPSILON * 100 }, - { -10, PAL_POSINF, PAL_POSINF, 0 }, - - { -2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON }, // x: -(e) - { -2.7182818284590452, -1, -0.36787944117144232, PAL_EPSILON }, // x: -(e) - { -2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: -(e) - { -2.7182818284590452, 1, -2.7182818284590452, PAL_EPSILON * 10 }, // x: -(e) expected: e - { -2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: -(e) - + { PAL_NEGINF, PAL_NEGINF, 0, PAL_EPSILON }, + { PAL_NEGINF, PAL_POSINF, PAL_POSINF, 0 }, + + { -10, PAL_NEGINF, 0, PAL_EPSILON }, + { -10, -1, -0.1, PAL_EPSILON }, + { -10, 0, 1, PAL_EPSILON * 10 }, + { -10, 1, -10, PAL_EPSILON * 100 }, + { -10, PAL_POSINF, PAL_POSINF, 0 }, + + { -2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON }, // x: -(e) + { -2.7182818284590452, -1, -0.36787944117144232, PAL_EPSILON }, // x: -(e) + { -2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: -(e) + { -2.7182818284590452, 1, -2.7182818284590452, PAL_EPSILON * 10 }, // x: -(e) expected: e + { -2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: -(e) + + { -0.0, PAL_NEGINF, PAL_POSINF, 0 }, + { -0.0, -1, PAL_NEGINF, 0 }, { -0.0, -0.0, 1, PAL_EPSILON * 10 }, { -0.0, 0, 1, PAL_EPSILON * 10 }, + { -0.0, 1, -0.0, PAL_EPSILON }, + { -0.0, PAL_POSINF, 0, PAL_EPSILON }, + { 0.0, PAL_NEGINF, PAL_POSINF, 0 }, + { 0.0, -1, PAL_POSINF, 0 }, { 0, -0.0, 1, PAL_EPSILON * 10 }, { 0, 0, 1, PAL_EPSILON * 10 }, + { 0.0, 1, 0, PAL_EPSILON }, + { 0.0, PAL_POSINF, 0, PAL_EPSILON }, + + { 1, PAL_NEGINF, 1, PAL_EPSILON * 10 }, + { 1, PAL_POSINF, 1, PAL_EPSILON * 10 }, { 2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON }, { 2.7182818284590452, -3.1415926535897932, 0.043213918263772250, PAL_EPSILON / 10 }, // x: e y: -(pi) @@ -199,6 +210,12 @@ int __cdecl main(int argc, char **argv) validate_isnan(-2.7182818284590452, -0.78539816339744828); // x: -(e) y: -(pi / 4) validate_isnan(-2.7182818284590452, 0.78539816339744828); // x: -(e) y: pi / 4 validate_isnan(-2.7182818284590452, 1.5707963267948966); // x: -(e) y: pi / 2 + + validate_isnan(-1, PAL_NEGINF); + validate_isnan(-1, PAL_POSINF); + + validate_isnan(PAL_NAN, -0.0); + validate_isnan(PAL_NAN, 0); validate_isnan(PAL_NEGINF, PAL_NAN); validate_isnan(PAL_NAN, PAL_NEGINF); |