summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanner Gooding <tannergooding@users.noreply.github.com>2016-06-02 11:29:59 -0700
committerJan Vorlicek <janvorli@microsoft.com>2016-06-02 20:29:59 +0200
commit3d53df24c366c8f0c44196039279d34f78f72b3e (patch)
tree476e0625d8e0c62bc8ebcafb78605d073688b7eb
parent7ba374cb4950e0c2ea8db5b982061dde99aef45a (diff)
downloadcoreclr-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.cmake20
-rw-r--r--src/pal/src/cruntime/math.cpp24
-rw-r--r--src/pal/tests/palsuite/c_runtime/pow/test1/test1.c47
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);