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

Commit 6bdf130

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 68e7e97 commit 6bdf130

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
@@ -1548,6 +1548,25 @@ dpow(PG_FUNCTION_ARGS)
15481548
float8 arg2 = PG_GETARG_FLOAT8(1);
15491549
float8 result;
15501550

1551+
/*
1552+
* The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
1553+
* cases with NaN inputs yield NaN (with no error). Many older platforms
1554+
* get one or more of these cases wrong, so deal with them via explicit
1555+
* logic rather than trusting pow(3).
1556+
*/
1557+
if (isnan(arg1))
1558+
{
1559+
if (isnan(arg2) || arg2 != 0.0)
1560+
PG_RETURN_FLOAT8(get_float8_nan());
1561+
PG_RETURN_FLOAT8(1.0);
1562+
}
1563+
if (isnan(arg2))
1564+
{
1565+
if (arg1 != 1.0)
1566+
PG_RETURN_FLOAT8(get_float8_nan());
1567+
PG_RETURN_FLOAT8(1.0);
1568+
}
1569+
15511570
/*
15521571
* The SQL spec requires that we emit a particular SQLSTATE error code for
15531572
* certain error conditions. Specifically, we don't return a
@@ -1569,12 +1588,11 @@ dpow(PG_FUNCTION_ARGS)
15691588
* and result == NaN for negative arg1 and very large arg2 (they must be
15701589
* using something different from our floor() test to decide it's
15711590
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
1572-
* (HUGE_VAL) but finite result to signal overflow. Also, some versions
1573-
* of MSVC return errno == EDOM and result == NaN for NaN inputs.
1591+
* (HUGE_VAL) but finite result to signal overflow.
15741592
*/
15751593
errno = 0;
15761594
result = pow(arg1, arg2);
1577-
if (errno == EDOM && isnan(result) && !isnan(arg1) && !isnan(arg2))
1595+
if (errno == EDOM && isnan(result))
15781596
{
15791597
if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
15801598
/* 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)