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

Commit d1fc750

Browse files
committed
Make numeric power() handle NaNs according to the modern POSIX spec.
In commit 6bdf130, we ensured that power()/^ for float8 would honor the NaN behaviors specified by POSIX standards released in this century, ie NaN ^ 0 = 1 and 1 ^ NaN = 1. However, numeric_power() was not touched and continued to follow the once-common behavior that every case involving NaN input produces NaN. For consistency, let's switch the numeric behavior to the modern spec in the same release that ensures that behavior for float8. (Note that while 6bdf130 was initially back-patched, we later undid that, concluding that any behavioral change should appear only in v11.) Discussion: https://postgr.es/m/10898.1526421338@sss.pgh.pa.us
1 parent b2b8222 commit d1fc750

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

src/backend/utils/adt/numeric.c

+19-2
Original file line numberDiff line numberDiff line change
@@ -2972,10 +2972,27 @@ numeric_power(PG_FUNCTION_ARGS)
29722972
NumericVar result;
29732973

29742974
/*
2975-
* Handle NaN
2975+
* Handle NaN cases. We follow the POSIX spec for pow(3), which says that
2976+
* NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other cases with NaN inputs
2977+
* yield NaN (with no error).
29762978
*/
2977-
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
2979+
if (NUMERIC_IS_NAN(num1))
2980+
{
2981+
if (!NUMERIC_IS_NAN(num2))
2982+
{
2983+
init_var_from_num(num2, &arg2);
2984+
if (cmp_var(&arg2, &const_zero) == 0)
2985+
PG_RETURN_NUMERIC(make_result(&const_one));
2986+
}
29782987
PG_RETURN_NUMERIC(make_result(&const_nan));
2988+
}
2989+
if (NUMERIC_IS_NAN(num2))
2990+
{
2991+
init_var_from_num(num1, &arg1);
2992+
if (cmp_var(&arg1, &const_one) == 0)
2993+
PG_RETURN_NUMERIC(make_result(&const_one));
2994+
PG_RETURN_NUMERIC(make_result(&const_nan));
2995+
}
29792996

29802997
/*
29812998
* Initialize things

src/test/regress/expected/numeric.out

+31
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,37 @@ select 0.0 ^ 12.34;
16641664
0.0000000000000000
16651665
(1 row)
16661666

1667+
-- NaNs
1668+
select 'NaN'::numeric ^ 'NaN'::numeric;
1669+
?column?
1670+
----------
1671+
NaN
1672+
(1 row)
1673+
1674+
select 'NaN'::numeric ^ 0;
1675+
?column?
1676+
----------
1677+
1
1678+
(1 row)
1679+
1680+
select 'NaN'::numeric ^ 1;
1681+
?column?
1682+
----------
1683+
NaN
1684+
(1 row)
1685+
1686+
select 0 ^ 'NaN'::numeric;
1687+
?column?
1688+
----------
1689+
NaN
1690+
(1 row)
1691+
1692+
select 1 ^ 'NaN'::numeric;
1693+
?column?
1694+
----------
1695+
1
1696+
(1 row)
1697+
16671698
-- invalid inputs
16681699
select 0.0 ^ (-12.34);
16691700
ERROR: zero raised to a negative power is undefined

src/test/regress/sql/numeric.sql

+7
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,13 @@ select (-12.34) ^ 0.0;
911911
select 12.34 ^ 0.0;
912912
select 0.0 ^ 12.34;
913913

914+
-- NaNs
915+
select 'NaN'::numeric ^ 'NaN'::numeric;
916+
select 'NaN'::numeric ^ 0;
917+
select 'NaN'::numeric ^ 1;
918+
select 0 ^ 'NaN'::numeric;
919+
select 1 ^ 'NaN'::numeric;
920+
914921
-- invalid inputs
915922
select 0.0 ^ (-12.34);
916923
select (-12.34) ^ 1.2;

0 commit comments

Comments
 (0)