Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 217d8f3

Browse files
committed
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
1 parent 783e8f5 commit 217d8f3

File tree

6 files changed

+46
-3
lines changed

6 files changed

+46
-3
lines changed

src/backend/utils/adt/float.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,25 @@ dpow(PG_FUNCTION_ARGS)
14611461
float8 arg2 = PG_GETARG_FLOAT8(1);
14621462
float8 result;
14631463

1464+
/*
1465+
* The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
1466+
* cases with NaN inputs yield NaN (with no error). Many older platforms
1467+
* get one or more of these cases wrong, so deal with them via explicit
1468+
* logic rather than trusting pow(3).
1469+
*/
1470+
if (isnan(arg1))
1471+
{
1472+
if (isnan(arg2) || arg2 != 0.0)
1473+
PG_RETURN_FLOAT8(get_float8_nan());
1474+
PG_RETURN_FLOAT8(1.0);
1475+
}
1476+
if (isnan(arg2))
1477+
{
1478+
if (arg1 != 1.0)
1479+
PG_RETURN_FLOAT8(get_float8_nan());
1480+
PG_RETURN_FLOAT8(1.0);
1481+
}
1482+
14641483
/*
14651484
* The SQL spec requires that we emit a particular SQLSTATE error code for
14661485
* certain error conditions. Specifically, we don't return a
@@ -1482,12 +1501,11 @@ dpow(PG_FUNCTION_ARGS)
14821501
* and result == NaN for negative arg1 and very large arg2 (they must be
14831502
* using something different from our floor() test to decide it's
14841503
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
1485-
* (HUGE_VAL) but finite result to signal overflow. Also, some versions
1486-
* of MSVC return errno == EDOM and result == NaN for NaN inputs.
1504+
* (HUGE_VAL) but finite result to signal overflow.
14871505
*/
14881506
errno = 0;
14891507
result = pow(arg1, arg2);
1490-
if (errno == EDOM && isnan(result) && !isnan(arg1) && !isnan(arg2))
1508+
if (errno == EDOM && isnan(result))
14911509
{
14921510
if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
14931511
/* The sign of Inf is not significant in this case. */

src/test/regress/expected/float8-exp-three-digits-win32.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
358358
NaN
359359
(1 row)
360360

361+
SELECT power(float8 '-1', float8 'NaN');
362+
power
363+
-------
364+
NaN
365+
(1 row)
366+
361367
SELECT power(float8 '1', float8 'NaN');
362368
power
363369
-------

src/test/regress/expected/float8-small-is-zero.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
362362
NaN
363363
(1 row)
364364

365+
SELECT power(float8 '-1', float8 'NaN');
366+
power
367+
-------
368+
NaN
369+
(1 row)
370+
365371
SELECT power(float8 '1', float8 'NaN');
366372
power
367373
-------

src/test/regress/expected/float8-small-is-zero_1.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
362362
NaN
363363
(1 row)
364364

365+
SELECT power(float8 '-1', float8 'NaN');
366+
power
367+
-------
368+
NaN
369+
(1 row)
370+
365371
SELECT power(float8 '1', float8 'NaN');
366372
power
367373
-------

src/test/regress/expected/float8.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
358358
NaN
359359
(1 row)
360360

361+
SELECT power(float8 '-1', float8 'NaN');
362+
power
363+
-------
364+
NaN
365+
(1 row)
366+
361367
SELECT power(float8 '1', float8 'NaN');
362368
power
363369
-------

src/test/regress/sql/float8.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ SELECT power(float8 '144', float8 '0.5');
111111
SELECT power(float8 'NaN', float8 '0.5');
112112
SELECT power(float8 '144', float8 'NaN');
113113
SELECT power(float8 'NaN', float8 'NaN');
114+
SELECT power(float8 '-1', float8 'NaN');
114115
SELECT power(float8 '1', float8 'NaN');
115116
SELECT power(float8 'NaN', float8 '0');
116117

0 commit comments

Comments
 (0)