]> granicus.if.org Git - postgresql/commitdiff
Attached is a patch implementing factorial(), returning numeric. Points
authorBruce Momjian <bruce@momjian.us>
Mon, 1 Dec 2003 21:52:38 +0000 (21:52 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 1 Dec 2003 21:52:38 +0000 (21:52 +0000)
to note:

1) arttype is numeric. I thought this was the best way of allowing
arbitarily large factorials, even though factorial(2^63) is a large
number. Happy to change to integers if this is overkill.
2) since we're accepting numeric arguments, the patch tests for floats.
If a numeric is passed with non-zero decimal portion, an error is raised
since (from memory) they are undefined.

Gavin Sherry

src/backend/utils/adt/int.c
src/backend/utils/adt/int8.c
src/backend/utils/adt/numeric.c
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/int8.h
src/test/regress/expected/create_operator.out
src/test/regress/sql/create_operator.sql

index 70e9971dd1f64db554be27e878e78121a3b6fb97..e23706582e268a31ed79be5cfff1f9ec55e7120a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.58 2003/11/29 19:51:58 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.59 2003/12/01 21:52:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,7 @@
  *              intpl, intmi, int4mul, intdiv
  *
  *             Arithmetic operators:
- *              intmod, int4fac
+ *              intmod
  */
 
 #include "postgres.h"
@@ -849,40 +849,6 @@ int42mod(PG_FUNCTION_ARGS)
        PG_RETURN_INT32(arg1 % arg2);
 }
 
-/* int[24]fac()
- * Factorial
- */
-Datum
-int4fac(PG_FUNCTION_ARGS)
-{
-       int32           arg1 = PG_GETARG_INT32(0);
-       int32           result;
-
-       if (arg1 == 0)
-               result = 1;
-       else if (arg1 < 0)
-               result = 0;
-       else
-               for (result = 1; arg1 > 0; --arg1)
-                       result *= arg1;
-       PG_RETURN_INT32(result);
-}
-
-Datum
-int2fac(PG_FUNCTION_ARGS)
-{
-       int16           arg1 = PG_GETARG_INT16(0);
-       int32           result;
-
-       if (arg1 == 0)
-               result = 1;
-       else if (arg1 < 0)
-               result = 0;
-       else
-               for (result = 1; arg1 > 0; --arg1)
-                       result *= arg1;
-       PG_RETURN_INT32(result);
-}
 
 /* int[24]abs()
  * Absolute value
index 616ceaaf9dbeb8c21c4591f67898fcbfdde4f49d..016330a053395a716d74914b00508437e0362cfb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.49 2003/11/29 19:51:58 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.50 2003/12/01 21:52:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -561,26 +561,6 @@ int8mod(PG_FUNCTION_ARGS)
        PG_RETURN_INT64(result);
 }
 
-/* int8fac()
- * Factorial
- */
-Datum
-int8fac(PG_FUNCTION_ARGS)
-{
-       int64           arg1 = PG_GETARG_INT64(0);
-       int64           result;
-       int64           i;
-
-       if (arg1 == 0)
-               result = 1;
-       else if (arg1 < 1)
-               result = 0;
-       else
-               for (i = arg1, result = 1; i > 0; --i)
-                       result *= i;
-
-       PG_RETURN_INT64(result);
-}
 
 Datum
 int8inc(PG_FUNCTION_ARGS)
index b2ffefa9da4bfbc6666b39da3ffe6725a3a50341..7f16ee37a247910126cb99ab0654080c8cda548b 100644 (file)
@@ -14,7 +14,7 @@
  * Copyright (c) 1998-2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.68 2003/11/29 19:51:59 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.69 2003/12/01 21:52:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1288,6 +1288,55 @@ numeric_larger(PG_FUNCTION_ARGS)
  * ----------------------------------------------------------------------
  */
 
+/*
+ * numeric_fac()
+ * Computer factorial
+ */
+
+Datum
+numeric_fac(PG_FUNCTION_ARGS)
+{
+
+       int64           num = PG_GETARG_INT64(0);
+       NumericVar      count;
+       NumericVar      fact;
+       NumericVar      zerovar;
+       NumericVar      result;
+       Numeric         res;
+
+       if(num < 1) {
+               res = make_result(&const_one);
+               PG_RETURN_NUMERIC(res);
+       }
+
+
+       init_var(&fact);
+       init_var(&count);
+       init_var(&result);
+       init_var(&zerovar);
+       zero_var(&zerovar);
+
+       int8_to_numericvar((int64)num, &result);
+       set_var_from_var(&const_one, &count);
+
+       for(num = num - 1; num > 0; num--) {
+               set_var_from_var(&result,&count);
+
+               int8_to_numericvar((int64)num,&fact);
+
+               mul_var(&count, &fact, &result, count.dscale + fact.dscale);
+       }
+
+       res = make_result(&count);
+
+       free_var(&count);
+       free_var(&fact);
+       free_var(&result);
+       free_var(&zerovar);
+
+       PG_RETURN_NUMERIC(res);
+}
+
 
 /*
  * numeric_sqrt() -
index 42f19d7687dbad538c79e9fe8ac5fdfc4c30ed33..f9ce05af2a6751658b2647894e55757531df524e 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.122 2003/11/29 22:40:58 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.123 2003/12/01 21:52:37 momjian Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -122,12 +122,12 @@ DATA(insert OID = 375 (  "||"        PGNSP PGUID b f 2277 2277 2277       0 0 0 0 0 0 arra
 
 DATA(insert OID = 352 (  "="      PGNSP PGUID b t      28      28      16 352   0       0       0       0       0 xideq eqsel eqjoinsel ));
 DATA(insert OID = 353 (  "="      PGNSP PGUID b f      28      23      16       0       0       0       0       0       0 xideqint4 eqsel eqjoinsel ));
+DATA(insert OID = 388 (  "!"      PGNSP PGUID r f  20   0  1700   0   0   0   0  0   0 numeric_fac - - ));
+DATA(insert OID = 389 (  "!!"     PGNSP PGUID l f   0  20  1700   0   0   0   0  0   0 numeric_fac - - ));
 DATA(insert OID = 385 (  "="      PGNSP PGUID b t      29      29      16 385   0       0       0       0       0 cideq eqsel eqjoinsel ));
 DATA(insert OID = 386 (  "="      PGNSP PGUID b t      22      22      16 386   0       0       0       0       0 int2vectoreq eqsel eqjoinsel ));
 DATA(insert OID = 387 (  "="      PGNSP PGUID b f      27      27      16 387   0       0       0       0       0 tideq eqsel eqjoinsel ));
 #define TIDEqualOperator   387
-DATA(insert OID = 388 (  "!"      PGNSP PGUID r f      20       0      20       0       0       0       0       0       0 int8fac - - ));
-DATA(insert OID = 389 (  "!!"     PGNSP PGUID l f       0      20      20       0       0       0       0       0       0 int8fac - - ));
 
 DATA(insert OID = 410 ( "="               PGNSP PGUID b t      20      20      16 410 411 412 412 412 413 int8eq eqsel eqjoinsel ));
 DATA(insert OID = 411 ( "<>"      PGNSP PGUID b f      20      20      16 411 410 0 0 0 0 int8ne neqsel neqjoinsel ));
@@ -176,8 +176,6 @@ DATA(insert OID = 511 (  "@"           PGNSP PGUID b f 600 603      16       0       0       0       0       0       0 on_
 DATA(insert OID = 512 (  "@"      PGNSP PGUID b f 600 602      16 755   0       0       0       0       0 on_ppath - - ));
 DATA(insert OID = 513 (  "@@"     PGNSP PGUID l f       0 603 600       0       0       0       0       0       0 box_center - - ));
 DATA(insert OID = 514 (  "*"      PGNSP PGUID b f      23      23      23 514   0       0       0       0       0 int4mul - - ));
-DATA(insert OID = 515 (  "!"      PGNSP PGUID r f      23       0      23       0       0       0       0       0       0 int4fac - - ));
-DATA(insert OID = 516 (  "!!"     PGNSP PGUID l f       0      23      23       0       0       0       0       0       0 int4fac - - ));
 DATA(insert OID = 517 (  "<->"    PGNSP PGUID b f 600 600 701 517       0       0       0       0       0 point_distance - - ));
 DATA(insert OID = 518 (  "<>"     PGNSP PGUID b f      23      23      16 518  96      0  0   0   0 int4ne neqsel neqjoinsel ));
 DATA(insert OID = 519 (  "<>"     PGNSP PGUID b f      21      21      16 519  94      0  0   0   0 int2ne neqsel neqjoinsel ));
@@ -507,8 +505,6 @@ DATA(insert OID = 1133 (  ">"               PGNSP PGUID b f  701    700  16 1122 1134  0 0 0 0 f
 DATA(insert OID = 1134 (  "<="         PGNSP PGUID b f  701    700  16 1125 1133  0 0 0 0 float84le scalarltsel scalarltjoinsel ));
 DATA(insert OID = 1135 (  ">="         PGNSP PGUID b f  701    700  16 1124 1132  0 0 0 0 float84ge scalargtsel scalargtjoinsel ));
 
-DATA(insert OID = 1158 (  "!"          PGNSP PGUID r f 21        0   23 0 0 0 0 0 0 int2fac - - ));
-DATA(insert OID = 1175 (  "!!"         PGNSP PGUID l f  0       21   23 0 0 0 0 0 0 int2fac - - ));
 
 /* LIKE hacks by Keith Parks. */
 DATA(insert OID = 1207 (  "~~"   PGNSP PGUID b f  19   25      16 0 1208 0 0 0 0 namelike likesel likejoinsel ));
index 5515a48d31cf4ba1a2883c75ee3a94d6cba2c9f8..1ed5359ffb9b4ebb130401ea8bdbcb494cc5e516 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.316 2003/11/29 22:40:58 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.317 2003/12/01 21:52:37 momjian Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -208,8 +208,6 @@ DESCR("PostgreSQL version string");
 
 /* OIDS 100 - 199 */
 
-DATA(insert OID = 100 (  int8fac                  PGNSP PGUID 12 f f t f i 1 20 "20"  int8fac - _null_ ));
-DESCR("factorial");
 DATA(insert OID = 101 (  eqsel                    PGNSP PGUID 12 f f t f s 4 701 "2281 26 2281 23"  eqsel - _null_ ));
 DESCR("restriction selectivity of = and related operators");
 DATA(insert OID = 102 (  neqsel                           PGNSP PGUID 12 f f t f s 4 701 "2281 26 2281 23"  neqsel - _null_ ));
@@ -231,7 +229,7 @@ DATA(insert OID =  109 (  unknownin            PGNSP PGUID 12 f f t f i 1 705 "2275"        un
 DESCR("I/O");
 DATA(insert OID =  110 (  unknownout      PGNSP PGUID 12 f f t f i 1 2275      "705"   unknownout - _null_ ));
 DESCR("I/O");
-
+DATA(insert OID = 111 (  numeric_fac      PGNSP PGUID 12 f f t f i 1 1700 "20"  numeric_fac - _null_ ));
 DATA(insert OID = 112 (  text                     PGNSP PGUID 12 f f t f i 1  25 "23"  int4_text - _null_ ));
 DESCR("convert int4 to text");
 DATA(insert OID = 113 (  text                     PGNSP PGUID 12 f f t f i 1  25 "21"  int2_text - _null_ ));
@@ -294,8 +292,6 @@ DATA(insert OID = 140 (  areajoinsel           PGNSP PGUID 12 f f t f s 4 701 "2281 26
 DESCR("join selectivity for area-comparison operators");
 DATA(insert OID = 141 (  int4mul                  PGNSP PGUID 12 f f t f i 2 23 "23 23"        int4mul - _null_ ));
 DESCR("multiply");
-DATA(insert OID = 142 (  int4fac                  PGNSP PGUID 12 f f t f i 1 23 "23"  int4fac - _null_ ));
-DESCR("factorial");
 DATA(insert OID = 144 (  int4ne                           PGNSP PGUID 12 f f t f i 2 16 "23 23"        int4ne - _null_ ));
 DESCR("not equal");
 DATA(insert OID = 145 (  int2ne                           PGNSP PGUID 12 f f t f i 2 16 "21 21"        int2ne - _null_ ));
@@ -571,9 +567,6 @@ DESCR("Current date and time - increments during transactions");
 DATA(insert OID = 275 (  isfinite                 PGNSP PGUID 12 f f t f i 1 16 "702"  abstime_finite - _null_ ));
 DESCR("finite abstime?");
 
-DATA(insert OID = 276 (  int2fac                  PGNSP PGUID 12 f f t f i 1 23 "21"  int2fac - _null_ ));
-DESCR("factorial");
-
 DATA(insert OID = 277 (  inter_sl                 PGNSP PGUID 12 f f t f i 2 16 "601 628"      inter_sl - _null_ ));
 DESCR("intersect?");
 DATA(insert OID = 278 (  inter_lb                 PGNSP PGUID 12 f f t f i 2 16 "628 603"      inter_lb - _null_ ));
@@ -1758,11 +1751,7 @@ DATA(insert OID = 1390 (  isfinite          PGNSP PGUID 12 f f t f i 1 16 "1186"  inte
 DESCR("finite interval?");
 
 
-DATA(insert OID = 1391 (  factorial               PGNSP PGUID 12 f f t f i 1 23 "21"  int2fac - _null_ ));
-DESCR("factorial");
-DATA(insert OID = 1392 (  factorial               PGNSP PGUID 12 f f t f i 1 23 "23"  int4fac - _null_ ));
-DESCR("factorial");
-DATA(insert OID = 1393 (  factorial               PGNSP PGUID 12 f f t f i 1 20 "20"  int8fac - _null_ ));
+DATA(insert OID = 1376 (  factorial        PGNSP PGUID 12 f f t f i 1 1700 "20"  numeric_fac - _null_ ));
 DESCR("factorial");
 DATA(insert OID = 1394 (  abs                     PGNSP PGUID 12 f f t f i 1 700 "700"  float4abs - _null_ ));
 DESCR("absolute value");
index 92663c3e5cd1ed1a4f64001ea9823be26c078548..c784f28afdc541558e0f7e109f2372ba382c9d11 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.230 2003/11/29 22:41:15 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.231 2003/12/01 21:52:38 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -159,8 +159,6 @@ extern Datum int4mod(PG_FUNCTION_ARGS);
 extern Datum int2mod(PG_FUNCTION_ARGS);
 extern Datum int24mod(PG_FUNCTION_ARGS);
 extern Datum int42mod(PG_FUNCTION_ARGS);
-extern Datum int4fac(PG_FUNCTION_ARGS);
-extern Datum int2fac(PG_FUNCTION_ARGS);
 extern Datum int2larger(PG_FUNCTION_ARGS);
 extern Datum int2smaller(PG_FUNCTION_ARGS);
 extern Datum int4larger(PG_FUNCTION_ARGS);
@@ -720,6 +718,7 @@ extern Datum numeric_mod(PG_FUNCTION_ARGS);
 extern Datum numeric_inc(PG_FUNCTION_ARGS);
 extern Datum numeric_smaller(PG_FUNCTION_ARGS);
 extern Datum numeric_larger(PG_FUNCTION_ARGS);
+extern Datum numeric_fac(PG_FUNCTION_ARGS);
 extern Datum numeric_sqrt(PG_FUNCTION_ARGS);
 extern Datum numeric_exp(PG_FUNCTION_ARGS);
 extern Datum numeric_ln(PG_FUNCTION_ARGS);
index aad610eb9eec42fef13a66b650806113b5ced293..7fe9800b2359010ee7f166bcd99a1cb27bffea75 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.39 2003/11/29 22:41:15 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.40 2003/12/01 21:52:38 momjian Exp $
  *
  * NOTES
  * These data types are supported on all 64-bit architectures, and may
@@ -72,7 +72,6 @@ extern Datum int8mi(PG_FUNCTION_ARGS);
 extern Datum int8mul(PG_FUNCTION_ARGS);
 extern Datum int8div(PG_FUNCTION_ARGS);
 extern Datum int8abs(PG_FUNCTION_ARGS);
-extern Datum int8fac(PG_FUNCTION_ARGS);
 extern Datum int8mod(PG_FUNCTION_ARGS);
 extern Datum int8inc(PG_FUNCTION_ARGS);
 extern Datum int8larger(PG_FUNCTION_ARGS);
index 7685dbe802c74e7134bca5ac00aabe2aacce37ba..df25f35ae77cbea5302b4752c7b70f24aebe28ab 100644 (file)
@@ -15,19 +15,17 @@ CREATE OPERATOR <% (
    negator = >=% 
 );
 CREATE OPERATOR @#@ (
-   rightarg = int4,            -- left unary 
-   procedure = int4fac 
+   rightarg = int8,            -- left unary 
+   procedure = numeric_fac 
 );
 CREATE OPERATOR #@# (
-   leftarg = int4,             -- right unary
-   procedure = int4fac 
+   leftarg = int8,             -- right unary
+   procedure = numeric_fac
 );
 CREATE OPERATOR #%# ( 
-   leftarg = int4,             -- right unary 
-   procedure = int4fac 
+   leftarg = int8,             -- right unary 
+   procedure = numeric_fac 
 );
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 ERROR:  operator does not exist: integer ######
-COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary';
-COMMENT ON OPERATOR #%# (int4, NONE) IS NULL;
index 4167bf3ab825a0d472df192d35071d0883083a61..6637629ea44223e8a3b8b0481338c73eec1ebb07 100644 (file)
@@ -18,23 +18,21 @@ CREATE OPERATOR <% (
 );
 
 CREATE OPERATOR @#@ (
-   rightarg = int4,            -- left unary 
-   procedure = int4fac 
+   rightarg = int8,            -- left unary 
+   procedure = numeric_fac 
 );
 
 CREATE OPERATOR #@# (
-   leftarg = int4,             -- right unary
-   procedure = int4fac 
+   leftarg = int8,             -- right unary
+   procedure = numeric_fac
 );
 
 CREATE OPERATOR #%# ( 
-   leftarg = int4,             -- right unary 
-   procedure = int4fac 
+   leftarg = int8,             -- right unary 
+   procedure = numeric_fac 
 );
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
-COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary';
-COMMENT ON OPERATOR #%# (int4, NONE) IS NULL;