4 * An exact numeric data type for the Postgres database system
8 * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.38 2001/03/22 03:59:52 momjian Exp $
19 #include <sys/types.h>
21 #include "utils/array.h"
22 #include "utils/builtins.h"
23 #include "utils/int8.h"
24 #include "utils/numeric.h"
27 * Uncomment the following to enable compilation of dump_numeric()
28 * and dump_var() and to get a dump of any result produced by make_result().
39 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
42 #define MAX(a,b) (((a)>(b)) ? (a) : (b))
53 * Note: the first digit of a NumericVar's value is assumed to be multiplied
54 * by 10 ** weight. Another way to say it is that there are weight+1 digits
55 * before the decimal point. It is possible to have weight < 0.
57 * The value represented by a NumericVar is determined by the sign, weight,
58 * ndigits, and digits[] array. The rscale and dscale are carried along,
59 * but they are just auxiliary information until rounding is done before
60 * final storage or display. (Scales are the number of digits wanted
61 * *after* the decimal point. Scales are always >= 0.)
63 * buf points at the physical start of the palloc'd digit buffer for the
64 * NumericVar. digits points at the first digit in actual use (the one
65 * with the specified weight). We normally leave an unused byte or two
66 * (preset to zeroes) between buf and digits, so that there is room to store
67 * a carry out of the top digit without special pushups. We just need to
68 * decrement digits (and increment weight) to make room for the carry digit.
70 * If buf is NULL then the digit buffer isn't actually palloc'd and should
71 * not be freed --- see the constants below for an example.
73 * NB: All the variable-level functions are written in a style that makes it
74 * possible to give one and the same variable as argument and destination.
75 * This is feasible because the digit buffer is separate from the variable.
78 typedef unsigned char NumericDigit;
80 typedef struct NumericVar
82 int ndigits; /* number of digits in digits[] - can be
84 int weight; /* weight of first digit */
85 int rscale; /* result scale */
86 int dscale; /* display scale */
87 int sign; /* NUMERIC_POS, NUMERIC_NEG, or
89 NumericDigit *buf; /* start of palloc'd space for digits[] */
90 NumericDigit *digits; /* decimal digits */
98 static int global_rscale = NUMERIC_MIN_RESULT_SCALE;
101 * Some preinitialized variables we need often
104 static NumericDigit const_zero_data[1] = {0};
105 static NumericVar const_zero =
106 {0, 0, 0, 0, NUMERIC_POS, NULL, const_zero_data};
108 static NumericDigit const_one_data[1] = {1};
109 static NumericVar const_one =
110 {1, 0, 0, 0, NUMERIC_POS, NULL, const_one_data};
112 static NumericDigit const_two_data[1] = {2};
113 static NumericVar const_two =
114 {1, 0, 0, 0, NUMERIC_POS, NULL, const_two_data};
116 static NumericVar const_nan =
117 {0, 0, 0, 0, NUMERIC_NAN, NULL, NULL};
127 static void dump_numeric(char *str, Numeric num);
128 static void dump_var(char *str, NumericVar *var);
131 #define dump_numeric(s,n)
132 #define dump_var(s,v)
135 #define digitbuf_alloc(size) ((NumericDigit *) palloc(size))
136 #define digitbuf_free(buf) \
142 #define init_var(v) memset(v,0,sizeof(NumericVar))
143 static void alloc_var(NumericVar *var, int ndigits);
144 static void free_var(NumericVar *var);
145 static void zero_var(NumericVar *var);
147 static void set_var_from_str(char *str, NumericVar *dest);
148 static void set_var_from_num(Numeric value, NumericVar *dest);
149 static void set_var_from_var(NumericVar *value, NumericVar *dest);
150 static char *get_str_from_var(NumericVar *var, int dscale);
152 static Numeric make_result(NumericVar *var);
154 static void apply_typmod(NumericVar *var, int32 typmod);
156 static int cmp_var(NumericVar *var1, NumericVar *var2);
157 static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
158 static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
159 static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
160 static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
161 static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
162 static void ceil_var(NumericVar *var, NumericVar *result);
163 static void floor_var(NumericVar *var, NumericVar *result);
165 static void sqrt_var(NumericVar *arg, NumericVar *result);
166 static void exp_var(NumericVar *arg, NumericVar *result);
167 static void ln_var(NumericVar *arg, NumericVar *result);
168 static void log_var(NumericVar *base, NumericVar *num, NumericVar *result);
169 static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result);
171 static int cmp_abs(NumericVar *var1, NumericVar *var2);
172 static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
173 static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
177 /* ----------------------------------------------------------------------
179 * Input-, output- and rounding-functions
181 * ----------------------------------------------------------------------
188 * Input function for numeric data type
192 numeric_in(PG_FUNCTION_ARGS)
194 char *str = PG_GETARG_CSTRING(0);
197 Oid typelem = PG_GETARG_OID(1);
200 int32 typmod = PG_GETARG_INT32(2);
208 if (strcmp(str, "NaN") == 0)
209 PG_RETURN_NUMERIC(make_result(&const_nan));
212 * Use set_var_from_str() to parse the input string
213 * and return it in the packed DB storage format
217 set_var_from_str(str, &value);
219 apply_typmod(&value, typmod);
221 res = make_result(&value);
224 PG_RETURN_NUMERIC(res);
231 * Output function for numeric data type
235 numeric_out(PG_FUNCTION_ARGS)
237 Numeric num = PG_GETARG_NUMERIC(0);
245 if (NUMERIC_IS_NAN(num))
246 PG_RETURN_CSTRING(pstrdup("NaN"));
249 * Get the number in the variable format.
251 * Even if we didn't need to change format, we'd still need to copy
252 * the value to have a modifiable copy for rounding. set_var_from_num()
253 * also guarantees there is extra digit space in case we produce a
254 * carry out from rounding.
258 set_var_from_num(num, &x);
260 str = get_str_from_var(&x, x.dscale);
264 PG_RETURN_CSTRING(str);
271 * This is a special function called by the Postgres database system
272 * before a value is stored in a tuples attribute. The precision and
273 * scale of the attribute have to be applied on the value.
277 numeric(PG_FUNCTION_ARGS)
279 Numeric num = PG_GETARG_NUMERIC(0);
280 int32 typmod = PG_GETARG_INT32(1);
292 if (NUMERIC_IS_NAN(num))
293 PG_RETURN_NUMERIC(make_result(&const_nan));
296 * If the value isn't a valid type modifier, simply return a
297 * copy of the input value
300 if (typmod < (int32) (VARHDRSZ))
302 new = (Numeric) palloc(num->varlen);
303 memcpy(new, num, num->varlen);
304 PG_RETURN_NUMERIC(new);
308 * Get the precision and scale out of the typmod value
311 tmp_typmod = typmod - VARHDRSZ;
312 precision = (tmp_typmod >> 16) & 0xffff;
313 scale = tmp_typmod & 0xffff;
314 maxweight = precision - scale;
317 * If the number is in bounds and due to the present result scale
318 * no rounding could be necessary, just make a copy of the input
319 * and modify its scale fields.
322 if (num->n_weight < maxweight && scale >= num->n_rscale)
324 new = (Numeric) palloc(num->varlen);
325 memcpy(new, num, num->varlen);
326 new->n_rscale = scale;
327 new->n_sign_dscale = NUMERIC_SIGN(new) |
328 ((uint16) scale & NUMERIC_DSCALE_MASK);
329 PG_RETURN_NUMERIC(new);
333 * We really need to fiddle with things - unpack the number into
334 * a variable and let apply_typmod() do it.
339 set_var_from_num(num, &var);
340 apply_typmod(&var, typmod);
341 new = make_result(&var);
345 PG_RETURN_NUMERIC(new);
349 /* ----------------------------------------------------------------------
351 * Sign manipulation, rounding and the like
353 * ----------------------------------------------------------------------
357 numeric_abs(PG_FUNCTION_ARGS)
359 Numeric num = PG_GETARG_NUMERIC(0);
366 if (NUMERIC_IS_NAN(num))
367 PG_RETURN_NUMERIC(make_result(&const_nan));
370 * Do it the easy way directly on the packed format
373 res = (Numeric) palloc(num->varlen);
374 memcpy(res, num, num->varlen);
376 res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
378 PG_RETURN_NUMERIC(res);
383 numeric_uminus(PG_FUNCTION_ARGS)
385 Numeric num = PG_GETARG_NUMERIC(0);
392 if (NUMERIC_IS_NAN(num))
393 PG_RETURN_NUMERIC(make_result(&const_nan));
396 * Do it the easy way directly on the packed format
399 res = (Numeric) palloc(num->varlen);
400 memcpy(res, num, num->varlen);
403 * The packed format is known to be totally zero digit trimmed
404 * always. So we can identify a ZERO by the fact that there
405 * are no digits at all. Do nothing to a zero.
408 if (num->varlen != NUMERIC_HDRSZ)
410 /* Else, flip the sign */
411 if (NUMERIC_SIGN(num) == NUMERIC_POS)
412 res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num);
414 res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
417 PG_RETURN_NUMERIC(res);
422 numeric_sign(PG_FUNCTION_ARGS)
424 Numeric num = PG_GETARG_NUMERIC(0);
432 if (NUMERIC_IS_NAN(num))
433 PG_RETURN_NUMERIC(make_result(&const_nan));
438 * The packed format is known to be totally zero digit trimmed
439 * always. So we can identify a ZERO by the fact that there
440 * are no digits at all.
443 if (num->varlen == NUMERIC_HDRSZ)
444 set_var_from_var(&const_zero, &result);
448 * And if there are some, we return a copy of ONE
449 * with the sign of our argument
452 set_var_from_var(&const_one, &result);
453 result.sign = NUMERIC_SIGN(num);
456 res = make_result(&result);
459 PG_RETURN_NUMERIC(res);
466 * Round a value to have 'scale' digits after the decimal point.
467 * We allow negative 'scale', implying rounding before the decimal
468 * point --- Oracle interprets rounding that way.
472 numeric_round(PG_FUNCTION_ARGS)
474 Numeric num = PG_GETARG_NUMERIC(0);
475 int32 scale = PG_GETARG_INT32(1);
484 if (NUMERIC_IS_NAN(num))
485 PG_RETURN_NUMERIC(make_result(&const_nan));
488 * Limit the scale value to avoid possible overflow in calculations below.
491 scale = MIN(NUMERIC_MAX_RESULT_SCALE,
492 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
495 * Unpack the argument and round it at the proper digit position
499 set_var_from_num(num, &arg);
501 i = arg.weight + scale + 1;
507 * If i = 0, the value loses all digits, but could round up if its
508 * first digit is more than 4. If i < 0 the result must be 0.
514 int carry = (arg.digits[i] > 4) ? 1 : 0;
520 carry += arg.digits[--i];
521 arg.digits[i] = carry % 10;
527 Assert(i == -1);/* better not have added more than 1 digit */
528 Assert(arg.digits > arg.buf);
537 * Set result's scale to something reasonable.
540 scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
545 * Return the rounded result
548 res = make_result(&arg);
551 PG_RETURN_NUMERIC(res);
558 * Truncate a value to have 'scale' digits after the decimal point.
559 * We allow negative 'scale', implying a truncation before the decimal
560 * point --- Oracle interprets truncation that way.
564 numeric_trunc(PG_FUNCTION_ARGS)
566 Numeric num = PG_GETARG_NUMERIC(0);
567 int32 scale = PG_GETARG_INT32(1);
575 if (NUMERIC_IS_NAN(num))
576 PG_RETURN_NUMERIC(make_result(&const_nan));
579 * Limit the scale value to avoid possible overflow in calculations below.
582 scale = MIN(NUMERIC_MAX_RESULT_SCALE,
583 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
586 * Unpack the argument and truncate it at the proper digit position
590 set_var_from_num(num, &arg);
592 arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));
595 * Set result's scale to something reasonable.
598 scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
603 * Return the truncated result
606 res = make_result(&arg);
609 PG_RETURN_NUMERIC(res);
616 * Return the smallest integer greater than or equal to the argument
620 numeric_ceil(PG_FUNCTION_ARGS)
622 Numeric num = PG_GETARG_NUMERIC(0);
626 if (NUMERIC_IS_NAN(num))
627 PG_RETURN_NUMERIC(make_result(&const_nan));
631 set_var_from_num(num, &result);
632 ceil_var(&result, &result);
636 res = make_result(&result);
639 PG_RETURN_NUMERIC(res);
646 * Return the largest integer equal to or less than the argument
650 numeric_floor(PG_FUNCTION_ARGS)
652 Numeric num = PG_GETARG_NUMERIC(0);
656 if (NUMERIC_IS_NAN(num))
657 PG_RETURN_NUMERIC(make_result(&const_nan));
661 set_var_from_num(num, &result);
662 floor_var(&result, &result);
666 res = make_result(&result);
669 PG_RETURN_NUMERIC(res);
673 /* ----------------------------------------------------------------------
675 * Comparison functions
677 * Note: btree indexes need these routines not to leak memory; therefore,
678 * be careful to free working copies of toasted datums. Most places don't
679 * need to be so careful.
680 * ----------------------------------------------------------------------
685 numeric_cmp(PG_FUNCTION_ARGS)
687 Numeric num1 = PG_GETARG_NUMERIC(0);
688 Numeric num2 = PG_GETARG_NUMERIC(1);
691 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
701 set_var_from_num(num1, &arg1);
702 set_var_from_num(num2, &arg2);
704 result = cmp_var(&arg1, &arg2);
710 PG_FREE_IF_COPY(num1, 0);
711 PG_FREE_IF_COPY(num2, 1);
713 PG_RETURN_INT32(result);
718 numeric_eq(PG_FUNCTION_ARGS)
720 Numeric num1 = PG_GETARG_NUMERIC(0);
721 Numeric num2 = PG_GETARG_NUMERIC(1);
724 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
734 set_var_from_num(num1, &arg1);
735 set_var_from_num(num2, &arg2);
737 result = cmp_var(&arg1, &arg2) == 0;
743 PG_FREE_IF_COPY(num1, 0);
744 PG_FREE_IF_COPY(num2, 1);
746 PG_RETURN_BOOL(result);
750 numeric_ne(PG_FUNCTION_ARGS)
752 Numeric num1 = PG_GETARG_NUMERIC(0);
753 Numeric num2 = PG_GETARG_NUMERIC(1);
756 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
766 set_var_from_num(num1, &arg1);
767 set_var_from_num(num2, &arg2);
769 result = cmp_var(&arg1, &arg2) != 0;
775 PG_FREE_IF_COPY(num1, 0);
776 PG_FREE_IF_COPY(num2, 1);
778 PG_RETURN_BOOL(result);
782 numeric_gt(PG_FUNCTION_ARGS)
784 Numeric num1 = PG_GETARG_NUMERIC(0);
785 Numeric num2 = PG_GETARG_NUMERIC(1);
788 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
798 set_var_from_num(num1, &arg1);
799 set_var_from_num(num2, &arg2);
801 result = cmp_var(&arg1, &arg2) > 0;
807 PG_FREE_IF_COPY(num1, 0);
808 PG_FREE_IF_COPY(num2, 1);
810 PG_RETURN_BOOL(result);
814 numeric_ge(PG_FUNCTION_ARGS)
816 Numeric num1 = PG_GETARG_NUMERIC(0);
817 Numeric num2 = PG_GETARG_NUMERIC(1);
820 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
830 set_var_from_num(num1, &arg1);
831 set_var_from_num(num2, &arg2);
833 result = cmp_var(&arg1, &arg2) >= 0;
839 PG_FREE_IF_COPY(num1, 0);
840 PG_FREE_IF_COPY(num2, 1);
842 PG_RETURN_BOOL(result);
846 numeric_lt(PG_FUNCTION_ARGS)
848 Numeric num1 = PG_GETARG_NUMERIC(0);
849 Numeric num2 = PG_GETARG_NUMERIC(1);
852 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
862 set_var_from_num(num1, &arg1);
863 set_var_from_num(num2, &arg2);
865 result = cmp_var(&arg1, &arg2) < 0;
871 PG_FREE_IF_COPY(num1, 0);
872 PG_FREE_IF_COPY(num2, 1);
874 PG_RETURN_BOOL(result);
878 numeric_le(PG_FUNCTION_ARGS)
880 Numeric num1 = PG_GETARG_NUMERIC(0);
881 Numeric num2 = PG_GETARG_NUMERIC(1);
884 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
894 set_var_from_num(num1, &arg1);
895 set_var_from_num(num2, &arg2);
897 result = cmp_var(&arg1, &arg2) <= 0;
903 PG_FREE_IF_COPY(num1, 0);
904 PG_FREE_IF_COPY(num2, 1);
906 PG_RETURN_BOOL(result);
910 /* ----------------------------------------------------------------------
912 * Arithmetic base functions
914 * ----------------------------------------------------------------------
925 numeric_add(PG_FUNCTION_ARGS)
927 Numeric num1 = PG_GETARG_NUMERIC(0);
928 Numeric num2 = PG_GETARG_NUMERIC(1);
938 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
939 PG_RETURN_NUMERIC(make_result(&const_nan));
942 * Unpack the values, let add_var() compute the result
943 * and return it. The internals of add_var() will automatically
944 * set the correct result and display scales in the result.
951 set_var_from_num(num1, &arg1);
952 set_var_from_num(num2, &arg2);
954 add_var(&arg1, &arg2, &result);
955 res = make_result(&result);
961 PG_RETURN_NUMERIC(res);
968 * Subtract one numeric from another
972 numeric_sub(PG_FUNCTION_ARGS)
974 Numeric num1 = PG_GETARG_NUMERIC(0);
975 Numeric num2 = PG_GETARG_NUMERIC(1);
985 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
986 PG_RETURN_NUMERIC(make_result(&const_nan));
989 * Unpack the two arguments, let sub_var() compute the
990 * result and return it.
997 set_var_from_num(num1, &arg1);
998 set_var_from_num(num2, &arg2);
1000 sub_var(&arg1, &arg2, &result);
1001 res = make_result(&result);
1007 PG_RETURN_NUMERIC(res);
1014 * Calculate the product of two numerics
1018 numeric_mul(PG_FUNCTION_ARGS)
1020 Numeric num1 = PG_GETARG_NUMERIC(0);
1021 Numeric num2 = PG_GETARG_NUMERIC(1);
1031 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1032 PG_RETURN_NUMERIC(make_result(&const_nan));
1035 * Unpack the arguments, let mul_var() compute the result
1036 * and return it. Unlike add_var() and sub_var(), mul_var()
1037 * will round the result to the scale stored in global_rscale.
1038 * In the case of numeric_mul(), which is invoked for the *
1039 * operator on numerics, we set it to the exact representation
1040 * for the product (rscale = sum(rscale of arg1, rscale of arg2)
1041 * and the same for the dscale).
1048 set_var_from_num(num1, &arg1);
1049 set_var_from_num(num2, &arg2);
1051 global_rscale = arg1.rscale + arg2.rscale;
1053 mul_var(&arg1, &arg2, &result);
1055 result.dscale = arg1.dscale + arg2.dscale;
1057 res = make_result(&result);
1063 PG_RETURN_NUMERIC(res);
1070 * Divide one numeric into another
1074 numeric_div(PG_FUNCTION_ARGS)
1076 Numeric num1 = PG_GETARG_NUMERIC(0);
1077 Numeric num2 = PG_GETARG_NUMERIC(1);
1088 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1089 PG_RETURN_NUMERIC(make_result(&const_nan));
1092 * Unpack the arguments
1099 set_var_from_num(num1, &arg1);
1100 set_var_from_num(num2, &arg2);
1103 * The result scale of a division isn't specified in any
1104 * SQL standard. For Postgres it is the following (where
1105 * SR, DR are the result- and display-scales of the returned
1106 * value, S1, D1, S2 and D2 are the scales of the two arguments,
1107 * The minimum and maximum scales are compile time options from
1110 * DR = MIN(MAX(D1 + D2, MIN_DISPLAY_SCALE), MAX_DISPLAY_SCALE)
1111 * SR = MIN(MAX(MAX(S1 + S2, MIN_RESULT_SCALE), DR + 4), MAX_RESULT_SCALE)
1113 * By default, any result is computed with a minimum of 34 digits
1114 * after the decimal point or at least with 4 digits more than
1118 res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1119 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1120 global_rscale = MAX(arg1.rscale + arg2.rscale,
1121 NUMERIC_MIN_RESULT_SCALE);
1122 global_rscale = MAX(global_rscale, res_dscale + 4);
1123 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1126 * Do the divide, set the display scale and return the result
1129 div_var(&arg1, &arg2, &result);
1131 result.dscale = res_dscale;
1133 res = make_result(&result);
1139 PG_RETURN_NUMERIC(res);
1146 * Calculate the modulo of two numerics
1150 numeric_mod(PG_FUNCTION_ARGS)
1152 Numeric num1 = PG_GETARG_NUMERIC(0);
1153 Numeric num2 = PG_GETARG_NUMERIC(1);
1159 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1160 PG_RETURN_NUMERIC(make_result(&const_nan));
1166 set_var_from_num(num1, &arg1);
1167 set_var_from_num(num2, &arg2);
1169 mod_var(&arg1, &arg2, &result);
1171 result.dscale = result.rscale;
1172 res = make_result(&result);
1178 PG_RETURN_NUMERIC(res);
1185 * Increment a number by one
1189 numeric_inc(PG_FUNCTION_ARGS)
1191 Numeric num = PG_GETARG_NUMERIC(0);
1199 if (NUMERIC_IS_NAN(num))
1200 PG_RETURN_NUMERIC(make_result(&const_nan));
1203 * Compute the result and return it
1208 set_var_from_num(num, &arg);
1210 add_var(&arg, &const_one, &arg);
1211 res = make_result(&arg);
1215 PG_RETURN_NUMERIC(res);
1220 * numeric_smaller() -
1222 * Return the smaller of two numbers
1226 numeric_smaller(PG_FUNCTION_ARGS)
1228 Numeric num1 = PG_GETARG_NUMERIC(0);
1229 Numeric num2 = PG_GETARG_NUMERIC(1);
1238 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1239 PG_RETURN_NUMERIC(make_result(&const_nan));
1242 * Unpack the values, and decide which is the smaller one
1248 set_var_from_num(num1, &arg1);
1249 set_var_from_num(num2, &arg2);
1251 if (cmp_var(&arg1, &arg2) <= 0)
1252 res = make_result(&arg1);
1254 res = make_result(&arg2);
1259 PG_RETURN_NUMERIC(res);
1264 * numeric_larger() -
1266 * Return the larger of two numbers
1270 numeric_larger(PG_FUNCTION_ARGS)
1272 Numeric num1 = PG_GETARG_NUMERIC(0);
1273 Numeric num2 = PG_GETARG_NUMERIC(1);
1282 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1283 PG_RETURN_NUMERIC(make_result(&const_nan));
1286 * Unpack the values, and decide which is the larger one
1292 set_var_from_num(num1, &arg1);
1293 set_var_from_num(num2, &arg2);
1295 if (cmp_var(&arg1, &arg2) >= 0)
1296 res = make_result(&arg1);
1298 res = make_result(&arg2);
1303 PG_RETURN_NUMERIC(res);
1307 /* ----------------------------------------------------------------------
1309 * Complex math functions
1311 * ----------------------------------------------------------------------
1318 * Compute the square root of a numeric.
1322 numeric_sqrt(PG_FUNCTION_ARGS)
1324 Numeric num = PG_GETARG_NUMERIC(0);
1334 if (NUMERIC_IS_NAN(num))
1335 PG_RETURN_NUMERIC(make_result(&const_nan));
1338 * Unpack the argument, determine the scales like for divide,
1339 * let sqrt_var() do the calculation and return the result.
1345 set_var_from_num(num, &arg);
1347 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1348 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1349 global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1350 global_rscale = MAX(global_rscale, res_dscale + 4);
1351 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1353 sqrt_var(&arg, &result);
1355 result.dscale = res_dscale;
1357 res = make_result(&result);
1362 PG_RETURN_NUMERIC(res);
1369 * Raise e to the power of x
1373 numeric_exp(PG_FUNCTION_ARGS)
1375 Numeric num = PG_GETARG_NUMERIC(0);
1385 if (NUMERIC_IS_NAN(num))
1386 PG_RETURN_NUMERIC(make_result(&const_nan));
1389 * Same procedure like for sqrt().
1394 set_var_from_num(num, &arg);
1396 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1397 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1398 global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1399 global_rscale = MAX(global_rscale, res_dscale + 4);
1400 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1402 exp_var(&arg, &result);
1404 result.dscale = res_dscale;
1406 res = make_result(&result);
1411 PG_RETURN_NUMERIC(res);
1418 * Compute the natural logarithm of x
1422 numeric_ln(PG_FUNCTION_ARGS)
1424 Numeric num = PG_GETARG_NUMERIC(0);
1434 if (NUMERIC_IS_NAN(num))
1435 PG_RETURN_NUMERIC(make_result(&const_nan));
1438 * Same procedure like for sqrt()
1443 set_var_from_num(num, &arg);
1445 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1446 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1447 global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1448 global_rscale = MAX(global_rscale, res_dscale + 4);
1449 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1451 ln_var(&arg, &result);
1453 result.dscale = res_dscale;
1455 res = make_result(&result);
1460 PG_RETURN_NUMERIC(res);
1467 * Compute the logarithm of x in a given base
1471 numeric_log(PG_FUNCTION_ARGS)
1473 Numeric num1 = PG_GETARG_NUMERIC(0);
1474 Numeric num2 = PG_GETARG_NUMERIC(1);
1485 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1486 PG_RETURN_NUMERIC(make_result(&const_nan));
1489 * Initialize things and calculate scales
1495 set_var_from_num(num1, &arg1);
1496 set_var_from_num(num2, &arg2);
1498 res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1499 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1500 global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1501 global_rscale = MAX(global_rscale, res_dscale + 4);
1502 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1505 * Call log_var() to compute and return the result
1508 log_var(&arg1, &arg2, &result);
1510 result.dscale = res_dscale;
1512 res = make_result(&result);
1518 PG_RETURN_NUMERIC(res);
1525 * Raise m to the power of x
1529 numeric_power(PG_FUNCTION_ARGS)
1531 Numeric num1 = PG_GETARG_NUMERIC(0);
1532 Numeric num2 = PG_GETARG_NUMERIC(1);
1543 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1544 PG_RETURN_NUMERIC(make_result(&const_nan));
1547 * Initialize things and calculate scales
1553 set_var_from_num(num1, &arg1);
1554 set_var_from_num(num2, &arg2);
1556 res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1557 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1558 global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1559 global_rscale = MAX(global_rscale, res_dscale + 4);
1560 global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1563 * Call log_var() to compute and return the result
1566 power_var(&arg1, &arg2, &result);
1568 result.dscale = res_dscale;
1570 res = make_result(&result);
1576 PG_RETURN_NUMERIC(res);
1580 /* ----------------------------------------------------------------------
1582 * Type conversion functions
1584 * ----------------------------------------------------------------------
1589 int4_numeric(PG_FUNCTION_ARGS)
1591 int32 val = PG_GETARG_INT32(0);
1598 tmp = DatumGetCString(DirectFunctionCall1(int4out,
1599 Int32GetDatum(val)));
1600 set_var_from_str(tmp, &result);
1601 res = make_result(&result);
1606 PG_RETURN_NUMERIC(res);
1611 numeric_int4(PG_FUNCTION_ARGS)
1613 Numeric num = PG_GETARG_NUMERIC(0);
1618 /* XXX would it be better to return NULL? */
1619 if (NUMERIC_IS_NAN(num))
1620 elog(ERROR, "Cannot convert NaN to int4");
1623 * Get the number in the variable format so we can round to integer.
1627 set_var_from_num(num, &x);
1629 str = get_str_from_var(&x, 0); /* dscale = 0 produces rounding */
1633 result = DirectFunctionCall1(int4in, CStringGetDatum(str));
1636 PG_RETURN_DATUM(result);
1641 int8_numeric(PG_FUNCTION_ARGS)
1643 Datum val = PG_GETARG_DATUM(0);
1650 tmp = DatumGetCString(DirectFunctionCall1(int8out, val));
1651 set_var_from_str(tmp, &result);
1652 res = make_result(&result);
1657 PG_RETURN_NUMERIC(res);
1662 numeric_int8(PG_FUNCTION_ARGS)
1664 Numeric num = PG_GETARG_NUMERIC(0);
1669 /* XXX would it be better to return NULL? */
1670 if (NUMERIC_IS_NAN(num))
1671 elog(ERROR, "Cannot convert NaN to int8");
1674 * Get the number in the variable format so we can round to integer.
1678 set_var_from_num(num, &x);
1680 str = get_str_from_var(&x, 0); /* dscale = 0 produces rounding */
1684 result = DirectFunctionCall1(int8in, CStringGetDatum(str));
1687 PG_RETURN_DATUM(result);
1692 int2_numeric(PG_FUNCTION_ARGS)
1694 int16 val = PG_GETARG_INT16(0);
1701 tmp = DatumGetCString(DirectFunctionCall1(int2out,
1702 Int16GetDatum(val)));
1703 set_var_from_str(tmp, &result);
1704 res = make_result(&result);
1709 PG_RETURN_NUMERIC(res);
1714 numeric_int2(PG_FUNCTION_ARGS)
1716 Numeric num = PG_GETARG_NUMERIC(0);
1721 if (NUMERIC_IS_NAN(num))
1722 elog(ERROR, "Cannot convert NaN to int2");
1725 * Get the number in the variable format so we can round to integer.
1729 set_var_from_num(num, &x);
1731 str = get_str_from_var(&x, 0); /* dscale = 0 produces rounding */
1735 result = DirectFunctionCall1(int2in, CStringGetDatum(str));
1743 float8_numeric(PG_FUNCTION_ARGS)
1745 float8 val = PG_GETARG_FLOAT8(0);
1748 char buf[DBL_DIG + 100];
1751 PG_RETURN_NUMERIC(make_result(&const_nan));
1753 sprintf(buf, "%.*g", DBL_DIG, val);
1757 set_var_from_str(buf, &result);
1758 res = make_result(&result);
1762 PG_RETURN_NUMERIC(res);
1767 numeric_float8(PG_FUNCTION_ARGS)
1769 Numeric num = PG_GETARG_NUMERIC(0);
1773 if (NUMERIC_IS_NAN(num))
1774 PG_RETURN_FLOAT8(NAN);
1776 tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
1777 NumericGetDatum(num)));
1779 result = DirectFunctionCall1(float8in, CStringGetDatum(tmp));
1783 PG_RETURN_DATUM(result);
1788 float4_numeric(PG_FUNCTION_ARGS)
1790 float4 val = PG_GETARG_FLOAT4(0);
1793 char buf[FLT_DIG + 100];
1796 PG_RETURN_NUMERIC(make_result(&const_nan));
1798 sprintf(buf, "%.*g", FLT_DIG, val);
1802 set_var_from_str(buf, &result);
1803 res = make_result(&result);
1807 PG_RETURN_NUMERIC(res);
1812 numeric_float4(PG_FUNCTION_ARGS)
1814 Numeric num = PG_GETARG_NUMERIC(0);
1818 if (NUMERIC_IS_NAN(num))
1819 PG_RETURN_FLOAT4((float4) NAN);
1821 tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
1822 NumericGetDatum(num)));
1824 result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));
1828 PG_RETURN_DATUM(result);
1832 /* ----------------------------------------------------------------------
1834 * Aggregate functions
1836 * The transition datatype for all these aggregates is a 3-element array
1837 * of Numeric, holding the values N, sum(X), sum(X*X) in that order.
1839 * We represent N as a numeric mainly to avoid having to build a special
1840 * datatype; it's unlikely it'd overflow an int4, but ...
1842 * ----------------------------------------------------------------------
1846 do_numeric_accum(ArrayType *transarray, Numeric newval)
1855 /* We assume the input is array of numeric */
1856 deconstruct_array(transarray,
1858 &transdatums, &ndatums);
1860 elog(ERROR, "do_numeric_accum: expected 3-element numeric array");
1862 sumX = transdatums[1];
1863 sumX2 = transdatums[2];
1865 N = DirectFunctionCall1(numeric_inc, N);
1866 sumX = DirectFunctionCall2(numeric_add, sumX,
1867 NumericGetDatum(newval));
1868 sumX2 = DirectFunctionCall2(numeric_add, sumX2,
1869 DirectFunctionCall2(numeric_mul,
1870 NumericGetDatum(newval),
1871 NumericGetDatum(newval)));
1874 transdatums[1] = sumX;
1875 transdatums[2] = sumX2;
1877 result = construct_array(transdatums, 3,
1884 numeric_accum(PG_FUNCTION_ARGS)
1886 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1887 Numeric newval = PG_GETARG_NUMERIC(1);
1889 PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1893 * Integer data types all use Numeric accumulators to share code and
1894 * avoid risk of overflow.
1898 int2_accum(PG_FUNCTION_ARGS)
1900 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1901 Datum newval2 = PG_GETARG_DATUM(1);
1904 newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
1906 PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1910 int4_accum(PG_FUNCTION_ARGS)
1912 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1913 Datum newval4 = PG_GETARG_DATUM(1);
1916 newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
1918 PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1922 int8_accum(PG_FUNCTION_ARGS)
1924 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1925 Datum newval8 = PG_GETARG_DATUM(1);
1928 newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
1930 PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1934 numeric_avg(PG_FUNCTION_ARGS)
1936 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1942 /* We assume the input is array of numeric */
1943 deconstruct_array(transarray,
1945 &transdatums, &ndatums);
1947 elog(ERROR, "numeric_avg: expected 3-element numeric array");
1948 N = DatumGetNumeric(transdatums[0]);
1949 sumX = DatumGetNumeric(transdatums[1]);
1952 /* SQL92 defines AVG of no values to be NULL */
1953 /* N is zero iff no digits (cf. numeric_uminus) */
1954 if (N->varlen == NUMERIC_HDRSZ)
1957 PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
1958 NumericGetDatum(sumX),
1959 NumericGetDatum(N)));
1963 numeric_variance(PG_FUNCTION_ARGS)
1965 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1977 /* We assume the input is array of numeric */
1978 deconstruct_array(transarray,
1980 &transdatums, &ndatums);
1982 elog(ERROR, "numeric_variance: expected 3-element numeric array");
1983 N = DatumGetNumeric(transdatums[0]);
1984 sumX = DatumGetNumeric(transdatums[1]);
1985 sumX2 = DatumGetNumeric(transdatums[2]);
1987 if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
1988 PG_RETURN_NUMERIC(make_result(&const_nan));
1990 /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
1991 /* N is zero iff no digits (cf. numeric_uminus) */
1992 if (N->varlen == NUMERIC_HDRSZ)
1996 set_var_from_num(N, &vN);
1998 init_var(&vNminus1);
1999 sub_var(&vN, &const_one, &vNminus1);
2001 if (cmp_var(&vNminus1, &const_zero) <= 0)
2004 free_var(&vNminus1);
2005 PG_RETURN_NUMERIC(make_result(&const_zero));
2009 set_var_from_num(sumX, &vsumX);
2011 set_var_from_num(sumX2, &vsumX2);
2013 mul_var(&vsumX, &vsumX, &vsumX); /* now vsumX contains sumX * sumX */
2014 mul_var(&vN, &vsumX2, &vsumX2); /* now vsumX2 contains N * sumX2 */
2015 sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
2016 mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
2017 div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
2019 res = make_result(&vsumX);
2022 free_var(&vNminus1);
2026 PG_RETURN_NUMERIC(res);
2030 numeric_stddev(PG_FUNCTION_ARGS)
2032 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2044 /* We assume the input is array of numeric */
2045 deconstruct_array(transarray,
2047 &transdatums, &ndatums);
2049 elog(ERROR, "numeric_stddev: expected 3-element numeric array");
2050 N = DatumGetNumeric(transdatums[0]);
2051 sumX = DatumGetNumeric(transdatums[1]);
2052 sumX2 = DatumGetNumeric(transdatums[2]);
2054 if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
2055 PG_RETURN_NUMERIC(make_result(&const_nan));
2057 /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
2058 /* N is zero iff no digits (cf. numeric_uminus) */
2059 if (N->varlen == NUMERIC_HDRSZ)
2063 set_var_from_num(N, &vN);
2065 init_var(&vNminus1);
2066 sub_var(&vN, &const_one, &vNminus1);
2068 if (cmp_var(&vNminus1, &const_zero) <= 0)
2071 free_var(&vNminus1);
2072 PG_RETURN_NUMERIC(make_result(&const_zero));
2076 set_var_from_num(sumX, &vsumX);
2078 set_var_from_num(sumX2, &vsumX2);
2080 mul_var(&vsumX, &vsumX, &vsumX); /* now vsumX contains sumX * sumX */
2081 mul_var(&vN, &vsumX2, &vsumX2); /* now vsumX2 contains N * sumX2 */
2082 sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
2083 mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
2084 div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
2085 sqrt_var(&vsumX, &vsumX); /* stddev */
2087 res = make_result(&vsumX);
2090 free_var(&vNminus1);
2094 PG_RETURN_NUMERIC(res);
2099 * SUM transition functions for integer datatypes.
2101 * We use a Numeric accumulator to avoid overflow. Because SQL92 defines
2102 * the SUM() of no values to be NULL, not zero, the initial condition of
2103 * the transition data value needs to be NULL. This means we can't rely
2104 * on ExecAgg to automatically insert the first non-null data value into
2105 * the transition data: it doesn't know how to do the type conversion.
2106 * The upshot is that these routines have to be marked non-strict and
2107 * handle substitution of the first non-null input themselves.
2111 int2_sum(PG_FUNCTION_ARGS)
2116 if (PG_ARGISNULL(0))
2118 /* No non-null input seen so far... */
2119 if (PG_ARGISNULL(1))
2120 PG_RETURN_NULL(); /* still no non-null */
2121 /* This is the first non-null input. */
2122 newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1));
2123 PG_RETURN_DATUM(newval);
2126 oldsum = PG_GETARG_NUMERIC(0);
2128 /* Leave sum unchanged if new input is null. */
2129 if (PG_ARGISNULL(1))
2130 PG_RETURN_NUMERIC(oldsum);
2132 /* OK to do the addition. */
2133 newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1));
2135 PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
2136 NumericGetDatum(oldsum), newval));
2140 int4_sum(PG_FUNCTION_ARGS)
2145 if (PG_ARGISNULL(0))
2147 /* No non-null input seen so far... */
2148 if (PG_ARGISNULL(1))
2149 PG_RETURN_NULL(); /* still no non-null */
2150 /* This is the first non-null input. */
2151 newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1));
2152 PG_RETURN_DATUM(newval);
2155 oldsum = PG_GETARG_NUMERIC(0);
2157 /* Leave sum unchanged if new input is null. */
2158 if (PG_ARGISNULL(1))
2159 PG_RETURN_NUMERIC(oldsum);
2161 /* OK to do the addition. */
2162 newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1));
2164 PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
2165 NumericGetDatum(oldsum), newval));
2169 int8_sum(PG_FUNCTION_ARGS)
2174 if (PG_ARGISNULL(0))
2176 /* No non-null input seen so far... */
2177 if (PG_ARGISNULL(1))
2178 PG_RETURN_NULL(); /* still no non-null */
2179 /* This is the first non-null input. */
2180 newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
2181 PG_RETURN_DATUM(newval);
2184 oldsum = PG_GETARG_NUMERIC(0);
2186 /* Leave sum unchanged if new input is null. */
2187 if (PG_ARGISNULL(1))
2188 PG_RETURN_NUMERIC(oldsum);
2190 /* OK to do the addition. */
2191 newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
2193 PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
2194 NumericGetDatum(oldsum), newval));
2198 /* ----------------------------------------------------------------------
2200 * Local functions follow
2202 * ----------------------------------------------------------------------
2206 #ifdef NUMERIC_DEBUG
2209 * dump_numeric() - Dump a value in the db storage format for debugging
2213 dump_numeric(char *str, Numeric num)
2217 printf("%s: NUMERIC w=%d r=%d d=%d ", str, num->n_weight, num->n_rscale,
2218 NUMERIC_DSCALE(num));
2219 switch (NUMERIC_SIGN(num))
2231 printf("SIGN=0x%x", NUMERIC_SIGN(num));
2235 for (i = 0; i < num->varlen - NUMERIC_HDRSZ; i++)
2236 printf(" %d %d", (num->n_data[i] >> 4) & 0x0f, num->n_data[i] & 0x0f);
2242 * dump_var() - Dump a value in the variable format for debugging
2246 dump_var(char *str, NumericVar *var)
2250 printf("%s: VAR w=%d r=%d d=%d ", str, var->weight, var->rscale,
2264 printf("SIGN=0x%x", var->sign);
2268 for (i = 0; i < var->ndigits; i++)
2269 printf(" %d", var->digits[i]);
2274 #endif /* NUMERIC_DEBUG */
2280 * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
2284 alloc_var(NumericVar *var, int ndigits)
2286 digitbuf_free(var->buf);
2287 var->buf = digitbuf_alloc(ndigits + 1);
2289 var->digits = var->buf + 1;
2290 var->ndigits = ndigits;
2297 * Return the digit buffer of a variable to the free pool
2301 free_var(NumericVar *var)
2303 digitbuf_free(var->buf);
2306 var->sign = NUMERIC_NAN;
2313 * Set a variable to ZERO.
2314 * Note: rscale and dscale are not touched.
2318 zero_var(NumericVar *var)
2320 digitbuf_free(var->buf);
2324 var->weight = 0; /* by convention; doesn't really matter */
2325 var->sign = NUMERIC_POS; /* anything but NAN... */
2330 * set_var_from_str()
2332 * Parse a string and put the number into a variable
2336 set_var_from_str(char *str, NumericVar *dest)
2339 bool have_dp = FALSE;
2344 if (!isspace((unsigned char) *cp))
2349 alloc_var(dest, strlen(cp));
2352 dest->sign = NUMERIC_POS;
2357 dest->sign = NUMERIC_POS;
2362 dest->sign = NUMERIC_NEG;
2373 if (!isdigit((unsigned char) *cp))
2374 elog(ERROR, "Bad numeric input format '%s'", str);
2378 if (isdigit((unsigned char) *cp))
2380 dest->digits[i++] = *cp++ - '0';
2386 else if (*cp == '.')
2389 elog(ERROR, "Bad numeric input format '%s'", str);
2398 /* Handle exponent, if any */
2399 if (*cp == 'e' || *cp == 'E')
2405 exponent = strtol(cp, &endptr, 10);
2407 elog(ERROR, "Bad numeric input format '%s'", str);
2409 if (exponent > NUMERIC_MAX_PRECISION ||
2410 exponent < -NUMERIC_MAX_PRECISION)
2411 elog(ERROR, "Bad numeric input format '%s'", str);
2412 dest->weight += (int) exponent;
2413 dest->dscale -= (int) exponent;
2414 if (dest->dscale < 0)
2418 /* Should be nothing left but spaces */
2421 if (!isspace((unsigned char) *cp))
2422 elog(ERROR, "Bad numeric input format '%s'", str);
2426 /* Strip any leading zeroes */
2427 while (dest->ndigits > 0 && *(dest->digits) == 0)
2433 if (dest->ndigits == 0)
2436 dest->rscale = dest->dscale;
2441 * set_var_from_num() -
2443 * Parse back the packed db format into a variable
2447 set_var_from_num(Numeric num, NumericVar *dest)
2449 NumericDigit *digit;
2453 n = num->varlen - NUMERIC_HDRSZ; /* number of digit-pairs in packed
2456 alloc_var(dest, n * 2);
2458 dest->weight = num->n_weight;
2459 dest->rscale = num->n_rscale;
2460 dest->dscale = NUMERIC_DSCALE(num);
2461 dest->sign = NUMERIC_SIGN(num);
2463 digit = dest->digits;
2465 for (i = 0; i < n; i++)
2467 unsigned char digitpair = num->n_data[i];
2469 *digit++ = (digitpair >> 4) & 0x0f;
2470 *digit++ = digitpair & 0x0f;
2476 * set_var_from_var() -
2478 * Copy one variable into another
2482 set_var_from_var(NumericVar *value, NumericVar *dest)
2484 NumericDigit *newbuf;
2486 newbuf = digitbuf_alloc(value->ndigits + 1);
2487 newbuf[0] = 0; /* spare digit for rounding */
2488 memcpy(newbuf + 1, value->digits, value->ndigits);
2490 digitbuf_free(dest->buf);
2492 memcpy(dest, value, sizeof(NumericVar));
2494 dest->digits = newbuf + 1;
2499 * get_str_from_var() -
2501 * Convert a var to text representation (guts of numeric_out).
2502 * CAUTION: var's contents may be modified by rounding!
2503 * Caller must have checked for NaN case.
2504 * Returns a palloc'd string.
2508 get_str_from_var(NumericVar *var, int dscale)
2516 * Check if we must round up before printing the value and
2520 i = dscale + var->weight + 1;
2521 if (i >= 0 && var->ndigits > i)
2523 int carry = (var->digits[i] > 4) ? 1 : 0;
2529 carry += var->digits[--i];
2530 var->digits[i] = carry % 10;
2536 Assert(i == -1); /* better not have added more than 1 digit */
2537 Assert(var->digits > var->buf);
2544 var->ndigits = MAX(0, MIN(i, var->ndigits));
2547 * Allocate space for the result
2550 str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4);
2554 * Output a dash for negative values
2557 if (var->sign == NUMERIC_NEG)
2561 * Output all digits before the decimal point
2564 i = MAX(var->weight, 0);
2569 if (i <= var->weight && d < var->ndigits)
2570 *cp++ = var->digits[d++] + '0';
2577 * If requested, output a decimal point and all the digits
2584 while (i >= -dscale)
2586 if (i <= var->weight && d < var->ndigits)
2587 *cp++ = var->digits[d++] + '0';
2595 * terminate the string and return it
2606 * Create the packed db numeric format in palloc()'d memory from
2607 * a variable. The var's rscale determines the number of digits kept.
2611 make_result(NumericVar *var)
2614 NumericDigit *digit = var->digits;
2615 int weight = var->weight;
2616 int sign = var->sign;
2621 if (sign == NUMERIC_NAN)
2623 result = (Numeric) palloc(NUMERIC_HDRSZ);
2625 result->varlen = NUMERIC_HDRSZ;
2626 result->n_weight = 0;
2627 result->n_rscale = 0;
2628 result->n_sign_dscale = NUMERIC_NAN;
2630 dump_numeric("make_result()", result);
2634 n = MAX(0, MIN(var->ndigits, var->weight + var->rscale + 1));
2636 /* truncate leading zeroes */
2637 while (n > 0 && *digit == 0)
2643 /* truncate trailing zeroes */
2644 while (n > 0 && digit[n - 1] == 0)
2647 /* If zero result, force to weight=0 and positive sign */
2654 result = (Numeric) palloc(NUMERIC_HDRSZ + (n + 1) / 2);
2655 result->varlen = NUMERIC_HDRSZ + (n + 1) / 2;
2656 result->n_weight = weight;
2657 result->n_rscale = var->rscale;
2658 result->n_sign_dscale = sign |
2659 ((uint16) var->dscale & NUMERIC_DSCALE_MASK);
2665 unsigned char digitpair = digit[j++] << 4;
2668 digitpair |= digit[j++];
2669 result->n_data[i++] = digitpair;
2672 dump_numeric("make_result()", result);
2680 * Do bounds checking and rounding according to the attributes
2685 apply_typmod(NumericVar *var, int32 typmod)
2692 /* Do nothing if we have a default typmod (-1) */
2693 if (typmod < (int32) (VARHDRSZ))
2697 precision = (typmod >> 16) & 0xffff;
2698 scale = typmod & 0xffff;
2699 maxweight = precision - scale;
2701 /* Round to target scale */
2702 i = scale + var->weight + 1;
2703 if (i >= 0 && var->ndigits > i)
2705 int carry = (var->digits[i] > 4) ? 1 : 0;
2711 carry += var->digits[--i];
2712 var->digits[i] = carry % 10;
2718 Assert(i == -1); /* better not have added more than 1 digit */
2719 Assert(var->digits > var->buf);
2726 var->ndigits = MAX(0, MIN(i, var->ndigits));
2729 * Check for overflow - note we can't do this before rounding,
2730 * because rounding could raise the weight. Also note that the
2731 * var's weight could be inflated by leading zeroes, which will
2732 * be stripped before storage but perhaps might not have been yet.
2733 * In any case, we must recognize a true zero, whose weight doesn't
2737 if (var->weight >= maxweight)
2739 /* Determine true weight; and check for all-zero result */
2740 int tweight = var->weight;
2742 for (i = 0; i < var->ndigits; i++)
2749 if (tweight >= maxweight && i < var->ndigits)
2750 elog(ERROR, "overflow on numeric "
2751 "ABS(value) >= 10^%d for field with precision %d scale %d",
2752 tweight, precision, scale);
2755 var->rscale = scale;
2756 var->dscale = scale;
2763 * Compare two values on variable level
2767 cmp_var(NumericVar *var1, NumericVar *var2)
2769 if (var1->ndigits == 0)
2771 if (var2->ndigits == 0)
2773 if (var2->sign == NUMERIC_NEG)
2777 if (var2->ndigits == 0)
2779 if (var1->sign == NUMERIC_POS)
2784 if (var1->sign == NUMERIC_POS)
2786 if (var2->sign == NUMERIC_NEG)
2788 return cmp_abs(var1, var2);
2791 if (var2->sign == NUMERIC_POS)
2794 return cmp_abs(var2, var1);
2801 * Full version of add functionality on variable level (handling signs).
2802 * result might point to one of the operands too without danger.
2806 add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
2809 * Decide on the signs of the two variables what to do
2812 if (var1->sign == NUMERIC_POS)
2814 if (var2->sign == NUMERIC_POS)
2818 * result = +(ABS(var1) + ABS(var2))
2821 add_abs(var1, var2, result);
2822 result->sign = NUMERIC_POS;
2827 * var1 is positive, var2 is negative
2828 * Must compare absolute values
2831 switch (cmp_abs(var1, var2))
2835 * ABS(var1) == ABS(var2)
2840 result->rscale = MAX(var1->rscale, var2->rscale);
2841 result->dscale = MAX(var1->dscale, var2->dscale);
2846 * ABS(var1) > ABS(var2)
2847 * result = +(ABS(var1) - ABS(var2))
2850 sub_abs(var1, var2, result);
2851 result->sign = NUMERIC_POS;
2856 * ABS(var1) < ABS(var2)
2857 * result = -(ABS(var2) - ABS(var1))
2860 sub_abs(var2, var1, result);
2861 result->sign = NUMERIC_NEG;
2868 if (var2->sign == NUMERIC_POS)
2871 * var1 is negative, var2 is positive
2872 * Must compare absolute values
2875 switch (cmp_abs(var1, var2))
2879 * ABS(var1) == ABS(var2)
2884 result->rscale = MAX(var1->rscale, var2->rscale);
2885 result->dscale = MAX(var1->dscale, var2->dscale);
2890 * ABS(var1) > ABS(var2)
2891 * result = -(ABS(var1) - ABS(var2))
2894 sub_abs(var1, var2, result);
2895 result->sign = NUMERIC_NEG;
2900 * ABS(var1) < ABS(var2)
2901 * result = +(ABS(var2) - ABS(var1))
2904 sub_abs(var2, var1, result);
2905 result->sign = NUMERIC_POS;
2913 * result = -(ABS(var1) + ABS(var2))
2916 add_abs(var1, var2, result);
2917 result->sign = NUMERIC_NEG;
2926 * Full version of sub functionality on variable level (handling signs).
2927 * result might point to one of the operands too without danger.
2931 sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
2934 * Decide on the signs of the two variables what to do
2937 if (var1->sign == NUMERIC_POS)
2939 if (var2->sign == NUMERIC_NEG)
2942 * var1 is positive, var2 is negative
2943 * result = +(ABS(var1) + ABS(var2))
2946 add_abs(var1, var2, result);
2947 result->sign = NUMERIC_POS;
2953 * Must compare absolute values
2956 switch (cmp_abs(var1, var2))
2960 * ABS(var1) == ABS(var2)
2965 result->rscale = MAX(var1->rscale, var2->rscale);
2966 result->dscale = MAX(var1->dscale, var2->dscale);
2971 * ABS(var1) > ABS(var2)
2972 * result = +(ABS(var1) - ABS(var2))
2975 sub_abs(var1, var2, result);
2976 result->sign = NUMERIC_POS;
2981 * ABS(var1) < ABS(var2)
2982 * result = -(ABS(var2) - ABS(var1))
2985 sub_abs(var2, var1, result);
2986 result->sign = NUMERIC_NEG;
2993 if (var2->sign == NUMERIC_NEG)
2997 * Must compare absolute values
3000 switch (cmp_abs(var1, var2))
3004 * ABS(var1) == ABS(var2)
3009 result->rscale = MAX(var1->rscale, var2->rscale);
3010 result->dscale = MAX(var1->dscale, var2->dscale);
3015 * ABS(var1) > ABS(var2)
3016 * result = -(ABS(var1) - ABS(var2))
3019 sub_abs(var1, var2, result);
3020 result->sign = NUMERIC_NEG;
3025 * ABS(var1) < ABS(var2)
3026 * result = +(ABS(var2) - ABS(var1))
3029 sub_abs(var2, var1, result);
3030 result->sign = NUMERIC_POS;
3037 * var1 is negative, var2 is positive
3038 * result = -(ABS(var1) + ABS(var2))
3041 add_abs(var1, var2, result);
3042 result->sign = NUMERIC_NEG;
3051 * Multiplication on variable level. Product of var1 * var2 is stored
3056 mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3058 NumericDigit *res_buf;
3059 NumericDigit *res_digits;
3069 res_weight = var1->weight + var2->weight + 2;
3070 res_ndigits = var1->ndigits + var2->ndigits + 1;
3071 if (var1->sign == var2->sign)
3072 res_sign = NUMERIC_POS;
3074 res_sign = NUMERIC_NEG;
3076 res_buf = digitbuf_alloc(res_ndigits);
3077 res_digits = res_buf;
3078 memset(res_digits, 0, res_ndigits);
3081 for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
3086 for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
3088 sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
3089 res_digits[i--] = sum % 10;
3092 res_digits[i] = sum;
3095 i = res_weight + global_rscale + 2;
3096 if (i >= 0 && i < res_ndigits)
3098 sum = (res_digits[i] > 4) ? 1 : 0;
3103 sum += res_digits[i];
3104 res_digits[i--] = sum % 10;
3109 while (res_ndigits > 0 && *res_digits == 0)
3115 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3118 if (res_ndigits == 0)
3120 res_sign = NUMERIC_POS;
3124 digitbuf_free(result->buf);
3125 result->buf = res_buf;
3126 result->digits = res_digits;
3127 result->ndigits = res_ndigits;
3128 result->weight = res_weight;
3129 result->rscale = global_rscale;
3130 result->sign = res_sign;
3137 * Division on variable level.
3141 div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3143 NumericDigit *res_digits;
3147 NumericVar dividend;
3148 NumericVar divisor[10];
3157 int first_nextdigit;
3161 * First of all division by zero check
3164 ndigits_tmp = var2->ndigits + 1;
3165 if (ndigits_tmp == 1)
3166 elog(ERROR, "division by zero on numeric");
3169 * Determine the result sign, weight and number of digits to calculate
3172 if (var1->sign == var2->sign)
3173 res_sign = NUMERIC_POS;
3175 res_sign = NUMERIC_NEG;
3176 res_weight = var1->weight - var2->weight + 1;
3177 res_ndigits = global_rscale + res_weight;
3178 if (res_ndigits <= 0)
3182 * Now result zero check
3185 if (var1->ndigits == 0)
3188 result->rscale = global_rscale;
3193 * Initialize local variables
3196 init_var(÷nd);
3197 for (i = 1; i < 10; i++)
3198 init_var(&divisor[i]);
3201 * Make a copy of the divisor which has one leading zero digit
3204 divisor[1].ndigits = ndigits_tmp;
3205 divisor[1].rscale = var2->ndigits;
3206 divisor[1].sign = NUMERIC_POS;
3207 divisor[1].buf = digitbuf_alloc(ndigits_tmp);
3208 divisor[1].digits = divisor[1].buf;
3209 divisor[1].digits[0] = 0;
3210 memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
3213 * Make a copy of the dividend
3216 dividend.ndigits = var1->ndigits;
3217 dividend.weight = 0;
3218 dividend.rscale = var1->ndigits;
3219 dividend.sign = NUMERIC_POS;
3220 dividend.buf = digitbuf_alloc(var1->ndigits);
3221 dividend.digits = dividend.buf;
3222 memcpy(dividend.digits, var1->digits, var1->ndigits);
3228 digitbuf_free(result->buf);
3229 result->buf = digitbuf_alloc(res_ndigits + 2);
3230 res_digits = result->buf;
3231 result->digits = res_digits;
3232 result->ndigits = res_ndigits;
3233 result->weight = res_weight;
3234 result->rscale = global_rscale;
3235 result->sign = res_sign;
3238 first_div = divisor[1].digits[1] * 10;
3239 if (ndigits_tmp > 2)
3240 first_div += divisor[1].digits[2];
3243 first_nextdigit = 0;
3246 rscale_tmp = divisor[1].rscale;
3248 for (ri = 0; ri <= res_ndigits; ri++)
3250 first_have = first_have * 10;
3251 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
3252 first_have += dividend.digits[first_nextdigit];
3255 guess = (first_have * 10) / first_div + 1;
3261 if (divisor[guess].buf == NULL)
3266 memcpy(&divisor[guess], &divisor[1], sizeof(NumericVar));
3267 divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
3268 divisor[guess].digits = divisor[guess].buf;
3269 for (i = divisor[1].ndigits - 1; i >= 0; i--)
3271 sum += divisor[1].digits[i] * guess;
3272 divisor[guess].digits[i] = sum % 10;
3277 divisor[guess].weight = weight_tmp;
3278 divisor[guess].rscale = rscale_tmp;
3280 stat = cmp_abs(÷nd, &divisor[guess]);
3287 res_digits[ri + 1] = guess;
3300 sub_abs(÷nd, &divisor[guess], ÷nd);
3302 first_nextdigit = dividend.weight - weight_tmp;
3304 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
3305 first_have = dividend.digits[first_nextdigit];
3309 result->ndigits = ri + 1;
3310 if (ri == res_ndigits + 1)
3312 int carry = (res_digits[ri] > 4) ? 1 : 0;
3314 result->ndigits = ri;
3317 while (carry && ri > 0)
3319 carry += res_digits[--ri];
3320 res_digits[ri] = carry % 10;
3325 while (result->ndigits > 0 && *(result->digits) == 0)
3329 (result->ndigits)--;
3331 while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
3332 (result->ndigits)--;
3333 if (result->ndigits == 0)
3334 result->sign = NUMERIC_POS;
3339 digitbuf_free(dividend.buf);
3340 for (i = 1; i < 10; i++)
3341 digitbuf_free(divisor[i].buf);
3348 * Calculate the modulo of two numerics at variable level
3352 mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3355 int save_global_rscale;
3360 * We do this using the equation
3361 * mod(x,y) = x - trunc(x/y)*y
3362 * We fiddle a bit with global_rscale to control result precision.
3365 save_global_rscale = global_rscale;
3366 global_rscale = var2->rscale + 2;
3368 div_var(var1, var2, &tmp);
3370 /* do trunc() by forgetting digits to the right of the decimal point */
3371 tmp.ndigits = MAX(0, MIN(tmp.ndigits, tmp.weight + 1));
3372 tmp.rscale = var2->rscale;
3374 global_rscale = var2->rscale;
3375 mul_var(var2, &tmp, &tmp);
3377 sub_var(var1, &tmp, result);
3379 global_rscale = save_global_rscale;
3387 * Return the smallest integer greater than or equal to the argument
3392 ceil_var(NumericVar *var, NumericVar *result)
3397 set_var_from_var(var, &tmp);
3400 tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
3401 if (tmp.sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
3402 add_var(&tmp, &const_one, &tmp);
3404 set_var_from_var(&tmp, result);
3412 * Return the largest integer equal to or less than the argument
3417 floor_var(NumericVar *var, NumericVar *result)
3422 set_var_from_var(var, &tmp);
3425 tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
3426 if (tmp.sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
3427 sub_var(&tmp, &const_one, &tmp);
3429 set_var_from_var(&tmp, result);
3437 * Compute the square root of x using Newtons algorithm
3441 sqrt_var(NumericVar *arg, NumericVar *result)
3445 NumericVar last_val;
3447 int save_global_rscale;
3450 save_global_rscale = global_rscale;
3452 res_rscale = global_rscale;
3454 stat = cmp_var(arg, &const_zero);
3457 set_var_from_var(&const_zero, result);
3458 result->rscale = res_rscale;
3459 result->sign = NUMERIC_POS;
3464 elog(ERROR, "math error on numeric - cannot compute SQRT of negative value");
3468 init_var(&last_val);
3470 set_var_from_var(arg, &tmp_arg);
3471 set_var_from_var(result, &last_val);
3474 * Initialize the result to the first guess
3477 digitbuf_free(result->buf);
3478 result->buf = digitbuf_alloc(1);
3479 result->digits = result->buf;
3480 result->digits[0] = tmp_arg.digits[0] / 2;
3481 if (result->digits[0] == 0)
3482 result->digits[0] = 1;
3483 result->ndigits = 1;
3484 result->weight = tmp_arg.weight / 2;
3485 result->rscale = res_rscale;
3486 result->sign = NUMERIC_POS;
3490 div_var(&tmp_arg, result, &tmp_val);
3492 add_var(result, &tmp_val, result);
3493 div_var(result, &const_two, result);
3495 if (cmp_var(&last_val, result) == 0)
3497 set_var_from_var(result, &last_val);
3500 free_var(&last_val);
3504 global_rscale = save_global_rscale;
3505 div_var(result, &const_one, result);
3512 * Raise e to the power of x
3516 exp_var(NumericVar *arg, NumericVar *result)
3527 int save_global_rscale;
3535 set_var_from_var(arg, &x);
3537 if (x.sign == NUMERIC_NEG)
3540 x.sign = NUMERIC_POS;
3543 save_global_rscale = global_rscale;
3545 for (i = x.weight, d = 0; i >= 0; i--, d++)
3547 global_rscale *= 10;
3549 global_rscale += x.digits[d];
3550 if (global_rscale >= 1000)
3551 elog(ERROR, "argument for EXP() too big");
3554 global_rscale = global_rscale / 2 + save_global_rscale + 8;
3556 while (cmp_var(&x, &const_one) > 0)
3560 div_var(&x, &const_two, &x);
3563 add_var(&const_one, &x, result);
3564 set_var_from_var(&x, &xpow);
3565 set_var_from_var(&const_one, &ifac);
3566 set_var_from_var(&const_one, &ni);
3570 add_var(&ni, &const_one, &ni);
3571 mul_var(&xpow, &x, &xpow);
3572 mul_var(&ifac, &ni, &ifac);
3573 div_var(&xpow, &ifac, &elem);
3575 if (elem.ndigits == 0)
3578 add_var(result, &elem, result);
3582 mul_var(result, result, result);
3584 global_rscale = save_global_rscale;
3586 div_var(&const_one, result, result);
3588 div_var(result, &const_one, result);
3590 result->sign = NUMERIC_POS;
3603 * Compute the natural log of x
3607 ln_var(NumericVar *arg, NumericVar *result)
3615 int save_global_rscale;
3617 if (cmp_var(arg, &const_zero) <= 0)
3618 elog(ERROR, "math error on numeric - cannot compute LN of value <= zero");
3620 save_global_rscale = global_rscale;
3629 set_var_from_var(&const_two, &fact);
3630 set_var_from_var(arg, &x);
3632 while (cmp_var(&x, &const_two) >= 0)
3635 mul_var(&fact, &const_two, &fact);
3637 set_var_from_str("0.5", &elem);
3638 while (cmp_var(&x, &elem) <= 0)
3641 mul_var(&fact, &const_two, &fact);
3644 sub_var(&x, &const_one, result);
3645 add_var(&x, &const_one, &elem);
3646 div_var(result, &elem, result);
3647 set_var_from_var(result, &xx);
3648 mul_var(result, result, &x);
3650 set_var_from_var(&const_one, &ni);
3654 add_var(&ni, &const_two, &ni);
3655 mul_var(&xx, &x, &xx);
3656 div_var(&xx, &ni, &elem);
3658 if (cmp_var(&elem, &const_zero) == 0)
3661 add_var(result, &elem, result);
3664 global_rscale = save_global_rscale;
3665 mul_var(result, &fact, result);
3678 * Compute the logarithm of x in a given base
3682 log_var(NumericVar *base, NumericVar *num, NumericVar *result)
3692 ln_var(base, &ln_base);
3693 ln_var(num, &ln_num);
3697 div_var(&ln_num, &ln_base, result);
3707 * Raise base to the power of exp
3711 power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
3715 int save_global_rscale;
3717 save_global_rscale = global_rscale;
3718 global_rscale += global_rscale / 3 + 8;
3723 ln_var(base, &ln_base);
3724 mul_var(&ln_base, exp, &ln_num);
3726 global_rscale = save_global_rscale;
3728 exp_var(&ln_num, result);
3736 /* ----------------------------------------------------------------------
3738 * Following are the lowest level functions that operate unsigned
3739 * on the variable level
3741 * ----------------------------------------------------------------------
3748 * Compare the absolute values of var1 and var2
3749 * Returns: -1 for ABS(var1) < ABS(var2)
3750 * 0 for ABS(var1) == ABS(var2)
3751 * 1 for ABS(var1) > ABS(var2)
3755 cmp_abs(NumericVar *var1, NumericVar *var2)
3759 int w1 = var1->weight;
3760 int w2 = var2->weight;
3763 while (w1 > w2 && i1 < var1->ndigits)
3765 if (var1->digits[i1++] != 0)
3769 while (w2 > w1 && i2 < var2->ndigits)
3771 if (var2->digits[i2++] != 0)
3778 while (i1 < var1->ndigits && i2 < var2->ndigits)
3780 stat = var1->digits[i1++] - var2->digits[i2++];
3790 while (i1 < var1->ndigits)
3792 if (var1->digits[i1++] != 0)
3795 while (i2 < var2->ndigits)
3797 if (var2->digits[i2++] != 0)
3808 * Add the absolute values of two variables into result.
3809 * result might point to one of the operands without danger.
3813 add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
3815 NumericDigit *res_buf;
3816 NumericDigit *res_digits;
3826 /* copy these values into local vars for speed in inner loop */
3827 int var1ndigits = var1->ndigits;
3828 int var2ndigits = var2->ndigits;
3829 NumericDigit *var1digits = var1->digits;
3830 NumericDigit *var2digits = var2->digits;
3832 res_weight = MAX(var1->weight, var2->weight) + 1;
3833 res_rscale = MAX(var1->rscale, var2->rscale);
3834 res_dscale = MAX(var1->dscale, var2->dscale);
3835 res_ndigits = res_rscale + res_weight + 1;
3836 if (res_ndigits <= 0)
3839 res_buf = digitbuf_alloc(res_ndigits);
3840 res_digits = res_buf;
3842 i1 = res_rscale + var1->weight + 1;
3843 i2 = res_rscale + var2->weight + 1;
3844 for (i = res_ndigits - 1; i >= 0; i--)
3848 if (i1 >= 0 && i1 < var1ndigits)
3849 carry += var1digits[i1];
3850 if (i2 >= 0 && i2 < var2ndigits)
3851 carry += var2digits[i2];
3855 res_digits[i] = carry - 10;
3860 res_digits[i] = carry;
3865 Assert(carry == 0); /* else we failed to allow for carry out */
3867 while (res_ndigits > 0 && *res_digits == 0)
3873 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3876 if (res_ndigits == 0)
3879 digitbuf_free(result->buf);
3880 result->ndigits = res_ndigits;
3881 result->buf = res_buf;
3882 result->digits = res_digits;
3883 result->weight = res_weight;
3884 result->rscale = res_rscale;
3885 result->dscale = res_dscale;
3892 * Subtract the absolute value of var2 from the absolute value of var1
3893 * and store in result. result might point to one of the operands
3896 * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
3900 sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
3902 NumericDigit *res_buf;
3903 NumericDigit *res_digits;
3913 /* copy these values into local vars for speed in inner loop */
3914 int var1ndigits = var1->ndigits;
3915 int var2ndigits = var2->ndigits;
3916 NumericDigit *var1digits = var1->digits;
3917 NumericDigit *var2digits = var2->digits;
3919 res_weight = var1->weight;
3920 res_rscale = MAX(var1->rscale, var2->rscale);
3921 res_dscale = MAX(var1->dscale, var2->dscale);
3922 res_ndigits = res_rscale + res_weight + 1;
3923 if (res_ndigits <= 0)
3926 res_buf = digitbuf_alloc(res_ndigits);
3927 res_digits = res_buf;
3929 i1 = res_rscale + var1->weight + 1;
3930 i2 = res_rscale + var2->weight + 1;
3931 for (i = res_ndigits - 1; i >= 0; i--)
3935 if (i1 >= 0 && i1 < var1ndigits)
3936 borrow += var1digits[i1];
3937 if (i2 >= 0 && i2 < var2ndigits)
3938 borrow -= var2digits[i2];
3942 res_digits[i] = borrow + 10;
3947 res_digits[i] = borrow;
3952 Assert(borrow == 0); /* else caller gave us var1 < var2 */
3954 while (res_ndigits > 0 && *res_digits == 0)
3960 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3963 if (res_ndigits == 0)
3966 digitbuf_free(result->buf);
3967 result->ndigits = res_ndigits;
3968 result->buf = res_buf;
3969 result->digits = res_digits;
3970 result->weight = res_weight;
3971 result->rscale = res_rscale;
3972 result->dscale = res_dscale;