pg.ddx.io  pgsql-docs@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Gavin Sherry <swm@linuxworld.com.au>
To: pgsql-patches@postgresql.org
Subject: Numeric version of factorial()
Date: Fri, 1 Aug 2003 10:58:15 +1000 (EST)
Message-ID: <Pine.LNX.4.21.0308011020560.12997-200000@linuxworld.com.au> (raw)

Attached is a patch implementing factorial(), returning numeric. Points 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.
3) I have not removed factorial([int2|int4|int8]), not their operator
counterparts since I didn't know what people would want done with these.
4) I haven't added any documentation but am happy to once I know if people
want int or numeric arguments.

Thanks,

Gavin

Attachments:

factorial.diff (text/plain, 5.9K) download Index: src/backend/utils/adt/numeric.c =================================================================== RCS file: /usr/local/cvsroot/pgsql-server/src/backend/utils/adt/numeric.c,v retrieving revision 1.62 diff -2 -c -r1.62 numeric.c *** src/backend/utils/adt/numeric.c 3 Jul 2003 19:41:47 -0000 1.62 --- src/backend/utils/adt/numeric.c 1 Aug 2003 14:48:23 -0000 *************** *** 1312,1315 **** --- 1312,1429 ---- */ + /* + * numeric_fac() + * Computer factorial + */ + + Datum + numeric_fac(PG_FUNCTION_ARGS) + { + + Numeric num1 = PG_GETARG_NUMERIC(0); + NumericVar count; + NumericVar fact; + NumericVar one; + NumericVar zerovar; + NumericVar result; + NumericVar tmp; + Numeric res; + int ret; + bool firstcall = true; + + /* + * Handle NaN + */ + if (NUMERIC_IS_NAN(num1)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&fact); + init_var(&one); + set_var_from_num(num1, &fact); + int8_to_numericvar((int64)1, &one); + + ret = cmp_var(&fact, &one); + + /* if <= 1, return(1) */ + + if(ret < 1) { + res = make_result(&one); + free_var(&fact); + free_var(&one); + PG_RETURN_NUMERIC(res); + } + + init_var(&tmp); + set_var_from_num(num1, &fact); + + /* + * n.x! is undefined, truncate factorial, and compare + * to original + */ + + set_var_from_var(&fact, &tmp); + trunc_var(&tmp,0); + ret = cmp_var(&fact, &tmp); + if(ret != 0) { + elog(ERROR,"Factorials can only be calculated on natural numbers"); + } + + /* + * Truncate factorial anyway, since n.0000 might have been passed + */ + + trunc_var(&fact, 0); + + init_var(&count); + init_var(&result); + init_var(&zerovar); + zero_var(&zerovar); + + + int8_to_numericvar((int64)1, &one); + set_var_from_var(&one, &count); + + /* + * Interate through N ... 1, multipling `count' by `fact' each time + */ + + while(1) { + if(!firstcall) { + free_var(&count); + init_var(&count); + set_var_from_var(&result,&count); + + free_var(&result); + init_var(&result); + + sub_var(&fact, &one, &result); + free_var(&fact); + init_var(&fact); + set_var_from_var(&result,&fact); + + ret = cmp_var(&fact, &zerovar); + if(ret == 0) { + break; + } + + free_var(&result); + init_var(&result); + } else { + firstcall = false; + } + mul_var(&count, &fact, &result, count.dscale + fact.dscale); + } + + res = make_result(&count); + + free_var(&count); + free_var(&fact); + free_var(&result); + free_var(&one); + free_var(&zerovar); + + PG_RETURN_NUMERIC(res); + } + /* Index: src/include/catalog/pg_operator.h =================================================================== RCS file: /usr/local/cvsroot/pgsql-server/src/include/catalog/pg_operator.h,v retrieving revision 1.118 diff -2 -c -r1.118 pg_operator.h *** src/include/catalog/pg_operator.h 27 Jun 2003 00:33:25 -0000 1.118 --- src/include/catalog/pg_operator.h 1 Aug 2003 14:03:54 -0000 *************** *** 123,126 **** --- 123,128 ---- 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 = 380 ( "!" PGNSP PGUID r f 1700 0 1700 0 0 0 0 0 0 numeric_fac - - )); + DATA(insert OID = 381 ( "!!" PGNSP PGUID r f 1700 0 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 )); Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /usr/local/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v retrieving revision 1.309 diff -2 -c -r1.309 pg_proc.h *** src/include/catalog/pg_proc.h 1 Jul 2003 00:04:38 -0000 1.309 --- src/include/catalog/pg_proc.h 1 Aug 2003 14:42:12 -0000 *************** *** 232,236 **** DATA(insert OID = 110 ( unknownout PGNSP PGUID 12 f f t f i 1 2275 "705" unknownout - _null_ )); DESCR("I/O"); ! DATA(insert OID = 112 ( text PGNSP PGUID 12 f f t f i 1 25 "23" int4_text - _null_ )); DESCR("convert int4 to text"); --- 232,236 ---- 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 "1700" 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"); *************** *** 1758,1761 **** --- 1758,1763 ---- DESCR("factorial"); DATA(insert OID = 1393 ( factorial PGNSP PGUID 12 f f t f i 1 20 "20" int8fac - _null_ )); + DESCR("factorial"); + DATA(insert OID = 1376 ( factorial PGNSP PGUID 12 f f t f i 1 1700 "1700" numeric_fac - _null_ )); DESCR("factorial"); DATA(insert OID = 1394 ( abs PGNSP PGUID 12 f f t f i 1 700 "700" float4abs - _null_ )); Index: src/include/utils/builtins.h =================================================================== RCS file: /usr/local/cvsroot/pgsql-server/src/include/utils/builtins.h,v retrieving revision 1.223 diff -2 -c -r1.223 builtins.h *** src/include/utils/builtins.h 27 Jun 2003 00:33:26 -0000 1.223 --- src/include/utils/builtins.h 31 Jul 2003 18:21:12 -0000 *************** *** 705,708 **** --- 705,709 ---- 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);

view thread (9+ messages)  latest in thread

Message-ID: <Pine.LNX.4.21.0308011020560.12997-200000@linuxworld.com.au>
Permalink:  ../Pine.LNX.4.21.0308011020560.12997-200000@linuxworld.com.au/
Also on:    postgresql.org/message-id/Pine.LNX.4.21.0308011020560.12997-200000@linuxworld.com.au

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-docs@postgresql.org
  Cc: swm@linuxworld.com.au, pgsql-patches@postgresql.org
  Subject: Re: Numeric version of factorial()
  In-Reply-To: <Pine.LNX.4.21.0308011020560.12997-200000@linuxworld.com.au>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox