]> granicus.if.org Git - postgresql/commitdiff
Make numeric power() handle NaNs according to the modern POSIX spec.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 May 2018 15:10:50 +0000 (11:10 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 May 2018 15:10:50 +0000 (11:10 -0400)
In commit 6bdf1303b, 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 6bdf1303b 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

src/backend/utils/adt/numeric.c
src/test/regress/expected/numeric.out
src/test/regress/sql/numeric.sql

index dcf31e340c15dc3fdcca79cf4f999e069fa83cba..8dfdffcfbd1cf2b90a914e66ca1bdbf45419fd83 100644 (file)
@@ -2972,10 +2972,27 @@ numeric_power(PG_FUNCTION_ARGS)
        NumericVar      result;
 
        /*
-        * Handle NaN
+        * Handle NaN cases.  We follow the POSIX spec for pow(3), which says that
+        * NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other cases with NaN inputs
+        * yield NaN (with no error).
         */
-       if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
+       if (NUMERIC_IS_NAN(num1))
+       {
+               if (!NUMERIC_IS_NAN(num2))
+               {
+                       init_var_from_num(num2, &arg2);
+                       if (cmp_var(&arg2, &const_zero) == 0)
+                               PG_RETURN_NUMERIC(make_result(&const_one));
+               }
                PG_RETURN_NUMERIC(make_result(&const_nan));
+       }
+       if (NUMERIC_IS_NAN(num2))
+       {
+               init_var_from_num(num1, &arg1);
+               if (cmp_var(&arg1, &const_one) == 0)
+                       PG_RETURN_NUMERIC(make_result(&const_one));
+               PG_RETURN_NUMERIC(make_result(&const_nan));
+       }
 
        /*
         * Initialize things
index 17985e8540124700122496a7b07cd2fe8a0a8114..1cb3c3bfab717cfe09fc953aedf6213b6c8b868d 100644 (file)
@@ -1664,6 +1664,37 @@ select 0.0 ^ 12.34;
  0.0000000000000000
 (1 row)
 
+-- NaNs
+select 'NaN'::numeric ^ 'NaN'::numeric;
+ ?column? 
+----------
+      NaN
+(1 row)
+
+select 'NaN'::numeric ^ 0;
+ ?column? 
+----------
+        1
+(1 row)
+
+select 'NaN'::numeric ^ 1;
+ ?column? 
+----------
+      NaN
+(1 row)
+
+select 0 ^ 'NaN'::numeric;
+ ?column? 
+----------
+      NaN
+(1 row)
+
+select 1 ^ 'NaN'::numeric;
+ ?column? 
+----------
+        1
+(1 row)
+
 -- invalid inputs
 select 0.0 ^ (-12.34);
 ERROR:  zero raised to a negative power is undefined
index d77504e6246332b747792dd22128c6b5e6279564..a939412359625e2d910280f58bb24980f0995c35 100644 (file)
@@ -911,6 +911,13 @@ select (-12.34) ^ 0.0;
 select 12.34 ^ 0.0;
 select 0.0 ^ 12.34;
 
+-- NaNs
+select 'NaN'::numeric ^ 'NaN'::numeric;
+select 'NaN'::numeric ^ 0;
+select 'NaN'::numeric ^ 1;
+select 0 ^ 'NaN'::numeric;
+select 1 ^ 'NaN'::numeric;
+
 -- invalid inputs
 select 0.0 ^ (-12.34);
 select (-12.34) ^ 1.2;