1 /****************************************************************************/
2 /* APQ DATABASE BINDINGS */
3 /* */
4 /* A P Q - POSTGRESQL */
5 /* */
6 /* B o d y */
7 /* */
8 /* Copyright (C) 2002-2007, Warren W. Gay VE3WWG */
9 /* Copyright (C) 2007-2009, Ada Works Project */
10 /* */
11 /* */
12 /* APQ is free software; you can redistribute it and/or modify it under */
13 /* terms of the GNU General Public License as published by the Free Soft- */
14 /* ware Foundation; either version 2, or (at your option) any later ver- */
15 /* sion. APQ is distributed in the hope that it will be useful, but WITH- */
16 /* OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY */
17 /* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License */
18 /* for more details. You should have received a copy of the GNU General */
19 /* Public License distributed with APQ; see file COPYING. If not, write */
20 /* to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, */
21 /* MA 02111-1307, USA. */
22 /* */
23 /* As a special exception, if other files instantiate generics from this */
24 /* unit, or you link this unit with other files to produce an executable, */
25 /* this unit does not by itself cause the resulting executable to be */
26 /* covered by the GNU General Public License. This exception does not */
27 /* however invalidate any other reasons why the executable file might be */
28 /* covered by the GNU Public License. */
29 /****************************************************************************/
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include "decimal.h"
36
37 /* ----------
38 * Uncomment the following to enable compilation of dump_numeric()
39 * and dump_var() and to get a dump of any result produced by make_result().
40 * ----------
41 #define NUMERIC_DEBUG
42 */
43
44 /* ----------
45 * Local definitions
46 * ----------
47 */
48 #ifndef MIN
49 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
50 #endif
51 #ifndef MAX
52 #define MAX(a,b) (((a)>(b)) ? (a) : (b))
53 #endif
54
55 #ifndef NAN
56 #define NAN (0.0/0.0)
57 #endif
58
59 #define nan_var(v) free_var(v)
60
61 /* ----------
62 * Local data types
63 *
64 * Note: the first digit of a NumericVar's value is assumed to be multiplied
65 * by 10 ** weight. Another way to say it is that there are weight+1 digits
66 * before the decimal point. It is possible to have weight < 0.
67 *
68 * The value represented by a NumericVar is determined by the sign, weight,
69 * ndigits, and digits[] array. The rscale and dscale are carried along,
70 * but they are just auxiliary information until rounding is done before
71 * final storage or display. (Scales are the number of digits wanted
72 * *after* the decimal point. Scales are always >= 0.)
73 *
74 * buf points at the physical start of the palloc'd digit buffer for the
75 * NumericVar. digits points at the first digit in actual use (the one
76 * with the specified weight). We normally leave an unused byte or two
77 * (preset to zeroes) between buf and digits, so that there is room to store
78 * a carry out of the top digit without special pushups. We just need to
79 * decrement digits (and increment weight) to make room for the carry digit.
80 *
81 * If buf is NULL then the digit buffer isn't actually palloc'd and should
82 * not be freed --- see the constants below for an example.
83 *
84 * NB: All the variable-level functions are written in a style that makes it
85 * possible to give one and the same variable as argument and destination.
86 * This is feasible because the digit buffer is separate from the variable.
87 * ----------
88 */
89 typedef unsigned char NumericDigit;
90
91 typedef struct NumericVar
92 {
93 int ndigits; /* number of digits in digits[] - can be * 0! */
94 int weight; /* weight of first digit */
95 int rscale; /* result scale */
96 int dscale; /* display scale */
97 int sign; /* NUMERIC_POS, NUMERIC_NEG, or * NUMERIC_NAN */
98 NumericDigit *buf; /* start of palloc'd space for digits[] */
99 NumericDigit *digits; /* decimal digits */
100 } NumericVar;
101
102 /* ----------
103 * Some preinitialized variables we need often
104 * ----------
105 */
106 static NumericDigit const_zero_data[1] = {0};
107 static NumericVar const_zero = {0, 0, 0, 0, NUMERIC_POS, NULL, const_zero_data};
108
109 static NumericDigit const_one_data[1] = {1};
110 static NumericVar const_one = {1, 0, 0, 0, NUMERIC_POS, NULL, const_one_data};
111
112 static NumericDigit const_two_data[1] = {2};
113 static NumericVar const_two = {1, 0, 0, 0, NUMERIC_POS, NULL, const_two_data};
114
115 static NumericVar const_nan = {0, 0, 0, 0, NUMERIC_NAN, NULL, NULL};
116
117 /* ----------
118 * Local functions
119 * ----------
120 */
121
122 #ifdef NUMERIC_DEBUG
123 static void dump_numeric(char *str, Numeric num);
124 static void dump_var(char *str, NumericVar *var);
125 #else
126 #define dump_numeric(s,n)
127 #define dump_var(s,v)
128 #endif
129
130 #define digitbuf_alloc(size) ((NumericDigit *) palloc(size))
131 #define digitbuf_free(buf) \
132 do { \
133 if ((buf) != NULL) \
134 pfree(buf); \
135 } while (0)
136
137 #define init_var(v) memset(v,0,sizeof(NumericVar))
138 static void alloc_var(NumericVar *var, int ndigits);
139 static void free_var(NumericVar *var);
140 static void zero_var(NumericVar *var);
141
142 static void set_var_from_str(const char *str, NumericVar *dest, Decimal_Exception *ex);
143 static void set_var_from_num(Numeric value, NumericVar *dest);
144 static void set_var_from_var(NumericVar *value, NumericVar *dest);
145 static char *get_str_from_var(NumericVar *var, int dscale);
146
147 static Numeric make_result(NumericVar *var);
148
149 static void apply_typmod(NumericVar *var, int precision, int scale, Decimal_Exception *ex);
150
151 static int cmp_numerics(Numeric num1, Numeric num2);
152 static int cmp_var(NumericVar *var1, NumericVar *var2);
153 static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
154 static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
155 static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale);
156 static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
157 static int select_div_scale(NumericVar *var1, NumericVar *var2, int *global_rscale);
158 static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
159 static void ceil_var(NumericVar *var, NumericVar *result);
160 static void floor_var(NumericVar *var, NumericVar *result);
161
162 static void sqrt_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
163 static void exp_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
164 static void ln_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
165 static void log_var(NumericVar *base, NumericVar *num, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
166 static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result, int *global_rscale, Decimal_Exception *ex);
167
168 static int cmp_abs(NumericVar *var1, NumericVar *var2);
169 static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
170 static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
171
172 /*
173 * Provide an initialization value for global_rscale :
174 */
175 int
numeric_global_rscale(void)176 numeric_global_rscale(void) {
177 return NUMERIC_MIN_RESULT_SCALE;
178 }
179
180 /* ----------------------------------------------------------------------
181 *
182 * Input-, output- and rounding-functions
183 *
184 * ----------------------------------------------------------------------
185 * numeric_in() -
186 *
187 * Input function for numeric data type :
188 * NOTES:
189 * When precision is zero, the precision and scale arguments are
190 * ignored. Otherwise the converted value is made to fit the
191 * parameters supplied, else Numeric_Overflow exception.
192 * ----------
193 */
194 Numeric
numeric_in(const char * str,int precision,int scale,Decimal_Exception * ex)195 numeric_in(const char *str, int precision, int scale, Decimal_Exception *ex) {
196 NumericVar value;
197 Numeric res;
198
199 *ex = No_Error;
200
201 /*
202 * Check for NaN
203 */
204 if (strcmp(str, "NaN") == 0)
205 return make_result(&const_nan);
206
207 /*
208 * Use set_var_from_str() to parse the input string and return it in
209 * the packed DB storage format
210 */
211 init_var(&value);
212 set_var_from_str(str, &value, ex);
213 if ( *ex != No_Error ) {
214 res = make_result(&const_nan);
215 } else {
216 if ( precision != 0 )
217 apply_typmod(&value, precision, scale, ex);
218 res = make_result(&value);
219 }
220 free_var(&value);
221
222 return res;
223 }
224
225 /* ----------
226 * numeric_out() -
227 *
228 * Output function for numeric data type
229 * ----------
230 */
231 char *
numeric_out(Numeric num)232 numeric_out(Numeric num) {
233 NumericVar x;
234 char *str;
235
236 /*
237 * Handle NaN
238 */
239 if (NUMERIC_IS_NAN(num))
240 return pstrdup("NaN");
241
242 /*
243 * Get the number in the variable format.
244 *
245 * Even if we didn't need to change format, we'd still need to copy the
246 * value to have a modifiable copy for rounding. set_var_from_num()
247 * also guarantees there is extra digit space in case we produce a
248 * carry out from rounding.
249 */
250 init_var(&x);
251 set_var_from_num(num, &x);
252
253 str = get_str_from_var(&x, x.dscale);
254
255 free_var(&x);
256
257 return str;
258 }
259
260 /*
261 * Return TRUE if the value is NaN :
262 */
263 int
numeric_isnan(Numeric num)264 numeric_isnan(Numeric num) {
265 return NUMERIC_IS_NAN(num);
266 }
267
268 /* ----------
269 * numeric() -
270 *
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.
274 * ----------
275 */
276 Numeric
numeric(Numeric num,int precision,int scale,Decimal_Exception * ex)277 numeric(Numeric num, int precision, int scale, Decimal_Exception *ex) {
278 Numeric new;
279 int maxweight;
280 NumericVar var;
281
282 *ex = No_Error;
283
284 /*
285 * Handle NaN
286 */
287 if (NUMERIC_IS_NAN(num))
288 return make_result(&const_nan);
289
290 maxweight = precision - scale;
291
292 /*
293 * If the number is in bounds and due to the present result scale no
294 * rounding could be necessary, just make a copy of the input and
295 * modify its scale fields.
296 */
297 if (num->n_weight < maxweight && scale >= num->n_rscale)
298 {
299 new = (Numeric) palloc(num->varlen);
300 memcpy(new, num, num->varlen);
301 new->n_rscale = scale;
302 new->n_sign_dscale = NUMERIC_SIGN(new) | ((uint16) scale & NUMERIC_DSCALE_MASK);
303 return new;
304 }
305
306 /*
307 * We really need to fiddle with things - unpack the number into a
308 * variable and let apply_typmod() do it.
309 */
310 init_var(&var);
311 set_var_from_num(num, &var);
312 apply_typmod(&var, precision, scale, ex);
313 new = make_result(&var);
314
315 free_var(&var);
316
317 return new;
318 }
319
320 /*
321 * Release the storage occupied by this Numeric :
322 * (designed to be called by Ada95)
323 */
324 void
numeric_free(Numeric num)325 numeric_free(Numeric num) {
326 free(num);
327 }
328
329 /* ----------------------------------------------------------------------
330 *
331 * Sign manipulation, rounding and the like
332 *
333 * ----------------------------------------------------------------------
334 */
335 Numeric
numeric_abs(Numeric num)336 numeric_abs(Numeric num) {
337 Numeric res;
338
339 /*
340 * Handle NaN
341 */
342 if (NUMERIC_IS_NAN(num))
343 return make_result(&const_nan);
344
345 /*
346 * Do it the easy way directly on the packed format
347 */
348 res = (Numeric) palloc(num->varlen);
349 memcpy(res, num, num->varlen);
350
351 res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
352
353 return res;
354 }
355
356 Numeric
numeric_uminus(Numeric num)357 numeric_uminus(Numeric num) {
358 Numeric res;
359
360 /*
361 * Handle NaN
362 */
363 if (NUMERIC_IS_NAN(num))
364 return make_result(&const_nan);
365
366 /*
367 * Do it the easy way directly on the packed format
368 */
369 res = (Numeric) palloc(num->varlen);
370 memcpy(res, num, num->varlen);
371
372 /*
373 * The packed format is known to be totally zero digit trimmed always.
374 * So we can identify a ZERO by the fact that there are no digits at
375 * all. Do nothing to a zero.
376 */
377 if (num->varlen != NUMERIC_HDRSZ)
378 {
379 /* Else, flip the sign */
380 if (NUMERIC_SIGN(num) == NUMERIC_POS)
381 res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num);
382 else
383 res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
384 }
385
386 return res;
387 }
388
389 /*
390 * This effectively just copies the value :
391 */
392 Numeric
numeric_uplus(Numeric num)393 numeric_uplus(Numeric num) {
394 Numeric res;
395
396 res = (Numeric) palloc(num->varlen);
397 memcpy(res, num, num->varlen);
398 return res;
399 }
400
401 /*
402 * Return the sign of the value :
403 */
404 Numeric
numeric_sign(Numeric num)405 numeric_sign(Numeric num) {
406 Numeric res;
407 NumericVar result;
408
409 /*
410 * Handle NaN
411 */
412 if (NUMERIC_IS_NAN(num))
413 return make_result(&const_nan);
414
415 init_var(&result);
416
417 /*
418 * The packed format is known to be totally zero digit trimmed always.
419 * So we can identify a ZERO by the fact that there are no digits at
420 * all.
421 */
422 if (num->varlen == NUMERIC_HDRSZ)
423 set_var_from_var(&const_zero, &result);
424 else
425 {
426 /*
427 * And if there are some, we return a copy of ONE with the sign of
428 * our argument
429 */
430 set_var_from_var(&const_one, &result);
431 result.sign = NUMERIC_SIGN(num);
432 }
433
434 res = make_result(&result);
435 free_var(&result);
436
437 return res;
438 }
439
440 /* ----------
441 * numeric_round() -
442 *
443 * Round a value to have 'scale' digits after the decimal point.
444 * We allow negative 'scale', implying rounding before the decimal
445 * point --- Oracle interprets rounding that way.
446 * ----------
447 */
448 Numeric
numeric_round(Numeric num,int scale)449 numeric_round(Numeric num,int scale) {
450 Numeric res;
451 NumericVar arg;
452 int i;
453
454 /*
455 * Handle NaN
456 */
457 if (NUMERIC_IS_NAN(num))
458 return make_result(&const_nan);
459
460 /*
461 * Limit the scale value to avoid possible overflow in calculations
462 * below.
463 */
464 scale = MIN(NUMERIC_MAX_RESULT_SCALE,
465 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
466
467 /*
468 * Unpack the argument and round it at the proper digit position
469 */
470 init_var(&arg);
471 set_var_from_num(num, &arg);
472
473 i = arg.weight + scale + 1;
474
475 if (i < arg.ndigits)
476 {
477 /*
478 * If i = 0, the value loses all digits, but could round up if its
479 * first digit is more than 4. If i < 0 the result must be 0.
480 */
481 if (i < 0)
482 arg.ndigits = 0;
483 else
484 {
485 int carry = (arg.digits[i] > 4) ? 1 : 0;
486
487 arg.ndigits = i;
488
489 while (carry)
490 {
491 carry += arg.digits[--i];
492 arg.digits[i] = carry % 10;
493 carry /= 10;
494 }
495
496 if (i < 0)
497 {
498 Assert(i == -1); /* better not have added more than 1 digit */
499 Assert(arg.digits > arg.buf);
500 arg.digits--;
501 arg.ndigits++;
502 arg.weight++;
503 }
504 }
505 }
506
507 /*
508 * Set result's scale to something reasonable.
509 */
510 scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
511 arg.rscale = scale;
512 arg.dscale = scale;
513
514 /*
515 * Return the rounded result
516 */
517 res = make_result(&arg);
518
519 free_var(&arg);
520 return res;
521 }
522
523 /* ----------
524 * numeric_trunc() -
525 *
526 * Truncate a value to have 'scale' digits after the decimal point.
527 * We allow negative 'scale', implying a truncation before the decimal
528 * point --- Oracle interprets truncation that way.
529 * ----------
530 */
531 Numeric
numeric_trunc(Numeric num,int scale)532 numeric_trunc(Numeric num,int scale) {
533 Numeric res;
534 NumericVar arg;
535
536 /*
537 * Handle NaN
538 */
539 if (NUMERIC_IS_NAN(num))
540 return make_result(&const_nan);
541
542 /*
543 * Limit the scale value to avoid possible overflow in calculations
544 * below.
545 */
546 scale = MIN(NUMERIC_MAX_RESULT_SCALE,
547 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
548
549 /*
550 * Unpack the argument and truncate it at the proper digit position
551 */
552 init_var(&arg);
553 set_var_from_num(num, &arg);
554
555 arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));
556
557 /*
558 * Set result's scale to something reasonable.
559 */
560 scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
561 arg.rscale = scale;
562 arg.dscale = scale;
563
564 /*
565 * Return the truncated result
566 */
567 res = make_result(&arg);
568
569 free_var(&arg);
570 return res;
571 }
572
573 /* ----------
574 * numeric_ceil() -
575 *
576 * Return the smallest integer greater than or equal to the argument
577 * ----------
578 */
579 Numeric
numeric_ceil(Numeric num)580 numeric_ceil(Numeric num) {
581 Numeric res;
582 NumericVar result;
583
584 if (NUMERIC_IS_NAN(num))
585 return make_result(&const_nan);
586
587 init_var(&result);
588
589 set_var_from_num(num, &result);
590 ceil_var(&result, &result);
591
592 result.dscale = 0;
593
594 res = make_result(&result);
595 free_var(&result);
596
597 return res;
598 }
599
600
601 /* ----------
602 * numeric_floor() -
603 *
604 * Return the largest integer equal to or less than the argument
605 * ----------
606 */
607 Numeric
numeric_floor(Numeric num)608 numeric_floor(Numeric num) {
609 Numeric res;
610 NumericVar result;
611
612 if (NUMERIC_IS_NAN(num))
613 return make_result(&const_nan);
614
615 init_var(&result);
616
617 set_var_from_num(num, &result);
618 floor_var(&result, &result);
619
620 result.dscale = 0;
621
622 res = make_result(&result);
623 free_var(&result);
624
625 return res;
626 }
627
628
629 /* ----------------------------------------------------------------------
630 *
631 * Comparison functions
632 *
633 * Note: btree indexes need these routines not to leak memory; therefore,
634 * be careful to free working copies of toasted datums. Most places don't
635 * need to be so careful.
636 * ----------------------------------------------------------------------
637 */
638
639 int
numeric_cmp(Numeric num1,Numeric num2)640 numeric_cmp(Numeric num1, Numeric num2) {
641 Numeric orig1 = num1, orig2 = num2;
642 int result;
643
644 result = cmp_numerics(num1, num2);
645
646 if ( num1 != orig1 )
647 free(num1);
648 if ( num2 != orig2 )
649 free(num2);
650
651 return result;
652 }
653
654 int
numeric_eq(Numeric num1,Numeric num2)655 numeric_eq(Numeric num1, Numeric num2) {
656 return numeric_cmp(num1,num2) == 0;
657 }
658
659 int
numeric_ne(Numeric num1,Numeric num2)660 numeric_ne(Numeric num1, Numeric num2) {
661 return numeric_cmp(num1,num2) != 0;
662 }
663
664 int
numeric_gt(Numeric num1,Numeric num2)665 numeric_gt(Numeric num1, Numeric num2) {
666 return numeric_cmp(num1,num2) > 0;
667 }
668
669 int
numeric_ge(Numeric num1,Numeric num2)670 numeric_ge(Numeric num1, Numeric num2) {
671 return numeric_cmp(num1,num2) >= 0;
672 }
673
674 int
numeric_lt(Numeric num1,Numeric num2)675 numeric_lt(Numeric num1, Numeric num2) {
676 return numeric_cmp(num1,num2) < 0;
677 }
678
679 int
numeric_le(Numeric num1,Numeric num2)680 numeric_le(Numeric num1, Numeric num2) {
681 return numeric_cmp(num1,num2) <= 0;
682 }
683
684 static int
cmp_numerics(Numeric num1,Numeric num2)685 cmp_numerics(Numeric num1, Numeric num2)
686 {
687 int result;
688
689 /*
690 * We consider all NANs to be equal and larger than any non-NAN. This
691 * is somewhat arbitrary; the important thing is to have a consistent
692 * sort order.
693 */
694 if (NUMERIC_IS_NAN(num1))
695 {
696 if (NUMERIC_IS_NAN(num2))
697 result = 0; /* NAN = NAN */
698 else
699 result = 1; /* NAN > non-NAN */
700 }
701 else if (NUMERIC_IS_NAN(num2))
702 {
703 result = -1; /* non-NAN < NAN */
704 }
705 else
706 {
707 NumericVar arg1;
708 NumericVar arg2;
709
710 init_var(&arg1);
711 init_var(&arg2);
712
713 set_var_from_num(num1, &arg1);
714 set_var_from_num(num2, &arg2);
715
716 result = cmp_var(&arg1, &arg2);
717
718 free_var(&arg1);
719 free_var(&arg2);
720 }
721
722 return result;
723 }
724
725
726 /* ----------------------------------------------------------------------
727 *
728 * Arithmetic base functions
729 *
730 * ----------------------------------------------------------------------
731 * numeric_add() -
732 *
733 * Add two numerics
734 * ----------
735 */
736 Numeric
numeric_add(Numeric num1,Numeric num2)737 numeric_add(Numeric num1, Numeric num2) {
738 NumericVar arg1;
739 NumericVar arg2;
740 NumericVar result;
741 Numeric res;
742
743 /*
744 * Handle NaN
745 */
746 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
747 return make_result(&const_nan);
748
749 /*
750 * Unpack the values, let add_var() compute the result and return it.
751 * The internals of add_var() will automatically set the correct
752 * result and display scales in the result.
753 */
754 init_var(&arg1);
755 init_var(&arg2);
756 init_var(&result);
757
758 set_var_from_num(num1, &arg1);
759 set_var_from_num(num2, &arg2);
760
761 add_var(&arg1, &arg2, &result);
762 res = make_result(&result);
763
764 free_var(&arg1);
765 free_var(&arg2);
766 free_var(&result);
767
768 return res;
769 }
770
771 /* ----------
772 * numeric_sub() -
773 *
774 * Subtract one numeric from another
775 * ----------
776 */
777 Numeric
numeric_sub(Numeric num1,Numeric num2)778 numeric_sub(Numeric num1, Numeric num2) {
779 NumericVar arg1;
780 NumericVar arg2;
781 NumericVar result;
782 Numeric res;
783
784 /*
785 * Handle NaN
786 */
787 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
788 return make_result(&const_nan);
789
790 /*
791 * Unpack the two arguments, let sub_var() compute the result and
792 * return it.
793 */
794 init_var(&arg1);
795 init_var(&arg2);
796 init_var(&result);
797
798 set_var_from_num(num1, &arg1);
799 set_var_from_num(num2, &arg2);
800
801 sub_var(&arg1, &arg2, &result);
802 res = make_result(&result);
803
804 free_var(&arg1);
805 free_var(&arg2);
806 free_var(&result);
807
808 return res;
809 }
810
811 /* ----------
812 * numeric_mul() -
813 *
814 * Calculate the product of two numerics
815 * ----------
816 */
817 Numeric
numeric_mul(Numeric num1,Numeric num2,int * global_rscale)818 numeric_mul(Numeric num1, Numeric num2, int *global_rscale) {
819 NumericVar arg1;
820 NumericVar arg2;
821 NumericVar result;
822 Numeric res;
823
824 /*
825 * Handle NaN
826 */
827 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
828 return make_result(&const_nan);
829
830 /*
831 * Unpack the arguments, let mul_var() compute the result and return
832 * it. Unlike add_var() and sub_var(), mul_var() will round the result
833 * to the scale stored in global_rscale. In the case of numeric_mul(),
834 * which is invoked for the * operator on numerics, we set it to the
835 * exact representation for the product (rscale = sum(rscale of arg1,
836 * rscale of arg2) and the same for the dscale).
837 */
838 init_var(&arg1);
839 init_var(&arg2);
840 init_var(&result);
841
842 set_var_from_num(num1, &arg1);
843 set_var_from_num(num2, &arg2);
844
845 *global_rscale = arg1.rscale + arg2.rscale;
846
847 mul_var(&arg1, &arg2, &result, global_rscale);
848
849 result.dscale = arg1.dscale + arg2.dscale;
850
851 res = make_result(&result);
852
853 free_var(&arg1);
854 free_var(&arg2);
855 free_var(&result);
856
857 return res;
858 }
859
860 /* ----------
861 * numeric_div() -
862 *
863 * Divide one numeric into another
864 * ----------
865 */
866 Numeric
numeric_div(Numeric num1,Numeric num2,int * global_rscale,Decimal_Exception * ex)867 numeric_div(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) {
868 NumericVar arg1;
869 NumericVar arg2;
870 NumericVar result;
871 Numeric res;
872 int res_dscale;
873
874 *ex = No_Error;
875
876 /*
877 * Handle NaN
878 */
879 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
880 return make_result(&const_nan);
881
882 /*
883 * Unpack the arguments
884 */
885 init_var(&arg1);
886 init_var(&arg2);
887 init_var(&result);
888
889 set_var_from_num(num1, &arg1);
890 set_var_from_num(num2, &arg2);
891
892 res_dscale = select_div_scale(&arg1, &arg2, global_rscale);
893
894 /*
895 * Do the divide, set the display scale and return the result
896 */
897 div_var(&arg1, &arg2, &result, global_rscale, ex);
898 if ( *ex != No_Error ) {
899 res = make_result(&const_nan);
900 } else {
901 result.dscale = res_dscale;
902 res = make_result(&result);
903 }
904
905 free_var(&arg1);
906 free_var(&arg2);
907 free_var(&result);
908
909 return res;
910 }
911
912 /* ----------
913 * numeric_mod() -
914 *
915 * Calculate the modulo of two numerics
916 * ----------
917 */
918 Numeric
numeric_mod(Numeric num1,Numeric num2,int * global_rscale,Decimal_Exception * ex)919 numeric_mod(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) {
920 Numeric res;
921 NumericVar arg1;
922 NumericVar arg2;
923 NumericVar result;
924
925 *ex = No_Error;
926
927 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
928 return make_result(&const_nan);
929
930 init_var(&arg1);
931 init_var(&arg2);
932 init_var(&result);
933
934 set_var_from_num(num1, &arg1);
935 set_var_from_num(num2, &arg2);
936
937 mod_var(&arg1, &arg2, &result, global_rscale, ex);
938
939 res = make_result(&result);
940
941 free_var(&result);
942 free_var(&arg2);
943 free_var(&arg1);
944
945 return res;
946 }
947
948 /* ----------
949 * numeric_smaller() -
950 *
951 * Return the smaller of two numbers
952 * ----------
953 */
954 Numeric
numeric_smaller(Numeric num1,Numeric num2)955 numeric_smaller(Numeric num1, Numeric num2) {
956 NumericVar arg1;
957 NumericVar arg2;
958 Numeric res;
959
960 /*
961 * Handle NaN
962 */
963 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
964 return make_result(&const_nan);
965
966 /*
967 * Unpack the values, and decide which is the smaller one
968 */
969 init_var(&arg1);
970 init_var(&arg2);
971
972 set_var_from_num(num1, &arg1);
973 set_var_from_num(num2, &arg2);
974
975 if (cmp_var(&arg1, &arg2) <= 0)
976 res = make_result(&arg1);
977 else
978 res = make_result(&arg2);
979
980 free_var(&arg1);
981 free_var(&arg2);
982
983 return res;
984 }
985
986
987 /* ----------
988 * numeric_larger() -
989 *
990 * Return the larger of two numbers
991 * ----------
992 */
993 Numeric
numeric_larger(Numeric num1,Numeric num2)994 numeric_larger(Numeric num1, Numeric num2) {
995 NumericVar arg1;
996 NumericVar arg2;
997 Numeric res;
998
999 /*
1000 * Handle NaN
1001 */
1002 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1003 return make_result(&const_nan);
1004
1005 /*
1006 * Unpack the values, and decide which is the larger one
1007 */
1008 init_var(&arg1);
1009 init_var(&arg2);
1010
1011 set_var_from_num(num1, &arg1);
1012 set_var_from_num(num2, &arg2);
1013
1014 if (cmp_var(&arg1, &arg2) >= 0)
1015 res = make_result(&arg1);
1016 else
1017 res = make_result(&arg2);
1018
1019 free_var(&arg1);
1020 free_var(&arg2);
1021
1022 return res;
1023 }
1024
1025 /* ----------------------------------------------------------------------
1026 *
1027 * Complex math functions
1028 *
1029 * ----------------------------------------------------------------------
1030 * numeric_sqrt() -
1031 *
1032 * Compute the square root of a numeric.
1033 * ----------
1034 */
1035 Numeric
numeric_sqrt(Numeric num,int * global_rscale,Decimal_Exception * ex)1036 numeric_sqrt(Numeric num, int *global_rscale, Decimal_Exception *ex) {
1037 Numeric res;
1038 NumericVar arg;
1039 NumericVar result;
1040 int res_dscale;
1041
1042 *ex = No_Error;
1043
1044 /*
1045 * Handle NaN
1046 */
1047 if (NUMERIC_IS_NAN(num))
1048 return make_result(&const_nan);
1049
1050 /*
1051 * Unpack the argument, determine the scales like for divide, let
1052 * sqrt_var() do the calculation and return the result.
1053 */
1054 init_var(&arg);
1055 init_var(&result);
1056
1057 set_var_from_num(num, &arg);
1058
1059 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1060 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1061 *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1062 *global_rscale = MAX(*global_rscale, res_dscale + 4);
1063 *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE);
1064
1065 sqrt_var(&arg, &result, global_rscale, ex);
1066
1067 result.dscale = res_dscale;
1068
1069 res = make_result(&result);
1070
1071 free_var(&result);
1072 free_var(&arg);
1073
1074 return res;
1075 }
1076
1077 /* ----------
1078 * numeric_exp() -
1079 *
1080 * Raise e to the power of x
1081 * ----------
1082 */
1083 Numeric
numeric_exp(Numeric num,int * global_rscale,Decimal_Exception * ex)1084 numeric_exp(Numeric num, int *global_rscale, Decimal_Exception *ex) {
1085 Numeric res;
1086 NumericVar arg;
1087 NumericVar result;
1088 int res_dscale;
1089
1090 *ex = No_Error;
1091
1092 /*
1093 * Handle NaN
1094 */
1095 if (NUMERIC_IS_NAN(num))
1096 return make_result(&const_nan);
1097
1098 /*
1099 * Same procedure like for sqrt().
1100 */
1101 init_var(&arg);
1102 init_var(&result);
1103 set_var_from_num(num, &arg);
1104
1105 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1106 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1107 *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1108 *global_rscale = MAX(*global_rscale, res_dscale + 4);
1109 *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE);
1110
1111 exp_var(&arg, &result, global_rscale, ex);
1112
1113 result.dscale = res_dscale;
1114
1115 res = make_result(&result);
1116
1117 free_var(&result);
1118 free_var(&arg);
1119
1120 return res;
1121 }
1122
1123
1124 /* ----------
1125 * numeric_ln() -
1126 *
1127 * Compute the natural logarithm of x
1128 * ----------
1129 */
1130 Numeric
numeric_ln(Numeric num,int * global_rscale,Decimal_Exception * ex)1131 numeric_ln(Numeric num, int *global_rscale, Decimal_Exception *ex) {
1132 Numeric res;
1133 NumericVar arg;
1134 NumericVar result;
1135 int res_dscale;
1136
1137 *ex = No_Error;
1138
1139 /*
1140 * Handle NaN
1141 */
1142 if (NUMERIC_IS_NAN(num))
1143 return make_result(&const_nan);
1144
1145 /*
1146 * Same procedure like for sqrt()
1147 */
1148 init_var(&arg);
1149 init_var(&result);
1150 set_var_from_num(num, &arg);
1151
1152 res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1153 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1154 *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1155 *global_rscale = MAX(*global_rscale, res_dscale + 4);
1156 *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE);
1157
1158 ln_var(&arg, &result, global_rscale, ex);
1159 if ( *ex == No_Error )
1160 result.dscale = res_dscale;
1161
1162 res = make_result(&result);
1163
1164 free_var(&result);
1165 free_var(&arg);
1166
1167 return res;
1168 }
1169
1170
1171 /* ----------
1172 * numeric_log() -
1173 *
1174 * Compute the logarithm of x in a given base
1175 * ----------
1176 */
1177 Numeric
numeric_log(Numeric num1,Numeric num2,int * global_rscale,Decimal_Exception * ex)1178 numeric_log(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) {
1179 Numeric res;
1180 NumericVar arg1;
1181 NumericVar arg2;
1182 NumericVar result;
1183 int res_dscale;
1184
1185 *ex = No_Error;
1186
1187 /*
1188 * Handle NaN
1189 */
1190 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1191 return make_result(&const_nan);
1192
1193 /*
1194 * Initialize things and calculate scales
1195 */
1196 init_var(&arg1);
1197 init_var(&arg2);
1198 init_var(&result);
1199 set_var_from_num(num1, &arg1);
1200 set_var_from_num(num2, &arg2);
1201
1202 res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1203 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1204 *global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1205 *global_rscale = MAX(*global_rscale, res_dscale + 4);
1206 *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE);
1207
1208 /*
1209 * Call log_var() to compute and return the result
1210 */
1211 log_var(&arg1, &arg2, &result, global_rscale, ex);
1212
1213 if ( *ex == No_Error )
1214 result.dscale = res_dscale;
1215
1216 res = make_result(&result);
1217
1218 free_var(&result);
1219 free_var(&arg2);
1220 free_var(&arg1);
1221
1222 return res;
1223 }
1224
1225
1226 /* ----------
1227 * numeric_power() -
1228 *
1229 * Raise m to the power of x
1230 * ----------
1231 */
1232 Numeric
numeric_power(Numeric num1,Numeric num2,int * global_rscale,Decimal_Exception * ex)1233 numeric_power(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) {
1234 Numeric res;
1235 NumericVar arg1;
1236 NumericVar arg2;
1237 NumericVar result;
1238 int res_dscale;
1239
1240 *ex = No_Error;
1241
1242 /*
1243 * Handle NaN
1244 */
1245 if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1246 return make_result(&const_nan);
1247
1248 /*
1249 * Initialize things and calculate scales
1250 */
1251 init_var(&arg1);
1252 init_var(&arg2);
1253 init_var(&result);
1254 set_var_from_num(num1, &arg1);
1255 set_var_from_num(num2, &arg2);
1256
1257 res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1258 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1259 *global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1260 *global_rscale = MAX(*global_rscale, res_dscale + 4);
1261 *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE);
1262
1263 /*
1264 * Call log_var() to compute and return the result
1265 */
1266 power_var(&arg1, &arg2, &result, global_rscale, ex);
1267
1268 if ( *ex == No_Error )
1269 result.dscale = res_dscale;
1270
1271 res = make_result(&result);
1272
1273 free_var(&result);
1274 free_var(&arg2);
1275 free_var(&arg1);
1276
1277 return res;
1278 }
1279
1280
1281 /* ----------------------------------------------------------------------
1282 *
1283 * Local functions follow
1284 *
1285 * ----------------------------------------------------------------------
1286 */
1287
1288 #ifdef NUMERIC_DEBUG
1289
1290 /* ----------
1291 * dump_numeric() - Dump a value in the db storage format for debugging
1292 * ----------
1293 */
1294 static void
dump_numeric(char * str,Numeric num)1295 dump_numeric(char *str, Numeric num)
1296 {
1297 int i;
1298
1299 printf("%s: NUMERIC w=%d r=%d d=%d ", str, num->n_weight, num->n_rscale,
1300 NUMERIC_DSCALE(num));
1301 switch (NUMERIC_SIGN(num))
1302 {
1303 case NUMERIC_POS:
1304 printf("POS");
1305 break;
1306 case NUMERIC_NEG:
1307 printf("NEG");
1308 break;
1309 case NUMERIC_NAN:
1310 printf("NaN");
1311 break;
1312 default:
1313 printf("SIGN=0x%x", NUMERIC_SIGN(num));
1314 break;
1315 }
1316
1317 for (i = 0; i < num->varlen - NUMERIC_HDRSZ; i++)
1318 printf(" %d %d", (num->n_data[i] >> 4) & 0x0f, num->n_data[i] & 0x0f);
1319 printf("\n");
1320 }
1321
1322 /* ----------
1323 * dump_var() - Dump a value in the variable format for debugging
1324 * ----------
1325 */
1326 static void
dump_var(char * str,NumericVar * var)1327 dump_var(char *str, NumericVar *var)
1328 {
1329 int i;
1330
1331 printf("%s: VAR w=%d r=%d d=%d ", str, var->weight, var->rscale,
1332 var->dscale);
1333 switch (var->sign)
1334 {
1335 case NUMERIC_POS:
1336 printf("POS");
1337 break;
1338 case NUMERIC_NEG:
1339 printf("NEG");
1340 break;
1341 case NUMERIC_NAN:
1342 printf("NaN");
1343 break;
1344 default:
1345 printf("SIGN=0x%x", var->sign);
1346 break;
1347 }
1348
1349 for (i = 0; i < var->ndigits; i++)
1350 printf(" %d", var->digits[i]);
1351
1352 printf("\n");
1353 }
1354 #endif /* NUMERIC_DEBUG */
1355
1356
1357 /* ----------
1358 * alloc_var() -
1359 *
1360 * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
1361 * ----------
1362 */
1363 static void
alloc_var(NumericVar * var,int ndigits)1364 alloc_var(NumericVar *var, int ndigits)
1365 {
1366 digitbuf_free(var->buf);
1367 var->buf = digitbuf_alloc(ndigits + 1);
1368 var->buf[0] = 0;
1369 var->digits = var->buf + 1;
1370 var->ndigits = ndigits;
1371 }
1372
1373 /* ----------
1374 * free_var() -
1375 *
1376 * Return the digit buffer of a variable to the free pool
1377 * ----------
1378 */
1379 static void
free_var(NumericVar * var)1380 free_var(NumericVar *var)
1381 {
1382 digitbuf_free(var->buf);
1383 var->buf = NULL;
1384 var->digits = NULL;
1385 var->sign = NUMERIC_NAN;
1386 }
1387
1388 /* ----------
1389 * zero_var() -
1390 *
1391 * Set a variable to ZERO.
1392 * Note: rscale and dscale are not touched.
1393 * ----------
1394 */
1395 static void
zero_var(NumericVar * var)1396 zero_var(NumericVar *var)
1397 {
1398 digitbuf_free(var->buf);
1399 var->buf = NULL;
1400 var->digits = NULL;
1401 var->ndigits = 0;
1402 var->weight = 0; /* by convention; doesn't really matter */
1403 var->sign = NUMERIC_POS; /* anything but NAN... */
1404 }
1405
1406 /* ----------
1407 * set_var_from_str()
1408 *
1409 * Parse a string and put the number into a variable
1410 * ----------
1411 */
1412 static void
set_var_from_str(const char * str,NumericVar * dest,Decimal_Exception * ex)1413 set_var_from_str(const char *str, NumericVar *dest, Decimal_Exception *ex) {
1414 char *cp = (char *) str;
1415 bool have_dp = FALSE;
1416 int i = 0;
1417 bool bad_format = FALSE;
1418
1419 while (*cp)
1420 {
1421 if (!isspace((unsigned char) *cp))
1422 break;
1423 cp++;
1424 }
1425
1426 alloc_var(dest, strlen(cp));
1427 dest->weight = -1;
1428 dest->dscale = 0;
1429 dest->sign = NUMERIC_POS;
1430
1431 switch (*cp)
1432 {
1433 case '+':
1434 dest->sign = NUMERIC_POS;
1435 cp++;
1436 break;
1437
1438 case '-':
1439 dest->sign = NUMERIC_NEG;
1440 cp++;
1441 break;
1442 }
1443
1444 if (*cp == '.')
1445 {
1446 have_dp = TRUE;
1447 cp++;
1448 }
1449
1450 if (!isdigit((unsigned char) *cp))
1451 bad_format = TRUE; /* Bad format exception */
1452
1453 while (*cp)
1454 {
1455 if (isdigit((unsigned char) *cp))
1456 {
1457 dest->digits[i++] = *cp++ - '0';
1458 if (!have_dp)
1459 dest->weight++;
1460 else
1461 dest->dscale++;
1462 }
1463 else if (*cp == '.')
1464 {
1465 if (have_dp)
1466 bad_format = TRUE;
1467 have_dp = TRUE;
1468 cp++;
1469 }
1470 else
1471 break;
1472 }
1473 dest->ndigits = i;
1474
1475 /* Handle exponent, if any */
1476 if (*cp == 'e' || *cp == 'E')
1477 {
1478 long exponent;
1479 char *endptr;
1480
1481 cp++;
1482 exponent = strtol(cp, &endptr, 10);
1483 if (endptr == cp)
1484 bad_format = TRUE;
1485 cp = endptr;
1486 if (exponent > NUMERIC_MAX_PRECISION ||
1487 exponent < -NUMERIC_MAX_PRECISION)
1488 bad_format = TRUE;
1489 dest->weight += (int) exponent;
1490 dest->dscale -= (int) exponent;
1491 if (dest->dscale < 0)
1492 dest->dscale = 0;
1493 }
1494
1495 /* Should be nothing left but spaces */
1496 while (*cp)
1497 {
1498 if (!isspace((unsigned char) *cp))
1499 bad_format = TRUE;
1500 cp++;
1501 }
1502
1503 /* Strip any leading zeroes */
1504 while (dest->ndigits > 0 && *(dest->digits) == 0)
1505 {
1506 (dest->digits)++;
1507 (dest->weight)--;
1508 (dest->ndigits)--;
1509 }
1510 if (dest->ndigits == 0)
1511 dest->weight = 0;
1512
1513 dest->rscale = dest->dscale;
1514
1515 if ( bad_format )
1516 *ex = Numeric_Format; /* Bad format exception */
1517 }
1518
1519 /*
1520 * set_var_from_num() -
1521 *
1522 * Parse back the packed db format into a variable
1523 *
1524 */
1525 static void
set_var_from_num(Numeric num,NumericVar * dest)1526 set_var_from_num(Numeric num, NumericVar *dest)
1527 {
1528 NumericDigit *digit;
1529 int i;
1530 int n;
1531
1532 n = num->varlen - NUMERIC_HDRSZ; /* number of digit-pairs in packed
1533 * fmt */
1534
1535 alloc_var(dest, n * 2);
1536
1537 dest->weight = num->n_weight;
1538 dest->rscale = num->n_rscale;
1539 dest->dscale = NUMERIC_DSCALE(num);
1540 dest->sign = NUMERIC_SIGN(num);
1541
1542 digit = dest->digits;
1543
1544 for (i = 0; i < n; i++)
1545 {
1546 unsigned char digitpair = num->n_data[i];
1547
1548 *digit++ = (digitpair >> 4) & 0x0f;
1549 *digit++ = digitpair & 0x0f;
1550 }
1551 }
1552
1553 /* ----------
1554 * set_var_from_var() -
1555 *
1556 * Copy one variable into another
1557 * ----------
1558 */
1559 static void
set_var_from_var(NumericVar * value,NumericVar * dest)1560 set_var_from_var(NumericVar *value, NumericVar *dest)
1561 {
1562 NumericDigit *newbuf;
1563
1564 newbuf = digitbuf_alloc(value->ndigits + 1);
1565 newbuf[0] = 0; /* spare digit for rounding */
1566 memcpy(newbuf + 1, value->digits, value->ndigits);
1567
1568 digitbuf_free(dest->buf);
1569
1570 memcpy(dest, value, sizeof(NumericVar));
1571 dest->buf = newbuf;
1572 dest->digits = newbuf + 1;
1573 }
1574
1575 /* ----------
1576 * get_str_from_var() -
1577 *
1578 * Convert a var to text representation (guts of numeric_out).
1579 * CAUTION: var's contents may be modified by rounding!
1580 * Caller must have checked for NaN case.
1581 * Returns a palloc'd string.
1582 * ----------
1583 */
1584 static char *
get_str_from_var(NumericVar * var,int dscale)1585 get_str_from_var(NumericVar *var, int dscale)
1586 {
1587 char *str;
1588 char *cp;
1589 int i;
1590 int d;
1591
1592 /*
1593 * Check if we must round up before printing the value and do so.
1594 */
1595 i = dscale + var->weight + 1;
1596 if (i >= 0 && var->ndigits > i) {
1597 int carry = (var->digits[i] > 4) ? 1 : 0;
1598
1599 var->ndigits = i;
1600
1601 while (carry)
1602 {
1603 carry += var->digits[--i];
1604 var->digits[i] = carry % 10;
1605 carry /= 10;
1606 }
1607
1608 if (i < 0)
1609 {
1610 Assert(i == -1); /* better not have added more than 1 digit */
1611 Assert(var->digits > var->buf);
1612 var->digits--;
1613 var->ndigits++;
1614 var->weight++;
1615 }
1616 }
1617 else
1618 var->ndigits = MAX(0, MIN(i, var->ndigits));
1619
1620 /*
1621 * Allocate space for the result
1622 */
1623 str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4);
1624 cp = str;
1625
1626 /*
1627 * Output a dash for negative values
1628 */
1629 if (var->sign == NUMERIC_NEG)
1630 *cp++ = '-';
1631
1632 /*
1633 * Output all digits before the decimal point
1634 */
1635 i = MAX(var->weight, 0);
1636 d = 0;
1637
1638 while (i >= 0)
1639 {
1640 if (i <= var->weight && d < var->ndigits)
1641 *cp++ = var->digits[d++] + '0';
1642 else
1643 *cp++ = '0';
1644 i--;
1645 }
1646
1647 /*
1648 * If requested, output a decimal point and all the digits that follow
1649 * it.
1650 */
1651 if (dscale > 0)
1652 {
1653 *cp++ = '.';
1654 while (i >= -dscale)
1655 {
1656 if (i <= var->weight && d < var->ndigits)
1657 *cp++ = var->digits[d++] + '0';
1658 else
1659 *cp++ = '0';
1660 i--;
1661 }
1662 }
1663
1664 /*
1665 * terminate the string and return it
1666 */
1667 *cp = '\0';
1668 return str;
1669 }
1670
1671 Numeric
numeric_nan(void)1672 numeric_nan(void) {
1673 Numeric num = (Numeric) palloc(NUMERIC_HDRSZ);
1674
1675 num->varlen = NUMERIC_HDRSZ;
1676 num->n_weight = 0;
1677 num->n_rscale = 0;
1678 num->n_sign_dscale = NUMERIC_NAN;
1679
1680 return num;
1681 }
1682
1683 /* ----------
1684 * make_result() -
1685 *
1686 * Create the packed db numeric format in palloc()'d memory from
1687 * a variable. The var's rscale determines the number of digits kept.
1688 * ----------
1689 */
1690 static Numeric
make_result(NumericVar * var)1691 make_result(NumericVar *var)
1692 {
1693 Numeric result;
1694 NumericDigit *digit = var->digits;
1695 int weight = var->weight;
1696 int sign = var->sign;
1697 int n;
1698 int i,
1699 j;
1700
1701 if (sign == NUMERIC_NAN)
1702 {
1703 return numeric_nan();
1704 return result;
1705 }
1706
1707 n = MAX(0, MIN(var->ndigits, var->weight + var->rscale + 1));
1708
1709 /* truncate leading zeroes */
1710 while (n > 0 && *digit == 0)
1711 {
1712 digit++;
1713 weight--;
1714 n--;
1715 }
1716 /* truncate trailing zeroes */
1717 while (n > 0 && digit[n - 1] == 0)
1718 n--;
1719
1720 /* If zero result, force to weight=0 and positive sign */
1721 if (n == 0)
1722 {
1723 weight = 0;
1724 sign = NUMERIC_POS;
1725 }
1726
1727 result = (Numeric) palloc(NUMERIC_HDRSZ + (n + 1) / 2);
1728 result->varlen = NUMERIC_HDRSZ + (n + 1) / 2;
1729 result->n_weight = weight;
1730 result->n_rscale = var->rscale;
1731 result->n_sign_dscale = sign |
1732 ((uint16) var->dscale & NUMERIC_DSCALE_MASK);
1733
1734 i = 0;
1735 j = 0;
1736 while (j < n)
1737 {
1738 unsigned char digitpair = digit[j++] << 4;
1739
1740 if (j < n)
1741 digitpair |= digit[j++];
1742 result->n_data[i++] = digitpair;
1743 }
1744
1745 dump_numeric("make_result()", result);
1746 return result;
1747 }
1748
1749 /* ----------
1750 * apply_typmod() -
1751 *
1752 * Do bounds checking and rounding according to the attributes
1753 * typmod field.
1754 * ----------
1755 */
1756 static void
apply_typmod(NumericVar * var,int precision,int scale,Decimal_Exception * ex)1757 apply_typmod(NumericVar *var, int precision, int scale, Decimal_Exception *ex) {
1758 int maxweight;
1759 int i;
1760
1761 maxweight = precision - scale;
1762
1763 /* Round to target scale */
1764 i = scale + var->weight + 1;
1765 if (i >= 0 && var->ndigits > i) {
1766 int carry = (var->digits[i] > 4) ? 1 : 0;
1767
1768 var->ndigits = i;
1769
1770 while (carry)
1771 {
1772 carry += var->digits[--i];
1773 var->digits[i] = carry % 10;
1774 carry /= 10;
1775 }
1776
1777 if (i < 0)
1778 {
1779 Assert(i == -1); /* better not have added more than 1 digit */
1780 Assert(var->digits > var->buf);
1781 var->digits--;
1782 var->ndigits++;
1783 var->weight++;
1784 }
1785 } else
1786 var->ndigits = MAX(0, MIN(i, var->ndigits));
1787
1788 /*
1789 * Check for overflow - note we can't do this before rounding, because
1790 * rounding could raise the weight. Also note that the var's weight
1791 * could be inflated by leading zeroes, which will be stripped before
1792 * storage but perhaps might not have been yet. In any case, we must
1793 * recognize a true zero, whose weight doesn't mean anything.
1794 */
1795 if (var->weight >= maxweight) {
1796 /* Determine true weight; and check for all-zero result */
1797 int tweight = var->weight;
1798
1799 for (i = 0; i < var->ndigits; i++)
1800 {
1801 if (var->digits[i])
1802 break;
1803 tweight--;
1804 }
1805
1806 if ( tweight >= maxweight && i < var->ndigits )
1807 *ex = Numeric_Overflow; /* Overflow exception */
1808 }
1809
1810 if ( *ex == No_Error ) {
1811 var->rscale = scale;
1812 var->dscale = scale;
1813 } else
1814 nan_var(var);
1815 }
1816
1817 /* ----------
1818 * cmp_var() -
1819 *
1820 * Compare two values on variable level
1821 * ----------
1822 */
1823 static int
cmp_var(NumericVar * var1,NumericVar * var2)1824 cmp_var(NumericVar *var1, NumericVar *var2)
1825 {
1826 if (var1->ndigits == 0)
1827 {
1828 if (var2->ndigits == 0)
1829 return 0;
1830 if (var2->sign == NUMERIC_NEG)
1831 return 1;
1832 return -1;
1833 }
1834 if (var2->ndigits == 0)
1835 {
1836 if (var1->sign == NUMERIC_POS)
1837 return 1;
1838 return -1;
1839 }
1840
1841 if (var1->sign == NUMERIC_POS)
1842 {
1843 if (var2->sign == NUMERIC_NEG)
1844 return 1;
1845 return cmp_abs(var1, var2);
1846 }
1847
1848 if (var2->sign == NUMERIC_POS)
1849 return -1;
1850
1851 return cmp_abs(var2, var1);
1852 }
1853
1854 /* ----------
1855 * add_var() -
1856 *
1857 * Full version of add functionality on variable level (handling signs).
1858 * result might point to one of the operands too without danger.
1859 * ----------
1860 */
1861 static void
add_var(NumericVar * var1,NumericVar * var2,NumericVar * result)1862 add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
1863 {
1864 /*
1865 * Decide on the signs of the two variables what to do
1866 */
1867 if (var1->sign == NUMERIC_POS)
1868 {
1869 if (var2->sign == NUMERIC_POS)
1870 {
1871 /*
1872 * Both are positive result = +(ABS(var1) + ABS(var2))
1873 */
1874 add_abs(var1, var2, result);
1875 result->sign = NUMERIC_POS;
1876 }
1877 else
1878 {
1879 /*
1880 * var1 is positive, var2 is negative Must compare absolute
1881 * values
1882 */
1883 switch (cmp_abs(var1, var2))
1884 {
1885 case 0:
1886 /* ----------
1887 * ABS(var1) == ABS(var2)
1888 * result = ZERO
1889 * ----------
1890 */
1891 zero_var(result);
1892 result->rscale = MAX(var1->rscale, var2->rscale);
1893 result->dscale = MAX(var1->dscale, var2->dscale);
1894 break;
1895
1896 case 1:
1897 /* ----------
1898 * ABS(var1) > ABS(var2)
1899 * result = +(ABS(var1) - ABS(var2))
1900 * ----------
1901 */
1902 sub_abs(var1, var2, result);
1903 result->sign = NUMERIC_POS;
1904 break;
1905
1906 case -1:
1907 /* ----------
1908 * ABS(var1) < ABS(var2)
1909 * result = -(ABS(var2) - ABS(var1))
1910 * ----------
1911 */
1912 sub_abs(var2, var1, result);
1913 result->sign = NUMERIC_NEG;
1914 break;
1915 }
1916 }
1917 }
1918 else
1919 {
1920 if (var2->sign == NUMERIC_POS)
1921 {
1922 /* ----------
1923 * var1 is negative, var2 is positive
1924 * Must compare absolute values
1925 * ----------
1926 */
1927 switch (cmp_abs(var1, var2))
1928 {
1929 case 0:
1930 /* ----------
1931 * ABS(var1) == ABS(var2)
1932 * result = ZERO
1933 * ----------
1934 */
1935 zero_var(result);
1936 result->rscale = MAX(var1->rscale, var2->rscale);
1937 result->dscale = MAX(var1->dscale, var2->dscale);
1938 break;
1939
1940 case 1:
1941 /* ----------
1942 * ABS(var1) > ABS(var2)
1943 * result = -(ABS(var1) - ABS(var2))
1944 * ----------
1945 */
1946 sub_abs(var1, var2, result);
1947 result->sign = NUMERIC_NEG;
1948 break;
1949
1950 case -1:
1951 /* ----------
1952 * ABS(var1) < ABS(var2)
1953 * result = +(ABS(var2) - ABS(var1))
1954 * ----------
1955 */
1956 sub_abs(var2, var1, result);
1957 result->sign = NUMERIC_POS;
1958 break;
1959 }
1960 }
1961 else
1962 {
1963 /* ----------
1964 * Both are negative
1965 * result = -(ABS(var1) + ABS(var2))
1966 * ----------
1967 */
1968 add_abs(var1, var2, result);
1969 result->sign = NUMERIC_NEG;
1970 }
1971 }
1972 }
1973
1974 /* ----------
1975 * sub_var() -
1976 *
1977 * Full version of sub functionality on variable level (handling signs).
1978 * result might point to one of the operands too without danger.
1979 * ----------
1980 */
1981 static void
sub_var(NumericVar * var1,NumericVar * var2,NumericVar * result)1982 sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
1983 {
1984 /*
1985 * Decide on the signs of the two variables what to do
1986 */
1987 if (var1->sign == NUMERIC_POS)
1988 {
1989 if (var2->sign == NUMERIC_NEG)
1990 {
1991 /* ----------
1992 * var1 is positive, var2 is negative
1993 * result = +(ABS(var1) + ABS(var2))
1994 * ----------
1995 */
1996 add_abs(var1, var2, result);
1997 result->sign = NUMERIC_POS;
1998 }
1999 else
2000 {
2001 /* ----------
2002 * Both are positive
2003 * Must compare absolute values
2004 * ----------
2005 */
2006 switch (cmp_abs(var1, var2))
2007 {
2008 case 0:
2009 /* ----------
2010 * ABS(var1) == ABS(var2)
2011 * result = ZERO
2012 * ----------
2013 */
2014 zero_var(result);
2015 result->rscale = MAX(var1->rscale, var2->rscale);
2016 result->dscale = MAX(var1->dscale, var2->dscale);
2017 break;
2018
2019 case 1:
2020 /* ----------
2021 * ABS(var1) > ABS(var2)
2022 * result = +(ABS(var1) - ABS(var2))
2023 * ----------
2024 */
2025 sub_abs(var1, var2, result);
2026 result->sign = NUMERIC_POS;
2027 break;
2028
2029 case -1:
2030 /* ----------
2031 * ABS(var1) < ABS(var2)
2032 * result = -(ABS(var2) - ABS(var1))
2033 * ----------
2034 */
2035 sub_abs(var2, var1, result);
2036 result->sign = NUMERIC_NEG;
2037 break;
2038 }
2039 }
2040 }
2041 else
2042 {
2043 if (var2->sign == NUMERIC_NEG)
2044 {
2045 /* ----------
2046 * Both are negative
2047 * Must compare absolute values
2048 * ----------
2049 */
2050 switch (cmp_abs(var1, var2))
2051 {
2052 case 0:
2053 /* ----------
2054 * ABS(var1) == ABS(var2)
2055 * result = ZERO
2056 * ----------
2057 */
2058 zero_var(result);
2059 result->rscale = MAX(var1->rscale, var2->rscale);
2060 result->dscale = MAX(var1->dscale, var2->dscale);
2061 break;
2062
2063 case 1:
2064 /* ----------
2065 * ABS(var1) > ABS(var2)
2066 * result = -(ABS(var1) - ABS(var2))
2067 * ----------
2068 */
2069 sub_abs(var1, var2, result);
2070 result->sign = NUMERIC_NEG;
2071 break;
2072
2073 case -1:
2074 /* ----------
2075 * ABS(var1) < ABS(var2)
2076 * result = +(ABS(var2) - ABS(var1))
2077 * ----------
2078 */
2079 sub_abs(var2, var1, result);
2080 result->sign = NUMERIC_POS;
2081 break;
2082 }
2083 }
2084 else
2085 {
2086 /* ----------
2087 * var1 is negative, var2 is positive
2088 * result = -(ABS(var1) + ABS(var2))
2089 * ----------
2090 */
2091 add_abs(var1, var2, result);
2092 result->sign = NUMERIC_NEG;
2093 }
2094 }
2095 }
2096
2097 /* ----------
2098 * mul_var() -
2099 *
2100 * Multiplication on variable level. Product of var1 * var2 is stored
2101 * in result.
2102 * ----------
2103 */
2104 static void
mul_var(NumericVar * var1,NumericVar * var2,NumericVar * result,int * global_rscale)2105 mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale)
2106 {
2107 NumericDigit *res_buf;
2108 NumericDigit *res_digits;
2109 int res_ndigits;
2110 int res_weight;
2111 int res_sign;
2112 int i,
2113 ri,
2114 i1,
2115 i2;
2116 long sum = 0;
2117
2118 res_weight = var1->weight + var2->weight + 2;
2119 res_ndigits = var1->ndigits + var2->ndigits + 1;
2120 if (var1->sign == var2->sign)
2121 res_sign = NUMERIC_POS;
2122 else
2123 res_sign = NUMERIC_NEG;
2124
2125 res_buf = digitbuf_alloc(res_ndigits);
2126 res_digits = res_buf;
2127 memset(res_digits, 0, res_ndigits);
2128
2129 ri = res_ndigits;
2130 for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
2131 {
2132 sum = 0;
2133 i = --ri;
2134
2135 for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
2136 {
2137 sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
2138 res_digits[i--] = sum % 10;
2139 sum /= 10;
2140 }
2141 res_digits[i] = sum;
2142 }
2143
2144 i = res_weight + *global_rscale + 2;
2145 if (i >= 0 && i < res_ndigits)
2146 {
2147 sum = (res_digits[i] > 4) ? 1 : 0;
2148 res_ndigits = i;
2149 i--;
2150 while (sum)
2151 {
2152 sum += res_digits[i];
2153 res_digits[i--] = sum % 10;
2154 sum /= 10;
2155 }
2156 }
2157
2158 while (res_ndigits > 0 && *res_digits == 0)
2159 {
2160 res_digits++;
2161 res_weight--;
2162 res_ndigits--;
2163 }
2164 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
2165 res_ndigits--;
2166
2167 if (res_ndigits == 0)
2168 {
2169 res_sign = NUMERIC_POS;
2170 res_weight = 0;
2171 }
2172
2173 digitbuf_free(result->buf);
2174 result->buf = res_buf;
2175 result->digits = res_digits;
2176 result->ndigits = res_ndigits;
2177 result->weight = res_weight;
2178 result->rscale = *global_rscale;
2179 result->sign = res_sign;
2180 }
2181
2182 /* ----------
2183 * div_var() -
2184 *
2185 * Division on variable level.
2186 * ----------
2187 */
2188 static void
div_var(NumericVar * var1,NumericVar * var2,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2189 div_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2190 {
2191 NumericDigit *res_digits;
2192 int res_ndigits;
2193 int res_sign;
2194 int res_weight;
2195 NumericVar dividend;
2196 NumericVar divisor[10];
2197 int ndigits_tmp;
2198 int weight_tmp;
2199 int rscale_tmp;
2200 int ri;
2201 int i;
2202 long guess;
2203 long first_have;
2204 long first_div;
2205 int first_nextdigit;
2206 int stat = 0;
2207
2208 /*
2209 * First of all division by zero check
2210 */
2211 ndigits_tmp = var2->ndigits + 1;
2212 if (ndigits_tmp == 1) {
2213 *ex = Divide_By_Zero;
2214 nan_var(result);
2215 return;
2216 }
2217
2218 /*
2219 * Determine the result sign, weight and number of digits to calculate
2220 */
2221 if (var1->sign == var2->sign)
2222 res_sign = NUMERIC_POS;
2223 else
2224 res_sign = NUMERIC_NEG;
2225 res_weight = var1->weight - var2->weight + 1;
2226 res_ndigits = *global_rscale + res_weight;
2227 if (res_ndigits <= 0)
2228 res_ndigits = 1;
2229
2230 /*
2231 * Now result zero check
2232 */
2233 if (var1->ndigits == 0)
2234 {
2235 zero_var(result);
2236 result->rscale = *global_rscale;
2237 return;
2238 }
2239
2240 /*
2241 * Initialize local variables
2242 */
2243 init_var(÷nd);
2244 for (i = 1; i < 10; i++)
2245 init_var(&divisor[i]);
2246
2247 /*
2248 * Make a copy of the divisor which has one leading zero digit
2249 */
2250 divisor[1].ndigits = ndigits_tmp;
2251 divisor[1].rscale = var2->ndigits;
2252 divisor[1].sign = NUMERIC_POS;
2253 divisor[1].buf = digitbuf_alloc(ndigits_tmp);
2254 divisor[1].digits = divisor[1].buf;
2255 divisor[1].digits[0] = 0;
2256 memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
2257
2258 /*
2259 * Make a copy of the dividend
2260 */
2261 dividend.ndigits = var1->ndigits;
2262 dividend.weight = 0;
2263 dividend.rscale = var1->ndigits;
2264 dividend.sign = NUMERIC_POS;
2265 dividend.buf = digitbuf_alloc(var1->ndigits);
2266 dividend.digits = dividend.buf;
2267 memcpy(dividend.digits, var1->digits, var1->ndigits);
2268
2269 /*
2270 * Setup the result
2271 */
2272 digitbuf_free(result->buf);
2273 result->buf = digitbuf_alloc(res_ndigits + 2);
2274 res_digits = result->buf;
2275 result->digits = res_digits;
2276 result->ndigits = res_ndigits;
2277 result->weight = res_weight;
2278 result->rscale = *global_rscale;
2279 result->sign = res_sign;
2280 res_digits[0] = 0;
2281
2282 first_div = divisor[1].digits[1] * 10;
2283 if (ndigits_tmp > 2)
2284 first_div += divisor[1].digits[2];
2285
2286 first_have = 0;
2287 first_nextdigit = 0;
2288
2289 weight_tmp = 1;
2290 rscale_tmp = divisor[1].rscale;
2291
2292 for (ri = 0; ri <= res_ndigits; ri++)
2293 {
2294 first_have = first_have * 10;
2295 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
2296 first_have += dividend.digits[first_nextdigit];
2297 first_nextdigit++;
2298
2299 guess = (first_have * 10) / first_div + 1;
2300 if (guess > 9)
2301 guess = 9;
2302
2303 while (guess > 0)
2304 {
2305 if (divisor[guess].buf == NULL)
2306 {
2307 int i;
2308 long sum = 0;
2309
2310 memcpy(&divisor[guess], &divisor[1], sizeof(NumericVar));
2311 divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
2312 divisor[guess].digits = divisor[guess].buf;
2313 for (i = divisor[1].ndigits - 1; i >= 0; i--)
2314 {
2315 sum += divisor[1].digits[i] * guess;
2316 divisor[guess].digits[i] = sum % 10;
2317 sum /= 10;
2318 }
2319 }
2320
2321 divisor[guess].weight = weight_tmp;
2322 divisor[guess].rscale = rscale_tmp;
2323
2324 stat = cmp_abs(÷nd, &divisor[guess]);
2325 if (stat >= 0)
2326 break;
2327
2328 guess--;
2329 }
2330
2331 res_digits[ri + 1] = guess;
2332 if (stat == 0)
2333 {
2334 ri++;
2335 break;
2336 }
2337
2338 weight_tmp--;
2339 rscale_tmp++;
2340
2341 if (guess == 0)
2342 continue;
2343
2344 sub_abs(÷nd, &divisor[guess], ÷nd);
2345
2346 first_nextdigit = dividend.weight - weight_tmp;
2347 first_have = 0;
2348 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
2349 first_have = dividend.digits[first_nextdigit];
2350 first_nextdigit++;
2351 }
2352
2353 result->ndigits = ri + 1;
2354 if (ri == res_ndigits + 1)
2355 {
2356 int carry = (res_digits[ri] > 4) ? 1 : 0;
2357
2358 result->ndigits = ri;
2359 res_digits[ri] = 0;
2360
2361 while (carry && ri > 0)
2362 {
2363 carry += res_digits[--ri];
2364 res_digits[ri] = carry % 10;
2365 carry /= 10;
2366 }
2367 }
2368
2369 while (result->ndigits > 0 && *(result->digits) == 0)
2370 {
2371 (result->digits)++;
2372 (result->weight)--;
2373 (result->ndigits)--;
2374 }
2375 while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
2376 (result->ndigits)--;
2377 if (result->ndigits == 0)
2378 result->sign = NUMERIC_POS;
2379
2380 /*
2381 * Tidy up
2382 */
2383 digitbuf_free(dividend.buf);
2384 for (i = 1; i < 10; i++)
2385 digitbuf_free(divisor[i].buf);
2386 }
2387
2388
2389 /*
2390 * Default scale selection for division
2391 *
2392 * Returns the appropriate display scale for the division result,
2393 * and sets global_rscale to the result scale to use during div_var.
2394 *
2395 * Note that this must be called before div_var.
2396 */
2397 static int
select_div_scale(NumericVar * var1,NumericVar * var2,int * global_rscale)2398 select_div_scale(NumericVar *var1, NumericVar *var2, int *global_rscale)
2399 {
2400 int res_dscale;
2401 int res_rscale;
2402
2403 /* ----------
2404 * The result scale of a division isn't specified in any
2405 * SQL standard. For Postgres it is the following (where
2406 * SR, DR are the result- and display-scales of the returned
2407 * value, S1, D1, S2 and D2 are the scales of the two arguments,
2408 * The minimum and maximum scales are compile time options from
2409 * numeric.h):
2410 *
2411 * DR = MIN(MAX(D1 + D2, MIN_DISPLAY_SCALE), MAX_DISPLAY_SCALE)
2412 * SR = MIN(MAX(MAX(S1 + S2, DR + 4), MIN_RESULT_SCALE), MAX_RESULT_SCALE)
2413 *
2414 * By default, any result is computed with a minimum of 34 digits
2415 * after the decimal point or at least with 4 digits more than
2416 * displayed.
2417 * ----------
2418 */
2419 res_dscale = var1->dscale + var2->dscale;
2420 res_dscale = MAX(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
2421 res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
2422
2423 res_rscale = var1->rscale + var2->rscale;
2424 res_rscale = MAX(res_rscale, res_dscale + 4);
2425 res_rscale = MAX(res_rscale, NUMERIC_MIN_RESULT_SCALE);
2426 res_rscale = MIN(res_rscale, NUMERIC_MAX_RESULT_SCALE);
2427 *global_rscale = res_rscale;
2428
2429 return res_dscale;
2430 }
2431
2432 /* ----------
2433 * mod_var() -
2434 *
2435 * Calculate the modulo of two numerics at variable level
2436 * ----------
2437 */
2438 static void
mod_var(NumericVar * var1,NumericVar * var2,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2439 mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2440 {
2441 NumericVar tmp;
2442 int save_global_rscale;
2443 int div_dscale;
2444
2445 *ex = No_Error;
2446
2447 init_var(&tmp);
2448
2449 /* ---------
2450 * We do this using the equation
2451 * mod(x,y) = x - trunc(x/y)*y
2452 * We set global_rscale the same way numeric_div and numeric_mul do
2453 * to get the right answer from the equation. The final result,
2454 * however, need not be displayed to more precision than the inputs.
2455 * ----------
2456 */
2457 save_global_rscale = *global_rscale;
2458
2459 div_dscale = select_div_scale(var1, var2, global_rscale);
2460
2461 div_var(var1, var2, &tmp, global_rscale, ex);
2462 if ( *ex == No_Error ) {
2463 tmp.dscale = div_dscale;
2464
2465 /* do trunc() by forgetting digits to the right of the decimal point */
2466 tmp.ndigits = MAX(0, MIN(tmp.ndigits, tmp.weight + 1));
2467
2468 *global_rscale = var2->rscale + tmp.rscale;
2469
2470 mul_var(var2, &tmp, &tmp, global_rscale);
2471
2472 sub_var(var1, &tmp, result);
2473
2474 result->dscale = MAX(var1->dscale, var2->dscale);
2475
2476 *global_rscale = save_global_rscale;
2477 }
2478 free_var(&tmp);
2479 }
2480
2481 /* ----------
2482 * ceil_var() -
2483 *
2484 * Return the smallest integer greater than or equal to the argument
2485 * on variable level
2486 * ----------
2487 */
2488 static void
ceil_var(NumericVar * var,NumericVar * result)2489 ceil_var(NumericVar *var, NumericVar *result)
2490 {
2491 NumericVar tmp;
2492
2493 init_var(&tmp);
2494 set_var_from_var(var, &tmp);
2495
2496 tmp.rscale = 0;
2497 tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
2498 if (tmp.sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
2499 add_var(&tmp, &const_one, &tmp);
2500
2501 set_var_from_var(&tmp, result);
2502 free_var(&tmp);
2503 }
2504
2505 /* ----------
2506 * floor_var() -
2507 *
2508 * Return the largest integer equal to or less than the argument
2509 * on variable level
2510 * ----------
2511 */
2512 static void
floor_var(NumericVar * var,NumericVar * result)2513 floor_var(NumericVar *var, NumericVar *result)
2514 {
2515 NumericVar tmp;
2516
2517 init_var(&tmp);
2518 set_var_from_var(var, &tmp);
2519
2520 tmp.rscale = 0;
2521 tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
2522 if (tmp.sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
2523 sub_var(&tmp, &const_one, &tmp);
2524
2525 set_var_from_var(&tmp, result);
2526 free_var(&tmp);
2527 }
2528
2529 /* ----------
2530 * sqrt_var() -
2531 *
2532 * Compute the square root of x using Newtons algorithm
2533 * ----------
2534 */
2535 static void
sqrt_var(NumericVar * arg,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2536 sqrt_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2537 {
2538 NumericVar tmp_arg;
2539 NumericVar tmp_val;
2540 NumericVar last_val;
2541 int res_rscale;
2542 int save_global_rscale;
2543 int stat;
2544
2545 save_global_rscale = *global_rscale;
2546 *global_rscale += 8;
2547 res_rscale = *global_rscale;
2548
2549 stat = cmp_var(arg, &const_zero);
2550 if (stat == 0)
2551 {
2552 set_var_from_var(&const_zero, result);
2553 result->rscale = res_rscale;
2554 result->sign = NUMERIC_POS;
2555 return;
2556 }
2557
2558 if (stat < 0) {
2559 *ex = Undefined_Result;
2560 nan_var(result);
2561 return;
2562 }
2563
2564 init_var(&tmp_arg);
2565 init_var(&tmp_val);
2566 init_var(&last_val);
2567
2568 set_var_from_var(arg, &tmp_arg);
2569 set_var_from_var(result, &last_val);
2570
2571 /*
2572 * Initialize the result to the first guess
2573 */
2574 digitbuf_free(result->buf);
2575 result->buf = digitbuf_alloc(1);
2576 result->digits = result->buf;
2577 result->digits[0] = tmp_arg.digits[0] / 2;
2578 if (result->digits[0] == 0)
2579 result->digits[0] = 1;
2580 result->ndigits = 1;
2581 result->weight = tmp_arg.weight / 2;
2582 result->rscale = res_rscale;
2583 result->sign = NUMERIC_POS;
2584
2585 for (;;)
2586 {
2587 div_var(&tmp_arg, result, &tmp_val, global_rscale, ex);
2588 if ( *ex != No_Error )
2589 break;
2590
2591 add_var(result, &tmp_val, result);
2592 div_var(result, &const_two, result, global_rscale, ex);
2593 if ( *ex != No_Error )
2594 break;
2595
2596 if (cmp_var(&last_val, result) == 0)
2597 break;
2598 set_var_from_var(result, &last_val);
2599 }
2600
2601 free_var(&last_val);
2602 free_var(&tmp_val);
2603 free_var(&tmp_arg);
2604
2605 if ( *ex == No_Error ) {
2606 *global_rscale = save_global_rscale;
2607 div_var(result, &const_one, result, global_rscale, ex);
2608 }
2609
2610 if ( *ex != No_Error )
2611 nan_var(result); /* Set NAN if any exception occurred */
2612 }
2613
2614 /* ----------
2615 * exp_var() -
2616 *
2617 * Raise e to the power of x
2618 * ----------
2619 */
2620 static void
exp_var(NumericVar * arg,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2621 exp_var(NumericVar *arg, NumericVar *result,int *global_rscale, Decimal_Exception *ex)
2622 {
2623 NumericVar x;
2624 NumericVar xpow;
2625 NumericVar ifac;
2626 NumericVar elem;
2627 NumericVar ni;
2628 int d;
2629 int i;
2630 int ndiv2 = 0;
2631 bool xneg = FALSE;
2632 int save_global_rscale;
2633
2634 init_var(&x);
2635 init_var(&xpow);
2636 init_var(&ifac);
2637 init_var(&elem);
2638 init_var(&ni);
2639
2640 set_var_from_var(arg, &x);
2641
2642 if (x.sign == NUMERIC_NEG)
2643 {
2644 xneg = TRUE;
2645 x.sign = NUMERIC_POS;
2646 }
2647
2648 save_global_rscale = *global_rscale;
2649 *global_rscale = 0;
2650 for (i = x.weight, d = 0; i >= 0; i--, d++)
2651 {
2652 *global_rscale *= 10;
2653 if (d < x.ndigits)
2654 *global_rscale += x.digits[d];
2655 if (*global_rscale >= 1000) {
2656 *ex = Numeric_Overflow; /* argument for EXP() too big */
2657 nan_var(result);
2658 return;
2659 }
2660 }
2661
2662 *global_rscale = *global_rscale / 2 + save_global_rscale + 8;
2663
2664 while (cmp_var(&x, &const_one) > 0)
2665 {
2666 ndiv2++;
2667 (*global_rscale)++;
2668 div_var(&x, &const_two, &x, global_rscale, ex);
2669 if ( *ex != No_Error )
2670 break;
2671 }
2672
2673 if ( *ex == No_Error ) {
2674 add_var(&const_one, &x, result);
2675 set_var_from_var(&x, &xpow);
2676 set_var_from_var(&const_one, &ifac);
2677 set_var_from_var(&const_one, &ni);
2678
2679 for (i = 2;; i++)
2680 {
2681 add_var(&ni, &const_one, &ni);
2682 mul_var(&xpow, &x, &xpow, global_rscale);
2683 mul_var(&ifac, &ni, &ifac, global_rscale);
2684 div_var(&xpow, &ifac, &elem, global_rscale, ex);
2685 if ( *ex != No_Error )
2686 break;
2687
2688 if (elem.ndigits == 0)
2689 break;
2690
2691 add_var(result, &elem, result);
2692 }
2693 }
2694
2695 if ( *ex == No_Error ) {
2696
2697 while (ndiv2-- > 0)
2698 mul_var(result, result, result, global_rscale);
2699
2700 *global_rscale = save_global_rscale;
2701 if (xneg)
2702 div_var(&const_one, result, result, global_rscale, ex);
2703 else
2704 div_var(result, &const_one, result, global_rscale, ex);
2705
2706 if ( *ex == No_Error )
2707 result->sign = NUMERIC_POS;
2708 }
2709
2710 free_var(&x);
2711 free_var(&xpow);
2712 free_var(&ifac);
2713 free_var(&elem);
2714 free_var(&ni);
2715
2716 if ( *ex != No_Error )
2717 nan_var(result);
2718 }
2719
2720 /* ----------
2721 * ln_var() -
2722 *
2723 * Compute the natural log of x
2724 * ----------
2725 */
2726 static void
ln_var(NumericVar * arg,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2727 ln_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2728 {
2729 NumericVar x;
2730 NumericVar xx;
2731 NumericVar ni;
2732 NumericVar elem;
2733 NumericVar fact;
2734 int i;
2735 int save_global_rscale;
2736
2737 if (cmp_var(arg, &const_zero) <= 0) {
2738 /* math error on numeric - cannot compute LN of value <= zero */
2739 *ex = Numeric_Overflow;
2740 nan_var(result);
2741 return;
2742 }
2743
2744 save_global_rscale = *global_rscale;
2745 *global_rscale += 8;
2746
2747 init_var(&x);
2748 init_var(&xx);
2749 init_var(&ni);
2750 init_var(&elem);
2751 init_var(&fact);
2752
2753 set_var_from_var(&const_two, &fact);
2754 set_var_from_var(arg, &x);
2755
2756 while (cmp_var(&x, &const_two) >= 0)
2757 {
2758 sqrt_var(&x, &x, global_rscale, ex);
2759 if ( *ex != No_Error )
2760 break;
2761 mul_var(&fact, &const_two, &fact, global_rscale);
2762 }
2763
2764 if ( *ex == No_Error ) {
2765 set_var_from_str("0.5", &elem, ex); /* This won't raise exception */
2766 while (cmp_var(&x, &elem) <= 0)
2767 {
2768 sqrt_var(&x, &x, global_rscale, ex);
2769 if ( *ex != No_Error )
2770 break;
2771 mul_var(&fact, &const_two, &fact, global_rscale);
2772 }
2773 }
2774
2775 if ( *ex == No_Error ) {
2776 sub_var(&x, &const_one, result);
2777 add_var(&x, &const_one, &elem);
2778 div_var(result, &elem, result, global_rscale, ex);
2779 }
2780
2781 if ( *ex == No_Error ) {
2782 set_var_from_var(result, &xx);
2783 mul_var(result, result, &x, global_rscale);
2784
2785 set_var_from_var(&const_one, &ni);
2786
2787 for (i = 2;; i++)
2788 {
2789 add_var(&ni, &const_two, &ni);
2790 mul_var(&xx, &x, &xx, global_rscale);
2791 div_var(&xx, &ni, &elem, global_rscale, ex);
2792 if ( *ex != No_Error )
2793 break;
2794 if (cmp_var(&elem, &const_zero) == 0)
2795 break;
2796
2797 add_var(result, &elem, result);
2798 }
2799 }
2800
2801 if ( *ex == No_Error ) {
2802 *global_rscale = save_global_rscale;
2803 mul_var(result, &fact, result, global_rscale);
2804 }
2805
2806 free_var(&x);
2807 free_var(&xx);
2808 free_var(&ni);
2809 free_var(&elem);
2810 free_var(&fact);
2811
2812 if ( *ex != No_Error )
2813 nan_var(result);
2814 }
2815
2816 /* ----------
2817 * log_var() -
2818 *
2819 * Compute the logarithm of x in a given base
2820 * ----------
2821 */
2822 static void
log_var(NumericVar * base,NumericVar * num,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2823 log_var(NumericVar *base, NumericVar *num, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2824 {
2825 NumericVar ln_base;
2826 NumericVar ln_num;
2827
2828 *global_rscale += 8;
2829
2830 init_var(&ln_base);
2831 init_var(&ln_num);
2832
2833 ln_var(base, &ln_base, global_rscale, ex);
2834 if ( *ex == No_Error )
2835 ln_var(num, &ln_num, global_rscale, ex);
2836
2837 if ( *ex == No_Error ) {
2838 *global_rscale -= 8;
2839
2840 div_var(&ln_num, &ln_base, result, global_rscale, ex);
2841 }
2842
2843 free_var(&ln_num);
2844 free_var(&ln_base);
2845
2846 if ( *ex != No_Error )
2847 nan_var(result);
2848 }
2849
2850 /* ----------
2851 * power_var() -
2852 *
2853 * Raise base to the power of exp
2854 * ----------
2855 */
2856 static void
power_var(NumericVar * base,NumericVar * exp,NumericVar * result,int * global_rscale,Decimal_Exception * ex)2857 power_var(NumericVar *base, NumericVar *exp, NumericVar *result, int *global_rscale, Decimal_Exception *ex)
2858 {
2859 NumericVar ln_base;
2860 NumericVar ln_num;
2861 int save_global_rscale;
2862
2863 save_global_rscale = *global_rscale;
2864 *global_rscale += *global_rscale / 3 + 8;
2865
2866 init_var(&ln_base);
2867 init_var(&ln_num);
2868
2869 ln_var(base, &ln_base, global_rscale, ex);
2870
2871 if ( *ex == No_Error ) {
2872 mul_var(&ln_base, exp, &ln_num, global_rscale);
2873 *global_rscale = save_global_rscale;
2874
2875 exp_var(&ln_num, result, global_rscale, ex);
2876 }
2877
2878 free_var(&ln_num);
2879 free_var(&ln_base);
2880
2881 if ( *ex != No_Error )
2882 nan_var(result);
2883 }
2884
2885 /* ----------------------------------------------------------------------
2886 *
2887 * Following are the lowest level functions that operate unsigned
2888 * on the variable level
2889 *
2890 * ----------------------------------------------------------------------
2891 */
2892
2893 /* ----------
2894 * cmp_abs() -
2895 *
2896 * Compare the absolute values of var1 and var2
2897 * Returns: -1 for ABS(var1) < ABS(var2)
2898 * 0 for ABS(var1) == ABS(var2)
2899 * 1 for ABS(var1) > ABS(var2)
2900 * ----------
2901 */
2902 static int
cmp_abs(NumericVar * var1,NumericVar * var2)2903 cmp_abs(NumericVar *var1, NumericVar *var2)
2904 {
2905 int i1 = 0;
2906 int i2 = 0;
2907 int w1 = var1->weight;
2908 int w2 = var2->weight;
2909 int stat;
2910
2911 while (w1 > w2 && i1 < var1->ndigits)
2912 {
2913 if (var1->digits[i1++] != 0)
2914 return 1;
2915 w1--;
2916 }
2917 while (w2 > w1 && i2 < var2->ndigits)
2918 {
2919 if (var2->digits[i2++] != 0)
2920 return -1;
2921 w2--;
2922 }
2923
2924 if (w1 == w2)
2925 {
2926 while (i1 < var1->ndigits && i2 < var2->ndigits)
2927 {
2928 stat = var1->digits[i1++] - var2->digits[i2++];
2929 if (stat)
2930 {
2931 if (stat > 0)
2932 return 1;
2933 return -1;
2934 }
2935 }
2936 }
2937
2938 while (i1 < var1->ndigits)
2939 {
2940 if (var1->digits[i1++] != 0)
2941 return 1;
2942 }
2943 while (i2 < var2->ndigits)
2944 {
2945 if (var2->digits[i2++] != 0)
2946 return -1;
2947 }
2948
2949 return 0;
2950 }
2951
2952 /* ----------
2953 * add_abs() -
2954 *
2955 * Add the absolute values of two variables into result.
2956 * result might point to one of the operands without danger.
2957 * ----------
2958 */
2959 static void
add_abs(NumericVar * var1,NumericVar * var2,NumericVar * result)2960 add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
2961 {
2962 NumericDigit *res_buf;
2963 NumericDigit *res_digits;
2964 int res_ndigits;
2965 int res_weight;
2966 int res_rscale;
2967 int res_dscale;
2968 int i,
2969 i1,
2970 i2;
2971 int carry = 0;
2972
2973 /* copy these values into local vars for speed in inner loop */
2974 int var1ndigits = var1->ndigits;
2975 int var2ndigits = var2->ndigits;
2976 NumericDigit *var1digits = var1->digits;
2977 NumericDigit *var2digits = var2->digits;
2978
2979 res_weight = MAX(var1->weight, var2->weight) + 1;
2980 res_rscale = MAX(var1->rscale, var2->rscale);
2981 res_dscale = MAX(var1->dscale, var2->dscale);
2982 res_ndigits = res_rscale + res_weight + 1;
2983 if (res_ndigits <= 0)
2984 res_ndigits = 1;
2985
2986 res_buf = digitbuf_alloc(res_ndigits);
2987 res_digits = res_buf;
2988
2989 i1 = res_rscale + var1->weight + 1;
2990 i2 = res_rscale + var2->weight + 1;
2991 for (i = res_ndigits - 1; i >= 0; i--)
2992 {
2993 i1--;
2994 i2--;
2995 if (i1 >= 0 && i1 < var1ndigits)
2996 carry += var1digits[i1];
2997 if (i2 >= 0 && i2 < var2ndigits)
2998 carry += var2digits[i2];
2999
3000 if (carry >= 10)
3001 {
3002 res_digits[i] = carry - 10;
3003 carry = 1;
3004 }
3005 else
3006 {
3007 res_digits[i] = carry;
3008 carry = 0;
3009 }
3010 }
3011
3012 Assert(carry == 0); /* else we failed to allow for carry out */
3013
3014 while (res_ndigits > 0 && *res_digits == 0)
3015 {
3016 res_digits++;
3017 res_weight--;
3018 res_ndigits--;
3019 }
3020 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3021 res_ndigits--;
3022
3023 if (res_ndigits == 0)
3024 res_weight = 0;
3025
3026 digitbuf_free(result->buf);
3027 result->ndigits = res_ndigits;
3028 result->buf = res_buf;
3029 result->digits = res_digits;
3030 result->weight = res_weight;
3031 result->rscale = res_rscale;
3032 result->dscale = res_dscale;
3033 }
3034
3035 /* ----------
3036 * sub_abs() -
3037 *
3038 * Subtract the absolute value of var2 from the absolute value of var1
3039 * and store in result. result might point to one of the operands
3040 * without danger.
3041 *
3042 * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
3043 * ----------
3044 */
3045 static void
sub_abs(NumericVar * var1,NumericVar * var2,NumericVar * result)3046 sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
3047 {
3048 NumericDigit *res_buf;
3049 NumericDigit *res_digits;
3050 int res_ndigits;
3051 int res_weight;
3052 int res_rscale;
3053 int res_dscale;
3054 int i,
3055 i1,
3056 i2;
3057 int borrow = 0;
3058
3059 /* copy these values into local vars for speed in inner loop */
3060 int var1ndigits = var1->ndigits;
3061 int var2ndigits = var2->ndigits;
3062 NumericDigit *var1digits = var1->digits;
3063 NumericDigit *var2digits = var2->digits;
3064
3065 res_weight = var1->weight;
3066 res_rscale = MAX(var1->rscale, var2->rscale);
3067 res_dscale = MAX(var1->dscale, var2->dscale);
3068 res_ndigits = res_rscale + res_weight + 1;
3069 if (res_ndigits <= 0)
3070 res_ndigits = 1;
3071
3072 res_buf = digitbuf_alloc(res_ndigits);
3073 res_digits = res_buf;
3074
3075 i1 = res_rscale + var1->weight + 1;
3076 i2 = res_rscale + var2->weight + 1;
3077 for (i = res_ndigits - 1; i >= 0; i--)
3078 {
3079 i1--;
3080 i2--;
3081 if (i1 >= 0 && i1 < var1ndigits)
3082 borrow += var1digits[i1];
3083 if (i2 >= 0 && i2 < var2ndigits)
3084 borrow -= var2digits[i2];
3085
3086 if (borrow < 0)
3087 {
3088 res_digits[i] = borrow + 10;
3089 borrow = -1;
3090 }
3091 else
3092 {
3093 res_digits[i] = borrow;
3094 borrow = 0;
3095 }
3096 }
3097
3098 Assert(borrow == 0); /* else caller gave us var1 < var2 */
3099
3100 while (res_ndigits > 0 && *res_digits == 0)
3101 {
3102 res_digits++;
3103 res_weight--;
3104 res_ndigits--;
3105 }
3106 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3107 res_ndigits--;
3108
3109 if (res_ndigits == 0)
3110 res_weight = 0;
3111
3112 digitbuf_free(result->buf);
3113 result->ndigits = res_ndigits;
3114 result->buf = res_buf;
3115 result->digits = res_digits;
3116 result->weight = res_weight;
3117 result->rscale = res_rscale;
3118 result->dscale = res_dscale;
3119 }
3120
3121
3122