00001
00002
00003 #include "postgres_fe.h"
00004 #include <ctype.h>
00005 #include <limits.h>
00006
00007 #include "extern.h"
00008 #include "pgtypes_error.h"
00009
00010 #define Max(x, y) ((x) > (y) ? (x) : (y))
00011 #define Min(x, y) ((x) < (y) ? (x) : (y))
00012
00013 #define init_var(v) memset(v,0,sizeof(numeric))
00014
00015 #define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))
00016 #define digitbuf_free(buf) \
00017 do { \
00018 if ((buf) != NULL) \
00019 free(buf); \
00020 } while (0)
00021
00022 #include "pgtypes_numeric.h"
00023
00024 #if 0
00025
00026
00027
00028
00029
00030
00031
00032 static int
00033 apply_typmod(numeric *var, long typmod)
00034 {
00035 int precision;
00036 int scale;
00037 int maxweight;
00038 int i;
00039
00040
00041 if (typmod < (long) (VARHDRSZ))
00042 return (0);
00043
00044 typmod -= VARHDRSZ;
00045 precision = (typmod >> 16) & 0xffff;
00046 scale = typmod & 0xffff;
00047 maxweight = precision - scale;
00048
00049
00050 i = scale + var->weight + 1;
00051 if (i >= 0 && var->ndigits > i)
00052 {
00053 int carry = (var->digits[i] > 4) ? 1 : 0;
00054
00055 var->ndigits = i;
00056
00057 while (carry)
00058 {
00059 carry += var->digits[--i];
00060 var->digits[i] = carry % 10;
00061 carry /= 10;
00062 }
00063
00064 if (i < 0)
00065 {
00066 var->digits--;
00067 var->ndigits++;
00068 var->weight++;
00069 }
00070 }
00071 else
00072 var->ndigits = Max(0, Min(i, var->ndigits));
00073
00074
00075
00076
00077
00078
00079
00080
00081 if (var->weight >= maxweight)
00082 {
00083
00084 int tweight = var->weight;
00085
00086 for (i = 0; i < var->ndigits; i++)
00087 {
00088 if (var->digits[i])
00089 break;
00090 tweight--;
00091 }
00092
00093 if (tweight >= maxweight && i < var->ndigits)
00094 {
00095 errno = PGTYPES_NUM_OVERFLOW;
00096 return -1;
00097 }
00098 }
00099
00100 var->rscale = scale;
00101 var->dscale = scale;
00102 return (0);
00103 }
00104 #endif
00105
00106
00107
00108
00109
00110
00111
00112 static int
00113 alloc_var(numeric *var, int ndigits)
00114 {
00115 digitbuf_free(var->buf);
00116 var->buf = digitbuf_alloc(ndigits + 1);
00117 if (var->buf == NULL)
00118 return -1;
00119 var->buf[0] = 0;
00120 var->digits = var->buf + 1;
00121 var->ndigits = ndigits;
00122 return 0;
00123 }
00124
00125 numeric *
00126 PGTYPESnumeric_new(void)
00127 {
00128 numeric *var;
00129
00130 if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
00131 return NULL;
00132
00133 if (alloc_var(var, 0) < 0)
00134 {
00135 free(var);
00136 return NULL;
00137 }
00138
00139 return var;
00140 }
00141
00142 decimal *
00143 PGTYPESdecimal_new(void)
00144 {
00145 decimal *var;
00146
00147 if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
00148 return NULL;
00149
00150 memset(var, 0, sizeof(decimal));
00151
00152 return var;
00153 }
00154
00155
00156
00157
00158
00159
00160
00161 static int
00162 set_var_from_str(char *str, char **ptr, numeric *dest)
00163 {
00164 bool have_dp = FALSE;
00165 int i = 0;
00166
00167 errno = 0;
00168 *ptr = str;
00169 while (*(*ptr))
00170 {
00171 if (!isspace((unsigned char) *(*ptr)))
00172 break;
00173 (*ptr)++;
00174 }
00175
00176 if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
00177 {
00178 *ptr += 3;
00179 dest->sign = NUMERIC_NAN;
00180
00181
00182 while (*(*ptr))
00183 {
00184 if (!isspace((unsigned char) *(*ptr)))
00185 {
00186 errno = PGTYPES_NUM_BAD_NUMERIC;
00187 return -1;
00188 }
00189 (*ptr)++;
00190 }
00191
00192 return 0;
00193 }
00194
00195 if (alloc_var(dest, strlen((*ptr))) < 0)
00196 return -1;
00197 dest->weight = -1;
00198 dest->dscale = 0;
00199 dest->sign = NUMERIC_POS;
00200
00201 switch (*(*ptr))
00202 {
00203 case '+':
00204 dest->sign = NUMERIC_POS;
00205 (*ptr)++;
00206 break;
00207
00208 case '-':
00209 dest->sign = NUMERIC_NEG;
00210 (*ptr)++;
00211 break;
00212 }
00213
00214 if (*(*ptr) == '.')
00215 {
00216 have_dp = TRUE;
00217 (*ptr)++;
00218 }
00219
00220 if (!isdigit((unsigned char) *(*ptr)))
00221 {
00222 errno = PGTYPES_NUM_BAD_NUMERIC;
00223 return -1;
00224 }
00225
00226 while (*(*ptr))
00227 {
00228 if (isdigit((unsigned char) *(*ptr)))
00229 {
00230 dest->digits[i++] = *(*ptr)++ - '0';
00231 if (!have_dp)
00232 dest->weight++;
00233 else
00234 dest->dscale++;
00235 }
00236 else if (*(*ptr) == '.')
00237 {
00238 if (have_dp)
00239 {
00240 errno = PGTYPES_NUM_BAD_NUMERIC;
00241 return -1;
00242 }
00243 have_dp = TRUE;
00244 (*ptr)++;
00245 }
00246 else
00247 break;
00248 }
00249 dest->ndigits = i;
00250
00251
00252 if (*(*ptr) == 'e' || *(*ptr) == 'E')
00253 {
00254 long exponent;
00255 char *endptr;
00256
00257 (*ptr)++;
00258 exponent = strtol(*ptr, &endptr, 10);
00259 if (endptr == (*ptr))
00260 {
00261 errno = PGTYPES_NUM_BAD_NUMERIC;
00262 return -1;
00263 }
00264 (*ptr) = endptr;
00265 if (exponent > NUMERIC_MAX_PRECISION ||
00266 exponent < -NUMERIC_MAX_PRECISION)
00267 {
00268 errno = PGTYPES_NUM_BAD_NUMERIC;
00269 return -1;
00270 }
00271 dest->weight += (int) exponent;
00272 dest->dscale -= (int) exponent;
00273 if (dest->dscale < 0)
00274 dest->dscale = 0;
00275 }
00276
00277
00278 while (*(*ptr))
00279 {
00280 if (!isspace((unsigned char) *(*ptr)))
00281 {
00282 errno = PGTYPES_NUM_BAD_NUMERIC;
00283 return -1;
00284 }
00285 (*ptr)++;
00286 }
00287
00288
00289 while (dest->ndigits > 0 && *(dest->digits) == 0)
00290 {
00291 (dest->digits)++;
00292 (dest->weight)--;
00293 (dest->ndigits)--;
00294 }
00295 if (dest->ndigits == 0)
00296 dest->weight = 0;
00297
00298 dest->rscale = dest->dscale;
00299 return (0);
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 static char *
00311 get_str_from_var(numeric *var, int dscale)
00312 {
00313 char *str;
00314 char *cp;
00315 int i;
00316 int d;
00317
00318 if (var->sign == NUMERIC_NAN)
00319 {
00320 str = (char *) pgtypes_alloc(4);
00321 if (str == NULL)
00322 return NULL;
00323 sprintf(str, "NaN");
00324 return str;
00325 }
00326
00327
00328
00329
00330 i = dscale + var->weight + 1;
00331 if (i >= 0 && var->ndigits > i)
00332 {
00333 int carry = (var->digits[i] > 4) ? 1 : 0;
00334
00335 var->ndigits = i;
00336
00337 while (carry)
00338 {
00339 carry += var->digits[--i];
00340 var->digits[i] = carry % 10;
00341 carry /= 10;
00342 }
00343
00344 if (i < 0)
00345 {
00346 var->digits--;
00347 var->ndigits++;
00348 var->weight++;
00349 }
00350 }
00351 else
00352 var->ndigits = Max(0, Min(i, var->ndigits));
00353
00354
00355
00356
00357 if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
00358 return NULL;
00359 cp = str;
00360
00361
00362
00363
00364 if (var->sign == NUMERIC_NEG)
00365 *cp++ = '-';
00366
00367
00368
00369
00370 i = Max(var->weight, 0);
00371 d = 0;
00372
00373 while (i >= 0)
00374 {
00375 if (i <= var->weight && d < var->ndigits)
00376 *cp++ = var->digits[d++] + '0';
00377 else
00378 *cp++ = '0';
00379 i--;
00380 }
00381
00382
00383
00384
00385 if (dscale > 0)
00386 {
00387 *cp++ = '.';
00388 while (i >= -dscale)
00389 {
00390 if (i <= var->weight && d < var->ndigits)
00391 *cp++ = var->digits[d++] + '0';
00392 else
00393 *cp++ = '0';
00394 i--;
00395 }
00396 }
00397
00398
00399
00400
00401 *cp = '\0';
00402 return str;
00403 }
00404
00405 numeric *
00406 PGTYPESnumeric_from_asc(char *str, char **endptr)
00407 {
00408 numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
00409 int ret;
00410
00411 char *realptr;
00412 char **ptr = (endptr != NULL) ? endptr : &realptr;
00413
00414 if (!value)
00415 return (NULL);
00416
00417 ret = set_var_from_str(str, ptr, value);
00418 if (ret)
00419 {
00420 PGTYPESnumeric_free(value);
00421 return (NULL);
00422 }
00423
00424 return (value);
00425 }
00426
00427 char *
00428 PGTYPESnumeric_to_asc(numeric *num, int dscale)
00429 {
00430 numeric *numcopy = PGTYPESnumeric_new();
00431 char *s;
00432
00433 if (dscale < 0)
00434 dscale = num->dscale;
00435
00436 if (PGTYPESnumeric_copy(num, numcopy) < 0)
00437 {
00438 PGTYPESnumeric_free(numcopy);
00439 return NULL;
00440 }
00441
00442 s = get_str_from_var(numcopy, dscale);
00443 PGTYPESnumeric_free(numcopy);
00444 return (s);
00445 }
00446
00447
00448
00449
00450
00451
00452
00453
00454 static void
00455 zero_var(numeric *var)
00456 {
00457 digitbuf_free(var->buf);
00458 var->buf = NULL;
00459 var->digits = NULL;
00460 var->ndigits = 0;
00461 var->weight = 0;
00462 var->sign = NUMERIC_POS;
00463 }
00464
00465 void
00466 PGTYPESnumeric_free(numeric *var)
00467 {
00468 digitbuf_free(var->buf);
00469 free(var);
00470 }
00471
00472 void
00473 PGTYPESdecimal_free(decimal *var)
00474 {
00475 free(var);
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 static int
00488 cmp_abs(numeric *var1, numeric *var2)
00489 {
00490 int i1 = 0;
00491 int i2 = 0;
00492 int w1 = var1->weight;
00493 int w2 = var2->weight;
00494 int stat;
00495
00496 while (w1 > w2 && i1 < var1->ndigits)
00497 {
00498 if (var1->digits[i1++] != 0)
00499 return 1;
00500 w1--;
00501 }
00502 while (w2 > w1 && i2 < var2->ndigits)
00503 {
00504 if (var2->digits[i2++] != 0)
00505 return -1;
00506 w2--;
00507 }
00508
00509 if (w1 == w2)
00510 {
00511 while (i1 < var1->ndigits && i2 < var2->ndigits)
00512 {
00513 stat = var1->digits[i1++] - var2->digits[i2++];
00514 if (stat)
00515 {
00516 if (stat > 0)
00517 return 1;
00518 return -1;
00519 }
00520 }
00521 }
00522
00523 while (i1 < var1->ndigits)
00524 {
00525 if (var1->digits[i1++] != 0)
00526 return 1;
00527 }
00528 while (i2 < var2->ndigits)
00529 {
00530 if (var2->digits[i2++] != 0)
00531 return -1;
00532 }
00533
00534 return 0;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 static int
00546 add_abs(numeric *var1, numeric *var2, numeric *result)
00547 {
00548 NumericDigit *res_buf;
00549 NumericDigit *res_digits;
00550 int res_ndigits;
00551 int res_weight;
00552 int res_rscale;
00553 int res_dscale;
00554 int i,
00555 i1,
00556 i2;
00557 int carry = 0;
00558
00559
00560 int var1ndigits = var1->ndigits;
00561 int var2ndigits = var2->ndigits;
00562 NumericDigit *var1digits = var1->digits;
00563 NumericDigit *var2digits = var2->digits;
00564
00565 res_weight = Max(var1->weight, var2->weight) + 1;
00566 res_rscale = Max(var1->rscale, var2->rscale);
00567 res_dscale = Max(var1->dscale, var2->dscale);
00568 res_ndigits = res_rscale + res_weight + 1;
00569 if (res_ndigits <= 0)
00570 res_ndigits = 1;
00571
00572 if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
00573 return -1;
00574 res_digits = res_buf;
00575
00576 i1 = res_rscale + var1->weight + 1;
00577 i2 = res_rscale + var2->weight + 1;
00578 for (i = res_ndigits - 1; i >= 0; i--)
00579 {
00580 i1--;
00581 i2--;
00582 if (i1 >= 0 && i1 < var1ndigits)
00583 carry += var1digits[i1];
00584 if (i2 >= 0 && i2 < var2ndigits)
00585 carry += var2digits[i2];
00586
00587 if (carry >= 10)
00588 {
00589 res_digits[i] = carry - 10;
00590 carry = 1;
00591 }
00592 else
00593 {
00594 res_digits[i] = carry;
00595 carry = 0;
00596 }
00597 }
00598
00599 while (res_ndigits > 0 && *res_digits == 0)
00600 {
00601 res_digits++;
00602 res_weight--;
00603 res_ndigits--;
00604 }
00605 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
00606 res_ndigits--;
00607
00608 if (res_ndigits == 0)
00609 res_weight = 0;
00610
00611 digitbuf_free(result->buf);
00612 result->ndigits = res_ndigits;
00613 result->buf = res_buf;
00614 result->digits = res_digits;
00615 result->weight = res_weight;
00616 result->rscale = res_rscale;
00617 result->dscale = res_dscale;
00618
00619 return 0;
00620 }
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 static int
00634 sub_abs(numeric *var1, numeric *var2, numeric *result)
00635 {
00636 NumericDigit *res_buf;
00637 NumericDigit *res_digits;
00638 int res_ndigits;
00639 int res_weight;
00640 int res_rscale;
00641 int res_dscale;
00642 int i,
00643 i1,
00644 i2;
00645 int borrow = 0;
00646
00647
00648 int var1ndigits = var1->ndigits;
00649 int var2ndigits = var2->ndigits;
00650 NumericDigit *var1digits = var1->digits;
00651 NumericDigit *var2digits = var2->digits;
00652
00653 res_weight = var1->weight;
00654 res_rscale = Max(var1->rscale, var2->rscale);
00655 res_dscale = Max(var1->dscale, var2->dscale);
00656 res_ndigits = res_rscale + res_weight + 1;
00657 if (res_ndigits <= 0)
00658 res_ndigits = 1;
00659
00660 if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
00661 return -1;
00662 res_digits = res_buf;
00663
00664 i1 = res_rscale + var1->weight + 1;
00665 i2 = res_rscale + var2->weight + 1;
00666 for (i = res_ndigits - 1; i >= 0; i--)
00667 {
00668 i1--;
00669 i2--;
00670 if (i1 >= 0 && i1 < var1ndigits)
00671 borrow += var1digits[i1];
00672 if (i2 >= 0 && i2 < var2ndigits)
00673 borrow -= var2digits[i2];
00674
00675 if (borrow < 0)
00676 {
00677 res_digits[i] = borrow + 10;
00678 borrow = -1;
00679 }
00680 else
00681 {
00682 res_digits[i] = borrow;
00683 borrow = 0;
00684 }
00685 }
00686
00687 while (res_ndigits > 0 && *res_digits == 0)
00688 {
00689 res_digits++;
00690 res_weight--;
00691 res_ndigits--;
00692 }
00693 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
00694 res_ndigits--;
00695
00696 if (res_ndigits == 0)
00697 res_weight = 0;
00698
00699 digitbuf_free(result->buf);
00700 result->ndigits = res_ndigits;
00701 result->buf = res_buf;
00702 result->digits = res_digits;
00703 result->weight = res_weight;
00704 result->rscale = res_rscale;
00705 result->dscale = res_dscale;
00706
00707 return 0;
00708 }
00709
00710
00711
00712
00713
00714
00715
00716
00717 int
00718 PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
00719 {
00720
00721
00722
00723 if (var1->sign == NUMERIC_POS)
00724 {
00725 if (var2->sign == NUMERIC_POS)
00726 {
00727
00728
00729
00730 if (add_abs(var1, var2, result) != 0)
00731 return -1;
00732 result->sign = NUMERIC_POS;
00733 }
00734 else
00735 {
00736
00737
00738
00739 switch (cmp_abs(var1, var2))
00740 {
00741 case 0:
00742
00743
00744
00745
00746
00747 zero_var(result);
00748 result->rscale = Max(var1->rscale, var2->rscale);
00749 result->dscale = Max(var1->dscale, var2->dscale);
00750 break;
00751
00752 case 1:
00753
00754
00755
00756
00757
00758 if (sub_abs(var1, var2, result) != 0)
00759 return -1;
00760 result->sign = NUMERIC_POS;
00761 break;
00762
00763 case -1:
00764
00765
00766
00767
00768
00769 if (sub_abs(var2, var1, result) != 0)
00770 return -1;
00771 result->sign = NUMERIC_NEG;
00772 break;
00773 }
00774 }
00775 }
00776 else
00777 {
00778 if (var2->sign == NUMERIC_POS)
00779 {
00780
00781
00782
00783
00784
00785 switch (cmp_abs(var1, var2))
00786 {
00787 case 0:
00788
00789
00790
00791
00792
00793 zero_var(result);
00794 result->rscale = Max(var1->rscale, var2->rscale);
00795 result->dscale = Max(var1->dscale, var2->dscale);
00796 break;
00797
00798 case 1:
00799
00800
00801
00802
00803
00804 if (sub_abs(var1, var2, result) != 0)
00805 return -1;
00806 result->sign = NUMERIC_NEG;
00807 break;
00808
00809 case -1:
00810
00811
00812
00813
00814
00815 if (sub_abs(var2, var1, result) != 0)
00816 return -1;
00817 result->sign = NUMERIC_POS;
00818 break;
00819 }
00820 }
00821 else
00822 {
00823
00824
00825
00826
00827
00828 if (add_abs(var1, var2, result) != 0)
00829 return -1;
00830 result->sign = NUMERIC_NEG;
00831 }
00832 }
00833
00834 return 0;
00835 }
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845 int
00846 PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
00847 {
00848
00849
00850
00851 if (var1->sign == NUMERIC_POS)
00852 {
00853 if (var2->sign == NUMERIC_NEG)
00854 {
00855
00856
00857
00858
00859
00860 if (add_abs(var1, var2, result) != 0)
00861 return -1;
00862 result->sign = NUMERIC_POS;
00863 }
00864 else
00865 {
00866
00867
00868
00869
00870
00871 switch (cmp_abs(var1, var2))
00872 {
00873 case 0:
00874
00875
00876
00877
00878
00879 zero_var(result);
00880 result->rscale = Max(var1->rscale, var2->rscale);
00881 result->dscale = Max(var1->dscale, var2->dscale);
00882 break;
00883
00884 case 1:
00885
00886
00887
00888
00889
00890 if (sub_abs(var1, var2, result) != 0)
00891 return -1;
00892 result->sign = NUMERIC_POS;
00893 break;
00894
00895 case -1:
00896
00897
00898
00899
00900
00901 if (sub_abs(var2, var1, result) != 0)
00902 return -1;
00903 result->sign = NUMERIC_NEG;
00904 break;
00905 }
00906 }
00907 }
00908 else
00909 {
00910 if (var2->sign == NUMERIC_NEG)
00911 {
00912
00913
00914
00915
00916
00917 switch (cmp_abs(var1, var2))
00918 {
00919 case 0:
00920
00921
00922
00923
00924
00925 zero_var(result);
00926 result->rscale = Max(var1->rscale, var2->rscale);
00927 result->dscale = Max(var1->dscale, var2->dscale);
00928 break;
00929
00930 case 1:
00931
00932
00933
00934
00935
00936 if (sub_abs(var1, var2, result) != 0)
00937 return -1;
00938 result->sign = NUMERIC_NEG;
00939 break;
00940
00941 case -1:
00942
00943
00944
00945
00946
00947 if (sub_abs(var2, var1, result) != 0)
00948 return -1;
00949 result->sign = NUMERIC_POS;
00950 break;
00951 }
00952 }
00953 else
00954 {
00955
00956
00957
00958
00959
00960 if (add_abs(var1, var2, result) != 0)
00961 return -1;
00962 result->sign = NUMERIC_NEG;
00963 }
00964 }
00965
00966 return 0;
00967 }
00968
00969
00970
00971
00972
00973
00974
00975
00976 int
00977 PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result)
00978 {
00979 NumericDigit *res_buf;
00980 NumericDigit *res_digits;
00981 int res_ndigits;
00982 int res_weight;
00983 int res_sign;
00984 int i,
00985 ri,
00986 i1,
00987 i2;
00988 long sum = 0;
00989 int global_rscale = var1->rscale + var2->rscale;
00990
00991 res_weight = var1->weight + var2->weight + 2;
00992 res_ndigits = var1->ndigits + var2->ndigits + 1;
00993 if (var1->sign == var2->sign)
00994 res_sign = NUMERIC_POS;
00995 else
00996 res_sign = NUMERIC_NEG;
00997
00998 if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
00999 return -1;
01000 res_digits = res_buf;
01001 memset(res_digits, 0, res_ndigits);
01002
01003 ri = res_ndigits;
01004 for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
01005 {
01006 sum = 0;
01007 i = --ri;
01008
01009 for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
01010 {
01011 sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
01012 res_digits[i--] = sum % 10;
01013 sum /= 10;
01014 }
01015 res_digits[i] = sum;
01016 }
01017
01018 i = res_weight + global_rscale + 2;
01019 if (i >= 0 && i < res_ndigits)
01020 {
01021 sum = (res_digits[i] > 4) ? 1 : 0;
01022 res_ndigits = i;
01023 i--;
01024 while (sum)
01025 {
01026 sum += res_digits[i];
01027 res_digits[i--] = sum % 10;
01028 sum /= 10;
01029 }
01030 }
01031
01032 while (res_ndigits > 0 && *res_digits == 0)
01033 {
01034 res_digits++;
01035 res_weight--;
01036 res_ndigits--;
01037 }
01038 while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
01039 res_ndigits--;
01040
01041 if (res_ndigits == 0)
01042 {
01043 res_sign = NUMERIC_POS;
01044 res_weight = 0;
01045 }
01046
01047 digitbuf_free(result->buf);
01048 result->buf = res_buf;
01049 result->digits = res_digits;
01050 result->ndigits = res_ndigits;
01051 result->weight = res_weight;
01052 result->rscale = global_rscale;
01053 result->sign = res_sign;
01054 result->dscale = var1->dscale + var2->dscale;
01055
01056 return 0;
01057 }
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 static int
01068 select_div_scale(numeric *var1, numeric *var2, int *rscale)
01069 {
01070 int weight1,
01071 weight2,
01072 qweight,
01073 i;
01074 NumericDigit firstdigit1,
01075 firstdigit2;
01076 int res_dscale;
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088 weight1 = 0;
01089 firstdigit1 = 0;
01090 for (i = 0; i < var1->ndigits; i++)
01091 {
01092 firstdigit1 = var1->digits[i];
01093 if (firstdigit1 != 0)
01094 {
01095 weight1 = var1->weight - i;
01096 break;
01097 }
01098 }
01099
01100 weight2 = 0;
01101 firstdigit2 = 0;
01102 for (i = 0; i < var2->ndigits; i++)
01103 {
01104 firstdigit2 = var2->digits[i];
01105 if (firstdigit2 != 0)
01106 {
01107 weight2 = var2->weight - i;
01108 break;
01109 }
01110 }
01111
01112
01113
01114
01115
01116 qweight = weight1 - weight2;
01117 if (firstdigit1 <= firstdigit2)
01118 qweight--;
01119
01120
01121 res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
01122 res_dscale = Max(res_dscale, var1->dscale);
01123 res_dscale = Max(res_dscale, var2->dscale);
01124 res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
01125 res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
01126
01127
01128 *rscale = res_dscale + 4;
01129
01130 return res_dscale;
01131 }
01132
01133 int
01134 PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result)
01135 {
01136 NumericDigit *res_digits;
01137 int res_ndigits;
01138 int res_sign;
01139 int res_weight;
01140 numeric dividend;
01141 numeric divisor[10];
01142 int ndigits_tmp;
01143 int weight_tmp;
01144 int rscale_tmp;
01145 int ri;
01146 int i;
01147 long guess;
01148 long first_have;
01149 long first_div;
01150 int first_nextdigit;
01151 int stat = 0;
01152 int rscale;
01153 int res_dscale = select_div_scale(var1, var2, &rscale);
01154 int err = -1;
01155 NumericDigit *tmp_buf;
01156
01157
01158
01159
01160 ndigits_tmp = var2->ndigits + 1;
01161 if (ndigits_tmp == 1)
01162 {
01163 errno = PGTYPES_NUM_DIVIDE_ZERO;
01164 return -1;
01165 }
01166
01167
01168
01169
01170 if (var1->sign == var2->sign)
01171 res_sign = NUMERIC_POS;
01172 else
01173 res_sign = NUMERIC_NEG;
01174 res_weight = var1->weight - var2->weight + 1;
01175 res_ndigits = rscale + res_weight;
01176 if (res_ndigits <= 0)
01177 res_ndigits = 1;
01178
01179
01180
01181
01182 if (var1->ndigits == 0)
01183 {
01184 zero_var(result);
01185 result->rscale = rscale;
01186 return 0;
01187 }
01188
01189
01190
01191
01192 init_var(÷nd);
01193 for (i = 1; i < 10; i++)
01194 init_var(&divisor[i]);
01195
01196
01197
01198
01199 divisor[1].ndigits = ndigits_tmp;
01200 divisor[1].rscale = var2->ndigits;
01201 divisor[1].sign = NUMERIC_POS;
01202 divisor[1].buf = digitbuf_alloc(ndigits_tmp);
01203 if (divisor[1].buf == NULL)
01204 goto done;
01205 divisor[1].digits = divisor[1].buf;
01206 divisor[1].digits[0] = 0;
01207 memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
01208
01209
01210
01211
01212 dividend.ndigits = var1->ndigits;
01213 dividend.weight = 0;
01214 dividend.rscale = var1->ndigits;
01215 dividend.sign = NUMERIC_POS;
01216 dividend.buf = digitbuf_alloc(var1->ndigits);
01217 if (dividend.buf == NULL)
01218 goto done;
01219 dividend.digits = dividend.buf;
01220 memcpy(dividend.digits, var1->digits, var1->ndigits);
01221
01222
01223
01224
01225
01226
01227 tmp_buf = digitbuf_alloc(res_ndigits + 2);
01228 if (tmp_buf == NULL)
01229 goto done;
01230 digitbuf_free(result->buf);
01231 result->buf = tmp_buf;
01232 res_digits = result->buf;
01233 result->digits = res_digits;
01234 result->ndigits = res_ndigits;
01235 result->weight = res_weight;
01236 result->rscale = rscale;
01237 result->sign = res_sign;
01238 res_digits[0] = 0;
01239
01240 first_div = divisor[1].digits[1] * 10;
01241 if (ndigits_tmp > 2)
01242 first_div += divisor[1].digits[2];
01243
01244 first_have = 0;
01245 first_nextdigit = 0;
01246
01247 weight_tmp = 1;
01248 rscale_tmp = divisor[1].rscale;
01249
01250 for (ri = 0; ri <= res_ndigits; ri++)
01251 {
01252 first_have = first_have * 10;
01253 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
01254 first_have += dividend.digits[first_nextdigit];
01255 first_nextdigit++;
01256
01257 guess = (first_have * 10) / first_div + 1;
01258 if (guess > 9)
01259 guess = 9;
01260
01261 while (guess > 0)
01262 {
01263 if (divisor[guess].buf == NULL)
01264 {
01265 int i;
01266 long sum = 0;
01267
01268 memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
01269 divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
01270 if (divisor[guess].buf == NULL)
01271 goto done;
01272 divisor[guess].digits = divisor[guess].buf;
01273 for (i = divisor[1].ndigits - 1; i >= 0; i--)
01274 {
01275 sum += divisor[1].digits[i] * guess;
01276 divisor[guess].digits[i] = sum % 10;
01277 sum /= 10;
01278 }
01279 }
01280
01281 divisor[guess].weight = weight_tmp;
01282 divisor[guess].rscale = rscale_tmp;
01283
01284 stat = cmp_abs(÷nd, &divisor[guess]);
01285 if (stat >= 0)
01286 break;
01287
01288 guess--;
01289 }
01290
01291 res_digits[ri + 1] = guess;
01292 if (stat == 0)
01293 {
01294 ri++;
01295 break;
01296 }
01297
01298 weight_tmp--;
01299 rscale_tmp++;
01300
01301 if (guess == 0)
01302 continue;
01303
01304 if (sub_abs(÷nd, &divisor[guess], ÷nd) != 0)
01305 goto done;
01306
01307 first_nextdigit = dividend.weight - weight_tmp;
01308 first_have = 0;
01309 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
01310 first_have = dividend.digits[first_nextdigit];
01311 first_nextdigit++;
01312 }
01313
01314 result->ndigits = ri + 1;
01315 if (ri == res_ndigits + 1)
01316 {
01317 int carry = (res_digits[ri] > 4) ? 1 : 0;
01318
01319 result->ndigits = ri;
01320 res_digits[ri] = 0;
01321
01322 while (carry && ri > 0)
01323 {
01324 carry += res_digits[--ri];
01325 res_digits[ri] = carry % 10;
01326 carry /= 10;
01327 }
01328 }
01329
01330 while (result->ndigits > 0 && *(result->digits) == 0)
01331 {
01332 (result->digits)++;
01333 (result->weight)--;
01334 (result->ndigits)--;
01335 }
01336 while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
01337 (result->ndigits)--;
01338 if (result->ndigits == 0)
01339 result->sign = NUMERIC_POS;
01340
01341 result->dscale = res_dscale;
01342 err = 0;
01343
01344 done:
01345
01346
01347
01348
01349 if (dividend.buf != NULL)
01350 digitbuf_free(dividend.buf);
01351
01352 for (i = 1; i < 10; i++)
01353 {
01354 if (divisor[i].buf != NULL)
01355 digitbuf_free(divisor[i].buf);
01356 }
01357
01358 return err;
01359 }
01360
01361
01362 int
01363 PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
01364 {
01365
01366
01367
01368
01369 if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
01370 return cmp_abs(var1, var2);
01371
01372
01373 if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
01374 {
01375
01376
01377
01378 return cmp_abs(var2, var1);
01379 }
01380
01381
01382 if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
01383 return 1;
01384 if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
01385 return -1;
01386
01387 errno = PGTYPES_NUM_BAD_NUMERIC;
01388 return INT_MAX;
01389
01390 }
01391
01392 int
01393 PGTYPESnumeric_from_int(signed int int_val, numeric *var)
01394 {
01395
01396 signed long int long_int = int_val;
01397
01398 return PGTYPESnumeric_from_long(long_int, var);
01399 }
01400
01401 int
01402 PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
01403 {
01404
01405
01406
01407
01408
01409
01410
01411
01412 int size = 0;
01413 int i;
01414 signed long int abs_long_val = long_val;
01415 signed long int extract;
01416 signed long int reach_limit;
01417
01418 if (abs_long_val < 0)
01419 {
01420 abs_long_val *= -1;
01421 var->sign = NUMERIC_NEG;
01422 }
01423 else
01424 var->sign = NUMERIC_POS;
01425
01426 reach_limit = 1;
01427 do
01428 {
01429 size++;
01430 reach_limit *= 10;
01431 } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
01432
01433 if (reach_limit > LONG_MAX / 10)
01434 {
01435
01436 size += 2;
01437 }
01438 else
01439 {
01440
01441 size++;
01442 reach_limit /= 10;
01443 }
01444
01445 if (alloc_var(var, size) < 0)
01446 return -1;
01447
01448 var->rscale = 1;
01449 var->dscale = 1;
01450 var->weight = size - 2;
01451
01452 i = 0;
01453 do
01454 {
01455 extract = abs_long_val - (abs_long_val % reach_limit);
01456 var->digits[i] = extract / reach_limit;
01457 abs_long_val -= extract;
01458 i++;
01459 reach_limit /= 10;
01460
01461
01462
01463
01464
01465
01466 } while (abs_long_val > 0);
01467
01468 return 0;
01469 }
01470
01471 int
01472 PGTYPESnumeric_copy(numeric *src, numeric *dst)
01473 {
01474 int i;
01475
01476 if (dst == NULL)
01477 return -1;
01478 zero_var(dst);
01479
01480 dst->weight = src->weight;
01481 dst->rscale = src->rscale;
01482 dst->dscale = src->dscale;
01483 dst->sign = src->sign;
01484
01485 if (alloc_var(dst, src->ndigits) != 0)
01486 return -1;
01487
01488 for (i = 0; i < src->ndigits; i++)
01489 dst->digits[i] = src->digits[i];
01490
01491 return 0;
01492 }
01493
01494 int
01495 PGTYPESnumeric_from_double(double d, numeric *dst)
01496 {
01497 char buffer[100];
01498 numeric *tmp;
01499 int i;
01500
01501 if (sprintf(buffer, "%f", d) == 0)
01502 return -1;
01503
01504 if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
01505 return -1;
01506 i = PGTYPESnumeric_copy(tmp, dst);
01507 PGTYPESnumeric_free(tmp);
01508 if (i != 0)
01509 return -1;
01510
01511 errno = 0;
01512 return 0;
01513 }
01514
01515 static int
01516 numericvar_to_double(numeric *var, double *dp)
01517 {
01518 char *tmp;
01519 double val;
01520 char *endptr;
01521 numeric *varcopy = PGTYPESnumeric_new();
01522
01523 if (PGTYPESnumeric_copy(var, varcopy) < 0)
01524 {
01525 PGTYPESnumeric_free(varcopy);
01526 return -1;
01527 }
01528
01529 tmp = get_str_from_var(varcopy, varcopy->dscale);
01530 PGTYPESnumeric_free(varcopy);
01531
01532 if (tmp == NULL)
01533 return -1;
01534
01535
01536
01537
01538 errno = 0;
01539 val = strtod(tmp, &endptr);
01540 if (errno == ERANGE)
01541 {
01542 free(tmp);
01543 if (val == 0)
01544 errno = PGTYPES_NUM_UNDERFLOW;
01545 else
01546 errno = PGTYPES_NUM_OVERFLOW;
01547 return -1;
01548 }
01549
01550
01551 if (*endptr != '\0')
01552 {
01553
01554 free(tmp);
01555 errno = PGTYPES_NUM_BAD_NUMERIC;
01556 return -1;
01557 }
01558 free(tmp);
01559 *dp = val;
01560 return 0;
01561 }
01562
01563 int
01564 PGTYPESnumeric_to_double(numeric *nv, double *dp)
01565 {
01566 double tmp;
01567
01568 if (numericvar_to_double(nv, &tmp) != 0)
01569 return -1;
01570 *dp = tmp;
01571 return 0;
01572 }
01573
01574 int
01575 PGTYPESnumeric_to_int(numeric *nv, int *ip)
01576 {
01577 long l;
01578 int i;
01579
01580 if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
01581 return i;
01582
01583 if (l < -INT_MAX || l > INT_MAX)
01584 {
01585 errno = PGTYPES_NUM_OVERFLOW;
01586 return -1;
01587 }
01588
01589 *ip = (int) l;
01590 return 0;
01591 }
01592
01593 int
01594 PGTYPESnumeric_to_long(numeric *nv, long *lp)
01595 {
01596 char *s = PGTYPESnumeric_to_asc(nv, 0);
01597 char *endptr;
01598
01599 if (s == NULL)
01600 return -1;
01601
01602 errno = 0;
01603 *lp = strtol(s, &endptr, 10);
01604 if (endptr == s)
01605 {
01606
01607 free(s);
01608 return -1;
01609 }
01610 free(s);
01611 if (errno == ERANGE)
01612 {
01613 if (*lp == LONG_MIN)
01614 errno = PGTYPES_NUM_UNDERFLOW;
01615 else
01616 errno = PGTYPES_NUM_OVERFLOW;
01617 return -1;
01618 }
01619 return 0;
01620 }
01621
01622 int
01623 PGTYPESnumeric_to_decimal(numeric *src, decimal *dst)
01624 {
01625 int i;
01626
01627 if (src->ndigits > DECSIZE)
01628 {
01629 errno = PGTYPES_NUM_OVERFLOW;
01630 return -1;
01631 }
01632
01633 dst->weight = src->weight;
01634 dst->rscale = src->rscale;
01635 dst->dscale = src->dscale;
01636 dst->sign = src->sign;
01637 dst->ndigits = src->ndigits;
01638
01639 for (i = 0; i < src->ndigits; i++)
01640 dst->digits[i] = src->digits[i];
01641
01642 return 0;
01643 }
01644
01645 int
01646 PGTYPESnumeric_from_decimal(decimal *src, numeric *dst)
01647 {
01648 int i;
01649
01650 zero_var(dst);
01651
01652 dst->weight = src->weight;
01653 dst->rscale = src->rscale;
01654 dst->dscale = src->dscale;
01655 dst->sign = src->sign;
01656
01657 if (alloc_var(dst, src->ndigits) != 0)
01658 return -1;
01659
01660 for (i = 0; i < src->ndigits; i++)
01661 dst->digits[i] = src->digits[i];
01662
01663 return 0;
01664 }