Header And Logo

PostgreSQL
| The world's most advanced open source database.

numeric.c

Go to the documentation of this file.
00001 /* src/interfaces/ecpg/pgtypeslib/numeric.c */
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  * apply_typmod() -
00027  *
00028  *  Do bounds checking and rounding according to the attributes
00029  *  typmod field.
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     /* Do nothing if we have a default typmod (-1) */
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     /* Round to target scale */
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      * Check for overflow - note we can't do this before rounding, because
00076      * rounding could raise the weight.  Also note that the var's weight could
00077      * be inflated by leading zeroes, which will be stripped before storage
00078      * but perhaps might not have been yet. In any case, we must recognize a
00079      * true zero, whose weight doesn't mean anything.
00080      */
00081     if (var->weight >= maxweight)
00082     {
00083         /* Determine true weight; and check for all-zero result */
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  *  alloc_var() -
00108  *
00109  *   Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
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  * set_var_from_str()
00157  *
00158  *  Parse a string and put the number into a variable
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         /* Should be nothing left but spaces */
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     /* Handle exponent, if any */
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     /* Should be nothing left but spaces */
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     /* Strip any leading zeroes */
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  * get_str_from_var() -
00305  *
00306  *  Convert a var to text representation (guts of numeric_out).
00307  *  CAUTION: var's contents may be modified by rounding!
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      * Check if we must round up before printing the value and do so.
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      * Allocate space for the result
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      * Output a dash for negative values
00363      */
00364     if (var->sign == NUMERIC_NEG)
00365         *cp++ = '-';
00366 
00367     /*
00368      * Output all digits before the decimal point
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      * If requested, output a decimal point and all the digits that follow it.
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      * terminate the string and return it
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     /* get_str_from_var may change its argument */
00442     s = get_str_from_var(numcopy, dscale);
00443     PGTYPESnumeric_free(numcopy);
00444     return (s);
00445 }
00446 
00447 /* ----------
00448  * zero_var() -
00449  *
00450  *  Set a variable to ZERO.
00451  *  Note: rscale and dscale are not touched.
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;            /* by convention; doesn't really matter */
00462     var->sign = NUMERIC_POS;    /* anything but NAN... */
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  * cmp_abs() -
00480  *
00481  *  Compare the absolute values of var1 and var2
00482  *  Returns:    -1 for ABS(var1) < ABS(var2)
00483  *              0  for ABS(var1) == ABS(var2)
00484  *              1  for ABS(var1) > ABS(var2)
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  * add_abs() -
00540  *
00541  *  Add the absolute values of two variables into result.
00542  *  result might point to one of the operands without danger.
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     /* copy these values into local vars for speed in inner loop */
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  * sub_abs() -
00625  *
00626  *  Subtract the absolute value of var2 from the absolute value of var1
00627  *  and store in result. result might point to one of the operands
00628  *  without danger.
00629  *
00630  *  ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
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     /* copy these values into local vars for speed in inner loop */
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  * add_var() -
00712  *
00713  *  Full version of add functionality on variable level (handling signs).
00714  *  result might point to one of the operands too without danger.
00715  * ----------
00716  */
00717 int
00718 PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
00719 {
00720     /*
00721      * Decide on the signs of the two variables what to do
00722      */
00723     if (var1->sign == NUMERIC_POS)
00724     {
00725         if (var2->sign == NUMERIC_POS)
00726         {
00727             /*
00728              * Both are positive result = +(ABS(var1) + ABS(var2))
00729              */
00730             if (add_abs(var1, var2, result) != 0)
00731                 return -1;
00732             result->sign = NUMERIC_POS;
00733         }
00734         else
00735         {
00736             /*
00737              * var1 is positive, var2 is negative Must compare absolute values
00738              */
00739             switch (cmp_abs(var1, var2))
00740             {
00741                 case 0:
00742                     /* ----------
00743                      * ABS(var1) == ABS(var2)
00744                      * result = ZERO
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                      * ABS(var1) > ABS(var2)
00755                      * result = +(ABS(var1) - ABS(var2))
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                      * ABS(var1) < ABS(var2)
00766                      * result = -(ABS(var2) - ABS(var1))
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              * var1 is negative, var2 is positive
00782              * Must compare absolute values
00783              * ----------
00784              */
00785             switch (cmp_abs(var1, var2))
00786             {
00787                 case 0:
00788                     /* ----------
00789                      * ABS(var1) == ABS(var2)
00790                      * result = ZERO
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                      * ABS(var1) > ABS(var2)
00801                      * result = -(ABS(var1) - ABS(var2))
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                      * ABS(var1) < ABS(var2)
00812                      * result = +(ABS(var2) - ABS(var1))
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              * Both are negative
00825              * result = -(ABS(var1) + ABS(var2))
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  * sub_var() -
00840  *
00841  *  Full version of sub functionality on variable level (handling signs).
00842  *  result might point to one of the operands too without danger.
00843  * ----------
00844  */
00845 int
00846 PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
00847 {
00848     /*
00849      * Decide on the signs of the two variables what to do
00850      */
00851     if (var1->sign == NUMERIC_POS)
00852     {
00853         if (var2->sign == NUMERIC_NEG)
00854         {
00855             /* ----------
00856              * var1 is positive, var2 is negative
00857              * result = +(ABS(var1) + ABS(var2))
00858              * ----------
00859              */
00860             if (add_abs(var1, var2, result) != 0)
00861                 return -1;
00862             result->sign = NUMERIC_POS;
00863         }
00864         else
00865         {
00866             /* ----------
00867              * Both are positive
00868              * Must compare absolute values
00869              * ----------
00870              */
00871             switch (cmp_abs(var1, var2))
00872             {
00873                 case 0:
00874                     /* ----------
00875                      * ABS(var1) == ABS(var2)
00876                      * result = ZERO
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                      * ABS(var1) > ABS(var2)
00887                      * result = +(ABS(var1) - ABS(var2))
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                      * ABS(var1) < ABS(var2)
00898                      * result = -(ABS(var2) - ABS(var1))
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              * Both are negative
00914              * Must compare absolute values
00915              * ----------
00916              */
00917             switch (cmp_abs(var1, var2))
00918             {
00919                 case 0:
00920                     /* ----------
00921                      * ABS(var1) == ABS(var2)
00922                      * result = ZERO
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                      * ABS(var1) > ABS(var2)
00933                      * result = -(ABS(var1) - ABS(var2))
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                      * ABS(var1) < ABS(var2)
00944                      * result = +(ABS(var2) - ABS(var1))
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              * var1 is negative, var2 is positive
00957              * result = -(ABS(var1) + ABS(var2))
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  * mul_var() -
00971  *
00972  *  Multiplication on variable level. Product of var1 * var2 is stored
00973  *  in result.  Accuracy of result is determined by global_rscale.
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  * Default scale selection for division
01061  *
01062  * Returns the appropriate display scale for the division result,
01063  * and sets global_rscale to the result scale to use during div_var.
01064  *
01065  * Note that this must be called before div_var.
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      * The result scale of a division isn't specified in any SQL standard. For
01080      * PostgreSQL we select a display scale that will give at least
01081      * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
01082      * result no less accurate than float8; but use a scale not less than
01083      * either input's display scale.
01084      */
01085 
01086     /* Get the actual (normalized) weight and first digit of each input */
01087 
01088     weight1 = 0;                /* values to use if var1 is zero */
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;                /* values to use if var2 is zero */
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      * Estimate weight of quotient.  If the two first digits are equal, we
01114      * can't be sure, but assume that var1 is less than var2.
01115      */
01116     qweight = weight1 - weight2;
01117     if (firstdigit1 <= firstdigit2)
01118         qweight--;
01119 
01120     /* Select display scale */
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     /* Select result scale */
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      * First of all division by zero check
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      * Determine the result sign, weight and number of digits to calculate
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      * Now result zero check
01181      */
01182     if (var1->ndigits == 0)
01183     {
01184         zero_var(result);
01185         result->rscale = rscale;
01186         return 0;
01187     }
01188 
01189     /*
01190      * Initialize local variables
01191      */
01192     init_var(&dividend);
01193     for (i = 1; i < 10; i++)
01194         init_var(&divisor[i]);
01195 
01196     /*
01197      * Make a copy of the divisor which has one leading zero digit
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      * Make a copy of the dividend
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      * Setup the result. Do the allocation in a temporary buffer first, so we
01224      * don't free result->buf unless we have successfully allocated a buffer
01225      * to replace it with.
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(&dividend, &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(&dividend, &divisor[guess], &dividend) != 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;                    /* if we've made it this far, return success */
01343 
01344 done:
01345 
01346     /*
01347      * Tidy up
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     /* use cmp_abs function to calculate the result */
01367 
01368     /* both are positive: normal comparation with cmp_abs */
01369     if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
01370         return cmp_abs(var1, var2);
01371 
01372     /* both are negative: return the inverse of the normal comparation */
01373     if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
01374     {
01375         /*
01376          * instead of inverting the result, we invert the paramter ordering
01377          */
01378         return cmp_abs(var2, var1);
01379     }
01380 
01381     /* one is positive, one is negative: trivial */
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     /* implicit conversion */
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     /* calculate the size of the long int number */
01405     /* a number n needs log_10 n digits */
01406 
01407     /*
01408      * however we multiply by 10 each time and compare instead of calculating
01409      * the logarithm
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         /* add the first digit and a .0 */
01436         size += 2;
01437     }
01438     else
01439     {
01440         /* always add a .0 */
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          * we can abandon if abs_long_val reaches 0, because the memory is
01463          * initialized properly and filled with '0', so converting 10000 in
01464          * only one step is no problem
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      * strtod does not reset errno to 0 in case of success.
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     /* can't free tmp yet, endptr points still into it */
01551     if (*endptr != '\0')
01552     {
01553         /* shouldn't happen ... */
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         /* this should not happen actually */
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 }