postgres.git / summary / log / commit / refs
commit 6bdf1303b34bc630e8945ae3407ec7e8395c8fe5
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun Apr 29 22:15:16 2018 +0000
First released in: 11.0, REL9_3_STABLE (reverted before release), REL9_4_STABLE (reverted before release), REL9_5_STABLE (reverted before release), REL9_6_STABLE (reverted before release), REL_10_STABLE (reverted before release)
Reverted by: 99095b632094 (in 9.3.23), 70211459a507 (in 9.4.18), 8fbdd63a52df (in 9.5.13), eab8d6312f15 (in 9.6.9), f74d83b3034f (in 10.4)
Avoid wrong results for power() with NaN input on more platforms.
Buildfarm results show that the modern POSIX rule that 1 ^ NaN = 1 is not
honored on *BSD until relatively recently, and really old platforms don't
believe that NaN ^ 0 = 1 either. (This is unsurprising, perhaps, since
SUSv2 doesn't require either behavior.) In hopes of getting to platform
independent behavior, let's deal with all the NaN-input cases explicitly
in dpow().
Note that numeric_power() doesn't know either of these special cases.
But since that behavior is platform-independent, I think it should be
addressed separately, and probably not back-patched.
Discussion: https://postgr.es/m/75DB81BEEA95B445AE6D576A0A5C9E936A73E741@BPXM05GP.gisp.nec.co.jp
src/backend/utils/adt/float.c | 24 +++++++++++++++++++---
.../expected/float8-exp-three-digits-win32.out | 6 ++++++
src/test/regress/expected/float8-small-is-zero.out | 6 ++++++
.../regress/expected/float8-small-is-zero_1.out | 6 ++++++
src/test/regress/expected/float8.out | 6 ++++++
src/test/regress/sql/float8.sql | 1 +
6 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 88215d910a5..f5b20a5a46b 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1548,6 +1548,25 @@ dpow(PG_FUNCTION_ARGS)
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
+ /*
+ * The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
+ * cases with NaN inputs yield NaN (with no error). Many older platforms
+ * get one or more of these cases wrong, so deal with them via explicit
+ * logic rather than trusting pow(3).
+ */
+ if (isnan(arg1))
+ {
+ if (isnan(arg2) || arg2 != 0.0)
+ PG_RETURN_FLOAT8(get_float8_nan());
+ PG_RETURN_FLOAT8(1.0);
+ }
+ if (isnan(arg2))
+ {
+ if (arg1 != 1.0)
+ PG_RETURN_FLOAT8(get_float8_nan());
+ PG_RETURN_FLOAT8(1.0);
+ }
+
/*
* The SQL spec requires that we emit a particular SQLSTATE error code for
* certain error conditions. Specifically, we don't return a
@@ -1569,12 +1588,11 @@ dpow(PG_FUNCTION_ARGS)
* and result == NaN for negative arg1 and very large arg2 (they must be
* using something different from our floor() test to decide it's
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
- * (HUGE_VAL) but finite result to signal overflow. Also, some versions
- * of MSVC return errno == EDOM and result == NaN for NaN inputs.
+ * (HUGE_VAL) but finite result to signal overflow.
*/
errno = 0;
result = pow(arg1, arg2);
- if (errno == EDOM && isnan(result) && !isnan(arg1) && !isnan(arg2))
+ if (errno == EDOM && isnan(result))
{
if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
/* The sign of Inf is not significant in this case. */
diff --git a/src/test/regress/expected/float8-exp-three-digits-win32.out b/src/test/regress/expected/float8-exp-three-digits-win32.out
index 3fe50b4bf00..3896cdec721 100644
--- a/src/test/regress/expected/float8-exp-three-digits-win32.out
+++ b/src/test/regress/expected/float8-exp-three-digits-win32.out
@@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
NaN
(1 row)
+SELECT power(float8 '-1', float8 'NaN');
+ power
+-------
+ NaN
+(1 row)
+
SELECT power(float8 '1', float8 'NaN');
power
-------
diff --git a/src/test/regress/expected/float8-small-is-zero.out b/src/test/regress/expected/float8-small-is-zero.out
index 46adbe1c4ba..f8e09390f51 100644
--- a/src/test/regress/expected/float8-small-is-zero.out
+++ b/src/test/regress/expected/float8-small-is-zero.out
@@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
NaN
(1 row)
+SELECT power(float8 '-1', float8 'NaN');
+ power
+-------
+ NaN
+(1 row)
+
SELECT power(float8 '1', float8 'NaN');
power
-------
diff --git a/src/test/regress/expected/float8-small-is-zero_1.out b/src/test/regress/expected/float8-small-is-zero_1.out
index f215eede103..ebfec4cdb68 100644
--- a/src/test/regress/expected/float8-small-is-zero_1.out
+++ b/src/test/regress/expected/float8-small-is-zero_1.out
@@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
NaN
(1 row)
+SELECT power(float8 '-1', float8 'NaN');
+ power
+-------
+ NaN
+(1 row)
+
SELECT power(float8 '1', float8 'NaN');
power
-------
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 7159e78d4a7..b05831d45c9 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
NaN
(1 row)
+SELECT power(float8 '-1', float8 'NaN');
+ power
+-------
+ NaN
+(1 row)
+
SELECT power(float8 '1', float8 'NaN');
power
-------
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 5510fe9d345..eeebddd4b78 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -111,6 +111,7 @@ SELECT power(float8 '144', float8 '0.5');
SELECT power(float8 'NaN', float8 '0.5');
SELECT power(float8 '144', float8 'NaN');
SELECT power(float8 'NaN', float8 'NaN');
+SELECT power(float8 '-1', float8 'NaN');
SELECT power(float8 '1', float8 'NaN');
SELECT power(float8 'NaN', float8 '0');
[parent: 68e7e973d222]