diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2018-04-29 18:15:16 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2018-04-29 18:15:16 -0400 |
commit | 6bdf1303b34bc630e8945ae3407ec7e8395c8fe5 (patch) | |
tree | 0d03b62e28f5de9103c4be0d0f8852a803eec768 /src/backend/utils/adt/float.c | |
parent | 68e7e973d22274a089ce95200b3782f514f6d2f8 (diff) | |
download | postgresql-6bdf1303b34bc630e8945ae3407ec7e8395c8fe5.tar.gz postgresql-6bdf1303b34bc630e8945ae3407ec7e8395c8fe5.zip |
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
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r-- | src/backend/utils/adt/float.c | 24 |
1 files changed, 21 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 @@ -1549,6 +1549,25 @@ dpow(PG_FUNCTION_ARGS) 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 * divide-by-zero error code for 0 ^ -1. @@ -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. */ |