OpenCOBOL 1.1pre-rel
numeric.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2009 Keisuke Nishida
00003  * Copyright (C) 2007-2009 Roger While
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public License
00007  * as published by the Free Software Foundation; either version 2.1,
00008  * or (at your option) any later version.
00009  * 
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU Lesser General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; see the file COPYING.LIB.  If
00017  * not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor
00018  * Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include "config.h"
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <math.h>
00028 
00029 #include "common.h"
00030 #include "coblocal.h"
00031 #include "move.h"
00032 #include "numeric.h"
00033 #include "byteswap.h"
00034 
00035 #define COB_LIB_INCLUDE
00036 #include "codegen.h"
00037 
00038 #define DECIMAL_NAN     -128
00039 #define DECIMAL_CHECK(d1,d2) \
00040   if (unlikely(d1->scale == DECIMAL_NAN || d2->scale == DECIMAL_NAN)) { \
00041       d1->scale = DECIMAL_NAN; \
00042       return; \
00043     }
00044 
00045 #define COB_MAX_BINARY  36
00046 
00047 static const unsigned char packed_bytes[] = {
00048         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
00049         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
00050         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
00051         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
00052         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
00053         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
00054         0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
00055         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
00056         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
00057         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
00058 };
00059 
00060 static unsigned char    *num_buff_ptr;
00061 static cob_decimal      cob_d1;
00062 static cob_decimal      cob_d2;
00063 static cob_decimal      cob_d3;
00064 static cob_decimal      cob_d4;
00065 static mpz_t            cob_mexp;
00066 static mpz_t            cob_mpzt;
00067 static mpz_t            cob_mpze10[COB_MAX_BINARY];
00068 static unsigned char    packed_value[20];
00069 
00070 #ifdef  COB_EXPERIMENTAL
00071 
00072 #if GMP_NAIL_BITS != 0
00073 #error NAILS not supported
00074 #endif
00075 
00076 #define COB_MAX_LL      9223372036854775807LL
00077 
00078 static void
00079 mpz_set_ull (mpz_ptr dest, const unsigned long long val)
00080 {
00081         size_t                  size;
00082 
00083         size = (val != 0);
00084         dest->_mp_d[0] = val & GMP_NUMB_MASK;
00085 #if     GMP_LIMB_BITS < 64
00086         if (val > GMP_NUMB_MAX) {
00087                 dest->_mp_d[1] = val >> GMP_NUMB_BITS;
00088                 size = 2;
00089         }
00090 #endif
00091         dest->_mp_size = size;
00092 }
00093 
00094 static void
00095 mpz_set_sll (mpz_ptr dest, const signed long long val)
00096 {
00097         unsigned long long      vtmp;
00098         size_t                  size;
00099 
00100         vtmp = (unsigned long long)(val >= 0 ? val : -val);
00101         size = (vtmp != 0);
00102         dest->_mp_d[0] = vtmp & GMP_NUMB_MASK;
00103 #if     GMP_LIMB_BITS < 64
00104         if (vtmp > GMP_NUMB_MAX) {
00105                 dest->_mp_d[1] = vtmp >> GMP_NUMB_BITS;
00106                 size = 2;
00107         }
00108 #endif
00109         dest->_mp_size = (val >= 0) ? size : -size;
00110 }
00111 
00112 static unsigned long long
00113 mpz_get_ull (const mpz_ptr src)
00114 {
00115         size_t                  size;
00116 
00117         size = mpz_size (src);
00118         if (!size) {
00119                 return 0;
00120         }
00121 #if     GMP_LIMB_BITS > 32
00122         return (unsigned long long)src->_mp_d[0];
00123 #else
00124         if (size < 2) {
00125                 return (unsigned long long)src->_mp_d[0];
00126         }
00127         return (unsigned long long)src->_mp_d[0] |
00128                 ((unsigned long long)src->_mp_d[1] << GMP_NUMB_BITS);
00129 #endif
00130 }
00131 
00132 static signed long long
00133 mpz_get_sll (const mpz_ptr src)
00134 {
00135         int                     size;
00136         unsigned long long      vtmp;
00137 
00138         size = src->_mp_size;
00139         if (!size) {
00140                 return 0;
00141         }
00142         vtmp = (unsigned long long)src->_mp_d[0];
00143 #if     GMP_LIMB_BITS < 64
00144         if (mpz_size (src) > 1) {
00145                 vtmp |= (unsigned long long)src->_mp_d[1] << GMP_NUMB_BITS;
00146         }
00147 #endif
00148         if (size > 0) {
00149                 return (signed long long) vtmp & COB_MAX_LL;
00150         }
00151         return ~(((signed long long) vtmp - 1LL) & COB_MAX_LL);
00152 }
00153 
00154 #endif  /* COB_EXPERIMENTAL */
00155 
00156 static COB_INLINE void
00157 num_byte_memcpy (unsigned char *s1, const unsigned char *s2, size_t size)
00158 {
00159         do {
00160                 *s1++ = *s2++;
00161         } while (--size);
00162 }
00163 
00164 static long long
00165 cob_binary_get_int64 (const cob_field * const f)
00166 {
00167         long long       n = 0;
00168         size_t          fsiz = 8 - f->size;
00169 
00170 /* Experimental code - not activated */
00171 #if 0
00172         unsigned char   *s;
00173 
00174         if ((COB_FIELD_BINARY_SWAP (f) && !COB_FIELD_HAVE_SIGN (f)) ||
00175             (!COB_FIELD_BINARY_SWAP (f) && COB_FIELD_HAVE_SIGN (f))) {
00176                 s = (unsigned char *)&n + fsiz;
00177         } else {
00178                 s = (unsigned char *)&n;
00179         }
00180         num_byte_memcpy (s, f->data, f->size);
00181         if (COB_FIELD_BINARY_SWAP (f)) {
00182                 n = COB_BSWAP_64 (n);
00183         }
00184         if (COB_FIELD_HAVE_SIGN (f)) {
00185                 n >>= 8 * fsiz; /* shift with sign */
00186         }
00187 #endif
00188 #ifndef WORDS_BIGENDIAN
00189         if (COB_FIELD_BINARY_SWAP (f)) {
00190                 if (COB_FIELD_HAVE_SIGN (f)) {
00191                         num_byte_memcpy ((unsigned char *)&n, f->data, f->size);
00192                         n = COB_BSWAP_64 (n);
00193                         n >>= 8 * fsiz; /* shift with sign */
00194                 } else {
00195                         num_byte_memcpy (((unsigned char *)&n) + fsiz, f->data, f->size);
00196                         n = COB_BSWAP_64 (n);
00197                 }
00198         } else {
00199                 if (COB_FIELD_HAVE_SIGN (f)) {
00200                         num_byte_memcpy (((unsigned char *)&n) + fsiz, f->data, f->size);
00201                         n >>= 8 * fsiz; /* shift with sign */
00202                 } else {
00203                         num_byte_memcpy ((unsigned char *)&n, f->data, f->size);
00204                 }
00205         }
00206 #else   /* WORDS_BIGENDIAN */
00207         if (COB_FIELD_HAVE_SIGN (f)) {
00208                 num_byte_memcpy ((unsigned char *)&n, f->data, f->size);
00209                 n >>= 8 * fsiz; /* shift with sign */
00210         } else {
00211                 num_byte_memcpy (((unsigned char *)&n) + fsiz, f->data, f->size);
00212         }
00213 #endif  /* WORDS_BIGENDIAN */
00214         return n;
00215 }
00216 
00217 static unsigned long long
00218 cob_binary_get_uint64 (const cob_field * const f)
00219 {
00220         unsigned long long      n = 0;
00221         size_t                  fsiz = 8 - f->size;
00222 
00223 #ifndef WORDS_BIGENDIAN
00224         if (COB_FIELD_BINARY_SWAP (f)) {
00225                 num_byte_memcpy (((unsigned char *)&n) + fsiz, f->data, f->size);
00226                 n = COB_BSWAP_64 (n);
00227         } else {
00228                 num_byte_memcpy ((unsigned char *)&n, f->data, f->size);
00229         }
00230 #else   /* WORDS_BIGENDIAN */
00231         num_byte_memcpy (((unsigned char *)&n) + fsiz, f->data, f->size);
00232 #endif  /* WORDS_BIGENDIAN */
00233         return n;
00234 }
00235 
00236 static void
00237 cob_binary_set_uint64 (cob_field *f, unsigned long long n)
00238 {
00239 #ifndef WORDS_BIGENDIAN
00240         unsigned char   *s;
00241 
00242         if (COB_FIELD_BINARY_SWAP (f)) {
00243                 n = COB_BSWAP_64 (n);
00244                 s = ((unsigned char *)&n) + 8 - f->size;
00245         } else {
00246                 s = (unsigned char *)&n;
00247         }
00248         num_byte_memcpy (f->data, s, f->size);
00249 #else   /* WORDS_BIGENDIAN */
00250         num_byte_memcpy (f->data, ((unsigned char *)&n) + 8 - f->size, f->size);
00251 #endif  /* WORDS_BIGENDIAN */
00252 }
00253 
00254 static void
00255 cob_binary_set_int64 (cob_field *f, long long n)
00256 {
00257 #ifndef WORDS_BIGENDIAN
00258         unsigned char   *s;
00259 
00260         if (COB_FIELD_BINARY_SWAP (f)) {
00261                 n = COB_BSWAP_64 (n);
00262                 s = ((unsigned char *)&n) + 8 - f->size;
00263         } else {
00264                 s = (unsigned char *)&n;
00265         }
00266         num_byte_memcpy (f->data, s, f->size);
00267 #else   /* WORDS_BIGENDIAN */
00268         num_byte_memcpy (f->data, ((unsigned char *)&n) + 8 - f->size, f->size);
00269 #endif  /* WORDS_BIGENDIAN */
00270 }
00271 
00272 /*
00273  * Decimal number
00274  */
00275 
00276 void
00277 cob_decimal_init (cob_decimal *d)
00278 {
00279         mpz_init2 (d->value, 256);
00280         d->scale = 0;
00281 }
00282 
00283 /* Not used - comment out
00284 void
00285 cob_decimal_print (cob_decimal *d)
00286 {
00287         mpz_out_str (stdout, 10, d->value);
00288         if (d->scale) {
00289                 fprintf (stdout, " * 10^%d", -d->scale);
00290         }
00291         fputs ("\n", stdout);
00292 }
00293 end comment out */
00294 
00295 /* d->value *= 10^n, d->scale += n */
00296 static void
00297 shift_decimal (cob_decimal *d, const int n)
00298 {
00299         if (n == 0) {
00300                 return;
00301         }
00302         if (n > 0) {
00303                 mpz_ui_pow_ui (cob_mexp, 10, n);
00304                 mpz_mul (d->value, d->value, cob_mexp);
00305         } else {
00306                 mpz_ui_pow_ui (cob_mexp, 10, -n);
00307                 mpz_tdiv_q (d->value, d->value, cob_mexp);
00308         }
00309         d->scale += n;
00310 }
00311 
00312 static void
00313 align_decimal (cob_decimal *d1, cob_decimal *d2)
00314 {
00315         if (d1->scale < d2->scale) {
00316                 shift_decimal (d1, d2->scale - d1->scale);
00317         } else if (d1->scale > d2->scale) {
00318                 shift_decimal (d2, d1->scale - d2->scale);
00319         }
00320 }
00321 
00322 /*
00323  * Decimal set/get
00324  */
00325 
00326 static void
00327 cob_decimal_set (cob_decimal *dst, const cob_decimal *src)
00328 {
00329         mpz_set (dst->value, src->value);
00330         dst->scale = src->scale;
00331 }
00332 
00333 /* double */
00334 
00335 static void
00336 cob_decimal_set_double (cob_decimal *d, const double v)
00337 {
00338         mpz_set_d (d->value, v * 1.0e9);
00339         d->scale = 9;
00340 }
00341 
00342 static double
00343 cob_decimal_get_double (cob_decimal *d)
00344 {
00345         double  v;
00346         int     n;
00347 
00348         v = mpz_get_d (d->value);
00349         n = d->scale;
00350         for (; n > 0; n--) {
00351                 v /= 10;
00352         }
00353         for (; n < 0; n++) {
00354                 v *= 10;
00355         }
00356         return v;
00357 }
00358 
00359 /* DISPLAY */
00360 
00361 static void
00362 cob_decimal_set_display (cob_decimal *d, cob_field *f)
00363 {
00364         unsigned char   *data;
00365         size_t          size;
00366         int             sign;
00367         unsigned int    n;
00368 
00369         data = COB_FIELD_DATA (f);
00370         size = COB_FIELD_SIZE (f);
00371         if (unlikely(*data == 255)) {
00372                 mpz_ui_pow_ui (d->value, 10, size);
00373                 d->scale = COB_FIELD_SCALE(f);
00374                 return;
00375         }
00376         if (unlikely(*data == 0)) {
00377                 mpz_ui_pow_ui (d->value, 10, size);
00378                 mpz_neg (d->value, d->value);
00379                 d->scale = COB_FIELD_SCALE(f);
00380                 return;
00381         }
00382         sign = cob_get_sign (f);
00383         /* skip leading zeros */
00384         while (size > 1 && *data == '0') {
00385                 size--;
00386                 data++;
00387         }
00388 
00389         /* set value */
00390         if (size < 10) {
00391                 n = 0;
00392                 while (size--) {
00393                         n = n * 10 + cob_d2i (*data++);
00394                 }
00395                 mpz_set_ui (d->value, n);
00396         } else {
00397                 memcpy (num_buff_ptr, data, size);
00398                 num_buff_ptr[size] = 0;
00399                 mpz_set_str (d->value, (char *)num_buff_ptr, 10);
00400         }
00401 
00402         /* set sign and scale */
00403         if (sign < 0) {
00404                 mpz_neg (d->value, d->value);
00405         }
00406         d->scale = COB_FIELD_SCALE(f);
00407         cob_put_sign (f, sign);
00408 }
00409 
00410 static int
00411 cob_decimal_get_display (cob_decimal *d, cob_field *f, const int opt)
00412 {
00413         unsigned char   *data;
00414         size_t          size;
00415         int             diff;
00416         int             sign;
00417 
00418         /* build string */
00419         sign = mpz_sgn (d->value);
00420         mpz_abs (d->value, d->value);
00421         mpz_get_str ((char *)num_buff_ptr, 10, d->value);
00422         size = strlen ((char *)num_buff_ptr);
00423 
00424         /* store number */
00425         data = COB_FIELD_DATA (f);
00426         diff = (int)(COB_FIELD_SIZE (f) - size);
00427         if (unlikely(diff < 0)) {
00428                 /* overflow */
00429                 cob_set_exception (COB_EC_SIZE_OVERFLOW);
00430 
00431                 /* if the statement has ON SIZE ERROR or NOT ON SIZE ERROR,
00432                    then throw an exception */
00433                 if (opt & COB_STORE_KEEP_ON_OVERFLOW) {
00434                         return cob_exception_code;
00435                 }
00436 
00437                 /* othersize, truncate digits */
00438                 memcpy (data, num_buff_ptr - diff, COB_FIELD_SIZE (f));
00439         } else {
00440                 /* no overflow */
00441                 memset (data, '0', (size_t)diff);
00442                 memcpy (data + diff, num_buff_ptr, size);
00443         }
00444 
00445         cob_put_sign (f, sign);
00446         return 0;
00447 }
00448 
00449 /* BINARY */
00450 
00451 static void
00452 cob_decimal_set_binary (cob_decimal *d, cob_field *f)
00453 {
00454 #ifdef  COB_LI_IS_LL
00455         if (COB_FIELD_HAVE_SIGN (f)) {
00456                 mpz_set_si (d->value, cob_binary_get_int64 (f));
00457         } else {
00458                 mpz_set_ui (d->value, cob_binary_get_uint64 (f));
00459         }
00460 #elif   defined(COB_EXPERIMENTAL)
00461         if (COB_FIELD_HAVE_SIGN (f)) {
00462                 mpz_set_sll (d->value, cob_binary_get_int64 (f));
00463         } else {
00464                 mpz_set_ull (d->value, cob_binary_get_uint64 (f));
00465         }
00466 #else
00467         size_t                  negative = 0;
00468         unsigned long long      uval;
00469         long long               val;
00470 
00471         if (f->size <= 4) {
00472                 if (COB_FIELD_HAVE_SIGN (f)) {
00473                         mpz_set_si (d->value, (int)cob_binary_get_int64 (f));
00474                 } else {
00475                         mpz_set_ui (d->value, (unsigned int) cob_binary_get_uint64 (f));
00476                 }
00477         } else {
00478                 if (COB_FIELD_HAVE_SIGN (f)) {
00479                         val = cob_binary_get_int64 (f);
00480                         if (val < 0) {
00481                                 negative = 1;
00482                                 val = -val;
00483                         }
00484                         mpz_set_ui (d->value, (unsigned int)((val & 0x7FFFFFFF00000000LL)>> 32));
00485                         mpz_mul_2exp (d->value, d->value, 32);
00486                         mpz_add_ui (d->value, d->value, (unsigned int)(val & 0xffffffff));
00487                         if (negative) {
00488                                 mpz_neg (d->value, d->value);
00489                         }
00490                 } else {
00491                         uval = cob_binary_get_uint64 (f);
00492                         mpz_set_ui (d->value, (unsigned int)(uval >> 32));
00493                         mpz_mul_2exp (d->value, d->value, 32);
00494                         mpz_add_ui (d->value, d->value, (unsigned int)(uval & 0xffffffff));
00495                 }
00496         }
00497 #endif
00498         d->scale = COB_FIELD_SCALE(f);
00499 }
00500 
00501 static int
00502 cob_decimal_get_binary (cob_decimal *d, cob_field *f, const int opt)
00503 {
00504         size_t                  overflow;
00505         size_t                  digits;
00506         size_t                  sign;
00507         size_t                  bitnum;
00508 #if     !defined(COB_EXPERIMENTAL) && !defined(COB_LI_IS_LL)
00509         long long               llval;
00510         unsigned long long      ullval;
00511         unsigned int            lo;
00512 #endif
00513 
00514         if (unlikely(mpz_size (d->value) == 0)) {
00515                 memset (f->data, 0, f->size);
00516                 return 0;
00517         }
00518         overflow = 0;
00519         digits = COB_FIELD_DIGITS(f);
00520         if (COB_FIELD_HAVE_SIGN (f)) {
00521                 sign = 1;
00522         } else {
00523                 sign = 0;
00524                 if (mpz_sgn (d->value) < 0) {
00525                         mpz_abs (d->value, d->value);
00526                 }
00527         }
00528         bitnum = (f->size * 8) - sign;
00529         if (unlikely(mpz_sizeinbase (d->value, 2) > bitnum)) {
00530                 if (opt & COB_STORE_KEEP_ON_OVERFLOW) {
00531                         goto overflow;
00532                 }
00533                 overflow = 1;
00534                 /* TRUNC_ON_OVERFLOW is only set for binary_truncate */
00535                 if (opt & COB_STORE_TRUNC_ON_OVERFLOW) {
00536                         mpz_tdiv_r (d->value, d->value, cob_mpze10[digits]);
00537 /*
00538                 }
00539 */
00540 /* RXW */
00541                 } else {
00542                         mpz_fdiv_r_2exp (d->value, d->value, (f->size * 8));
00543                 }
00544         } else if (opt && cob_current_module->flag_binary_truncate) {
00545                 if (mpz_cmpabs (d->value, cob_mpze10[digits]) >= 0) {
00546                         /* overflow */
00547                         if (opt & COB_STORE_KEEP_ON_OVERFLOW) {
00548                                 goto overflow;
00549                         }
00550                         overflow = 1;
00551                         /* TRUNC_ON_OVERFLOW is only set for binary_truncate */
00552                         if (opt & COB_STORE_TRUNC_ON_OVERFLOW) {
00553                                 mpz_tdiv_r (d->value, d->value, cob_mpze10[digits]);
00554 /*
00555                         }
00556 */
00557 /* RXW */
00558                         } else {
00559                                 mpz_fdiv_r_2exp (d->value, d->value, (f->size * 8));
00560                         }
00561                 }
00562         }
00563 #ifdef  COB_LI_IS_LL
00564         if (!sign || overflow) {
00565                 cob_binary_set_uint64 (f, mpz_get_ui (d->value));
00566         } else {
00567                 cob_binary_set_int64 (f, mpz_get_si (d->value));
00568         }
00569 #elif   defined(COB_EXPERIMENTAL)
00570         if (!sign || overflow) {
00571                 cob_binary_set_uint64 (f, mpz_get_ull (d->value));
00572         } else {
00573                 cob_binary_set_int64 (f, mpz_get_sll (d->value));
00574         }
00575 #else
00576         if (f->size <= 4) {
00577                 if (!sign || overflow) {
00578                         cob_binary_set_uint64 (f, (unsigned long long)mpz_get_ui (d->value));
00579                 } else {
00580                         cob_binary_set_int64 (f, (long long)mpz_get_si (d->value));
00581                 }
00582         } else {
00583                 mpz_fdiv_r_2exp (cob_mpzt, d->value, 32);
00584                 mpz_fdiv_q_2exp (d->value, d->value, 32);
00585                 lo = mpz_get_ui (cob_mpzt);
00586 
00587                 if (!sign || overflow) {
00588                         ullval = mpz_get_ui (d->value);
00589                         ullval = (ullval << 32) | lo;
00590                         cob_binary_set_uint64 (f, ullval);
00591                 } else {
00592                         llval = mpz_get_si (d->value);
00593                         llval = (llval << 32) | lo;
00594                         cob_binary_set_int64 (f, llval);
00595                 }
00596         }
00597 #endif
00598         if (!overflow) {
00599                 return 0;
00600         }
00601 
00602 overflow:
00603         cob_set_exception (COB_EC_SIZE_OVERFLOW);
00604         return cob_exception_code;
00605 }
00606 
00607 /* PACKED-DECIMAL */
00608 
00609 static int
00610 cob_packed_get_sign (const cob_field *f)
00611 {
00612         unsigned char *p;
00613 
00614         if (!COB_FIELD_HAVE_SIGN (f)) {
00615                 return 0;
00616         }
00617         p = f->data + f->size - 1;
00618         return ((*p & 0x0f) == 0x0d) ? -1 : 1;
00619 }
00620 
00621 static void
00622 cob_add_packed (cob_field *f, int val)
00623 {
00624         unsigned char   *p;
00625         int             sign;
00626         int             ndigs;
00627         int             tval;
00628         int             carry = 0;
00629         unsigned int    msn;
00630         unsigned int    subtr = 0;
00631         unsigned int    zeroes = 0;
00632         unsigned int    origdigs;
00633 
00634         ndigs = COB_FIELD_DIGITS(f) - COB_FIELD_SCALE(f);
00635         if (ndigs <= 0) {
00636                 return;
00637         }
00638         sign = cob_packed_get_sign (f);
00639         msn = 1 - (COB_FIELD_SCALE(f) % 2);
00640 
00641         /* -x +v = -(x - v), -x -v = -(x + v) */
00642         if (sign < 0) {
00643                 val = -val;
00644         }
00645         if (val < 0) {
00646                 val = -val;
00647                 subtr = 1;
00648         }
00649         p = f->data + (ndigs / 2) - (1 - msn);
00650         origdigs = ndigs;
00651         while (ndigs--) {
00652                 if (!msn) {
00653                         tval = *p & 0x0f;
00654                 } else {
00655                         tval = (*p & 0xf0) >> 4;
00656                 }
00657                 if (val) {
00658                         carry += (val % 10);
00659                         val /= 10;
00660                 }
00661                 if (subtr) {
00662                         tval -= carry;
00663                         if (tval < 0) {
00664                                 tval += 10;
00665                                 carry = 1;
00666                         } else {
00667                                 carry = 0;
00668                         }
00669                 } else {
00670                         tval += carry;
00671                         if (tval > 9) {
00672                                 tval %= 10;
00673                                 carry = 1;
00674                         } else {
00675                                 carry = 0;
00676                         }
00677                 }
00678                 if (tval == 0) {
00679                         zeroes++;
00680                 }
00681                 if (!msn) {
00682                         *p = (*p & 0xf0) | tval;
00683                         msn = 1;
00684                 } else {
00685                         *p = (*p & 0x0f) | (tval << 4);
00686                         msn = 0;
00687                         p--;
00688                 }
00689         }
00690         if (sign) {
00691                 p = f->data + f->size - 1;
00692                 if (origdigs == zeroes) {
00693                         *p = (*p & 0xf0) | 0x0c;
00694                 } else if (subtr && carry) {
00695                         sign = -sign;
00696                         if (sign < 0) {
00697                                 *p = (*p & 0xf0) | 0x0d;
00698                         } else {
00699                                 *p = (*p & 0xf0) | 0x0c;
00700                         }
00701                 }
00702         }
00703 }
00704 
00705 static void
00706 cob_decimal_set_packed (cob_decimal *d, cob_field *f)
00707 {
00708         unsigned char   *p;
00709         int             digits;
00710         int             sign;
00711         unsigned int    val;
00712         unsigned int    valseen;
00713 
00714         p = f->data;
00715         /* Fixme */
00716         digits = COB_FIELD_DIGITS (f);
00717         sign = cob_packed_get_sign (f);
00718 
00719         if (digits % 2 == 0) {
00720                 val = *p & 0x0f;
00721                 digits--;
00722                 p++;
00723         } else {
00724                 val = 0;
00725         }
00726 
00727         if (COB_FIELD_DIGITS(f) < 10) {
00728                 while (digits > 1) {
00729                         if (val) {
00730                                 val *= 100;
00731                         }
00732                         if (*p) {
00733                                 val += ((*p >> 4) * 10) + (*p & 0x0f);
00734                         }
00735                         digits -= 2;
00736                         p++;
00737                 }
00738                 if (val) {
00739                         val *= 10;
00740                 }
00741                 val += *p >> 4;
00742                 mpz_set_ui (d->value, val);
00743         } else {
00744                 valseen = 0;
00745                 mpz_set_ui (d->value, val);
00746                 if (val) {
00747                         valseen = 1;
00748                 }
00749                 while (digits > 1) {
00750                         if (valseen) {
00751                                 mpz_mul_ui (d->value, d->value, 100);
00752                         }
00753                         if (*p) {
00754                                 mpz_add_ui (d->value, d->value,
00755                                         (*p >> 4) * 10 + (*p & 0x0f));
00756                                 valseen = 1;
00757                         }
00758                         digits -= 2;
00759                         p++;
00760                 }
00761                 if (valseen) {
00762                         mpz_mul_ui (d->value, d->value, 10);
00763                 }
00764                 mpz_add_ui (d->value, d->value, (*p >> 4));
00765         }
00766 
00767         if (sign < 0) {
00768                 mpz_neg (d->value, d->value);
00769         }
00770         d->scale = COB_FIELD_SCALE(f);
00771 }
00772 
00773 static int
00774 cob_decimal_get_packed (cob_decimal *d, cob_field *f, const int opt)
00775 {
00776         unsigned char   *data;
00777         unsigned char   *p;
00778         unsigned char   *q;
00779         size_t          size;
00780         size_t          n;
00781         size_t          i;
00782         int             diff;
00783         int             sign;
00784         int             digits;
00785         unsigned char   x;
00786 
00787         /* build string */
00788         sign = mpz_sgn (d->value);
00789         mpz_abs (d->value, d->value);
00790         mpz_get_str ((char *)num_buff_ptr, 10, d->value);
00791         size = strlen ((char *)num_buff_ptr);
00792 
00793         /* store number */
00794         data = f->data;
00795         /* Fixme */
00796         digits = COB_FIELD_DIGITS(f);
00797         q = num_buff_ptr;
00798         diff = (int)(digits - size);
00799         if (diff < 0) {
00800                 /* overflow */
00801                 cob_set_exception (COB_EC_SIZE_OVERFLOW);
00802 
00803                 /* if the statement has ON SIZE ERROR or NOT ON SIZE ERROR,
00804                    then throw an exception */
00805                 if (opt & COB_STORE_KEEP_ON_OVERFLOW) {
00806                         return cob_exception_code;
00807                 }
00808                 q += size - digits;
00809                 size = digits;
00810         }
00811         memset (data, 0, f->size);
00812         p = data + (digits / 2) - (size / 2);
00813         diff = 1 - (int)(size % 2);
00814         for (i = diff, n = 0; i < size + diff; i++, n++) {
00815                 x = cob_d2i (q[n]);
00816                 if (i % 2 == 0) {
00817                         *p = x << 4;
00818                 } else {
00819                         *p++ |= x;
00820                 }
00821         }
00822 
00823         p = f->data + f->size - 1;
00824         if (!COB_FIELD_HAVE_SIGN (f)) {
00825                 *p = (*p & 0xf0) | 0x0f;
00826         } else if (sign < 0) {
00827                 *p = (*p & 0xf0) | 0x0d;
00828         } else {
00829                 *p = (*p & 0xf0) | 0x0c;
00830         }
00831 
00832         return 0;
00833 }
00834 
00835 void
00836 cob_set_packed_zero (cob_field *f)
00837 {
00838         memset (f->data, 0, f->size);
00839         if (!COB_FIELD_HAVE_SIGN (f)) {
00840                 *(f->data + f->size - 1) = 0x0f;
00841         } else {
00842                 *(f->data + f->size - 1) = 0x0c;
00843         }
00844 }
00845 
00846 void
00847 cob_set_packed_int (cob_field *f, const int val)
00848 {
00849         unsigned char   *p;
00850         size_t          sign = 0;
00851         int             n;
00852 
00853         if (val < 0) {
00854                 n = -val;
00855                 sign = 1;
00856         } else {
00857                 n = val;
00858         }
00859         memset (f->data, 0, f->size);
00860         p = f->data + f->size - 1;
00861         *p = (n % 10) << 4;
00862         if (!COB_FIELD_HAVE_SIGN (f)) {
00863                 *p |= 0x0f;
00864         } else if (sign) {
00865                 *p |= 0x0d;
00866         } else {
00867                 *p |= 0x0c;
00868         }
00869         n /= 10;
00870         p--;
00871         for (; n && p >= f->data; n /= 100, p--) {
00872                 *p = packed_bytes[n % 100];
00873         }
00874         /* Fixme */
00875         if ((COB_FIELD_DIGITS(f) % 2) == 0) {
00876                 *(f->data) &= 0x0f;
00877         }
00878 }
00879 
00880 /* General field */
00881 
00882 void
00883 cob_decimal_set_field (cob_decimal *d, cob_field *f)
00884 {
00885         double  dval;
00886         float   fval;
00887 
00888         switch (COB_FIELD_TYPE (f)) {
00889         case COB_TYPE_NUMERIC_BINARY:
00890                 cob_decimal_set_binary (d, f);
00891                 break;
00892         case COB_TYPE_NUMERIC_PACKED:
00893                 cob_decimal_set_packed (d, f);
00894                 break;
00895         case COB_TYPE_NUMERIC_FLOAT:
00896                 memcpy ((ucharptr)&fval, f->data, sizeof(float));
00897                 cob_decimal_set_double (d, (double)fval);
00898                 break;
00899         case COB_TYPE_NUMERIC_DOUBLE:
00900                 memcpy ((ucharptr)&dval, f->data, sizeof(double));
00901                 cob_decimal_set_double (d, dval);
00902                 break;
00903         default:
00904                 cob_decimal_set_display (d, f);
00905                 break;
00906         }
00907 }
00908 
00909 int
00910 cob_decimal_get_field (cob_decimal *d, cob_field *f, const int opt)
00911 {
00912         cob_field       temp;
00913         cob_field_attr  attr;
00914         double          val;
00915         float           fval;
00916         int             sign;
00917         unsigned char   data[64];
00918 
00919         if (unlikely(d->scale == DECIMAL_NAN)) {
00920                 cob_set_exception (COB_EC_SIZE_OVERFLOW);
00921                 return cob_exception_code;
00922         }
00923 
00924         /* work copy */
00925         if (d != &cob_d1) {
00926                 cob_decimal_set (&cob_d1, d);
00927                 d = &cob_d1;
00928         }
00929 
00930         /* rounding */
00931         if (opt & COB_STORE_ROUND) {
00932                 if (COB_FIELD_SCALE(f) < d->scale) {
00933                         sign = mpz_sgn (d->value);
00934                         if (sign != 0) {
00935                                 shift_decimal (d, COB_FIELD_SCALE(f) - d->scale + 1);
00936                                 if (sign > 0) {
00937                                         mpz_add_ui (d->value, d->value, 5);
00938                                 } else {
00939                                         mpz_sub_ui (d->value, d->value, 5);
00940                                 }
00941                         }
00942                 }
00943         }
00944 
00945         /* append or truncate decimal digits */
00946         shift_decimal (d, COB_FIELD_SCALE(f) - d->scale);
00947 
00948         /* store number */
00949         switch (COB_FIELD_TYPE (f)) {
00950         case COB_TYPE_NUMERIC_BINARY:
00951                 return cob_decimal_get_binary (d, f, opt);
00952         case COB_TYPE_NUMERIC_PACKED:
00953                 return cob_decimal_get_packed (d, f, opt);
00954         case COB_TYPE_NUMERIC_DISPLAY:
00955                 return cob_decimal_get_display (d, f, opt);
00956         case COB_TYPE_NUMERIC_FLOAT:
00957                 fval = (float) cob_decimal_get_double (d);
00958                 memcpy (f->data, (ucharptr)&fval, sizeof (float));
00959                 return 0;
00960         case COB_TYPE_NUMERIC_DOUBLE:
00961                 val = cob_decimal_get_double (d);
00962                 memcpy (f->data, (ucharptr)&val, sizeof (double));
00963                 return 0;
00964         default:
00965                 COB_ATTR_INIT (COB_TYPE_NUMERIC_DISPLAY, COB_FIELD_DIGITS(f),
00966                                 COB_FIELD_SCALE(f), COB_FLAG_HAVE_SIGN, NULL);
00967                 temp.size = COB_FIELD_DIGITS(f);
00968                 temp.data = data;
00969                 temp.attr = &attr;
00970                 if (cob_decimal_get_display (d, &temp, opt) == 0) {
00971                         cob_move (&temp, f);
00972                 }
00973                 return cob_exception_code;
00974         }
00975 }
00976 
00977 /*
00978  * Decimal arithmetic
00979  */
00980 
00981 void
00982 cob_decimal_add (cob_decimal *d1, cob_decimal *d2)
00983 {
00984         DECIMAL_CHECK (d1, d2);
00985         align_decimal (d1, d2);
00986         mpz_add (d1->value, d1->value, d2->value);
00987 }
00988 
00989 void
00990 cob_decimal_sub (cob_decimal *d1, cob_decimal *d2)
00991 {
00992         DECIMAL_CHECK (d1, d2);
00993         align_decimal (d1, d2);
00994         mpz_sub (d1->value, d1->value, d2->value);
00995 }
00996 
00997 void
00998 cob_decimal_mul (cob_decimal *d1, cob_decimal *d2)
00999 {
01000         DECIMAL_CHECK (d1, d2);
01001         d1->scale += d2->scale;
01002         mpz_mul (d1->value, d1->value, d2->value);
01003 }
01004 
01005 void
01006 cob_decimal_div (cob_decimal *d1, cob_decimal *d2)
01007 {
01008         DECIMAL_CHECK (d1, d2);
01009 
01010         /* check for division by zero */
01011         if (unlikely(mpz_sgn (d2->value) == 0)) {
01012                 d1->scale = DECIMAL_NAN;
01013                 cob_set_exception (COB_EC_SIZE_ZERO_DIVIDE);
01014                 return;
01015         }
01016         if (unlikely(mpz_sgn (d1->value) == 0)) {
01017                 d1->scale = 0;
01018                 return;
01019         }
01020         d1->scale -= d2->scale;
01021         shift_decimal (d1, 37 + ((d1->scale < 0) ? -d1->scale : 0));
01022         mpz_tdiv_q (d1->value, d1->value, d2->value);
01023 }
01024 
01025 void
01026 cob_decimal_pow (cob_decimal *d1, cob_decimal *d2)
01027 {
01028         unsigned int    n;
01029 
01030         DECIMAL_CHECK (d1, d2);
01031 
01032         if (d2->scale == 0 && mpz_fits_ulong_p (d2->value)) {
01033                 n = mpz_get_ui (d2->value);
01034                 mpz_pow_ui (d1->value, d1->value, n);
01035                 d1->scale *= n;
01036         } else {
01037                 cob_decimal_set_double (d1, pow (cob_decimal_get_double (d1),
01038                                                  cob_decimal_get_double (d2)));
01039         }
01040 }
01041 
01042 int
01043 cob_decimal_cmp (cob_decimal *d1, cob_decimal *d2)
01044 {
01045         align_decimal (d1, d2);
01046         return mpz_cmp (d1->value, d2->value);
01047 }
01048 
01049 /*
01050  * Optimized arithmetic for DISPLAY
01051  */
01052 
01053 static int
01054 display_add_int (unsigned char *data, const size_t size, unsigned int n)
01055 {
01056         unsigned char   *sp;
01057         size_t          carry = 0;
01058         int             i;
01059         int             is;
01060 
01061         sp = data + size;
01062         while (n > 0) {
01063                 i = n % 10;
01064                 n /= 10;
01065 
01066                 /* check for overflow */
01067                 if (unlikely(--sp < data)) {
01068                         if (!cob_current_module->flag_binary_truncate) {
01069                                 return 0;
01070                         }
01071                         return 1;
01072                 }
01073 
01074                 /* perform addition */
01075                 is = (*sp & 0x0F) + i + carry;
01076                 if (is > 9) {
01077                         carry = 1;
01078                         *sp = '0' + (is % 10);
01079                 } else {
01080                         carry = 0;
01081                         *sp = '0' + is;
01082                 }
01083         }
01084         if (carry == 0) {
01085                 return 0;
01086         }
01087 
01088         /* carry up */
01089         while (--sp >= data) {
01090                 if ((*sp += 1) <= '9') {
01091                         return 0;
01092                 }
01093                 *sp = '0';
01094         }
01095         if (!cob_current_module->flag_binary_truncate) {
01096                 return 0;
01097         }
01098         return 1;
01099 }
01100 
01101 static int
01102 display_sub_int (unsigned char *data, const size_t size, unsigned int n)
01103 {
01104         unsigned char   *sp;
01105         size_t          carry = 0;
01106         int             i;
01107 
01108         sp = data + size;
01109         while (n > 0) {
01110                 i = n % 10;
01111                 n /= 10;
01112 
01113                 /* check for overflow */
01114                 if (unlikely(--sp < data)) {
01115                         return 1;
01116                 }
01117 
01118                 /* perform subtraction */
01119                 if ((*sp -= i + carry) < '0') {
01120                         carry = 1;
01121                         *sp += 10;
01122                 } else {
01123                         carry = 0;
01124                 }
01125         }
01126         if (carry == 0) {
01127                 return 0;
01128         }
01129 
01130         /* carry up */
01131         while (--sp >= data) {
01132                 if ((*sp -= 1) >= '0') {
01133                         return 0;
01134                 }
01135                 *sp = '9';
01136         }
01137         return 1;
01138 }
01139 
01140 static int
01141 cob_display_add_int (cob_field *f, int n)
01142 {
01143         unsigned char   *data;
01144         size_t          osize;
01145         size_t          i;
01146         size_t          size;
01147         int             scale;
01148         int             sign;
01149         unsigned char   tfield[64];
01150 
01151         data = COB_FIELD_DATA (f);
01152         size = COB_FIELD_SIZE (f);
01153         scale = COB_FIELD_SCALE (f);
01154         sign = cob_get_sign (f);
01155         osize = size;
01156         memcpy (tfield, data, osize);
01157         /* -x + n = -(x - n) */
01158         if (sign < 0) {
01159                 n = -n;
01160         }
01161 
01162         if (unlikely(scale < 0)) {
01163                 /* PIC 9(n)P(m) */
01164                 if (-scale < 10) {
01165                         while (scale++) {
01166                                 n /= 10;
01167                         }
01168                 } else {
01169                         n = 0;
01170                 }
01171         } else {
01172                 /* PIC 9(n)V9(m) */
01173                 size -= scale;
01174                 /* Following can never be true as size is unsigned ?? */
01175                 /* Comment out
01176                 if (size < 0) {
01177                         cob_put_sign (f, sign);
01178                         goto overflow;
01179                 }
01180                 */
01181         }
01182 
01183         if (n > 0) {
01184                 /* add n to the field */
01185                 if (display_add_int (data, size, n) != 0) {
01186                         /* if there was an overflow, recover the last value */
01187                         memcpy (data, tfield, osize);
01188                         goto overflow;
01189                 }
01190         } else if (n < 0) {
01191                 /* subtract n from the field */
01192                 if (display_sub_int (data, size, -n) != 0) {
01193                         for (i = 0; i < size; i++) {
01194                                 data[i] = cob_i2d (9 - cob_d2i (data[i]));
01195                         }
01196                         display_add_int (data, size, 1);
01197                         sign = -sign;
01198                 }
01199         }
01200 
01201         cob_put_sign (f, sign);
01202         return 0;
01203 
01204 overflow:
01205         cob_put_sign (f, sign);
01206         cob_set_exception (COB_EC_SIZE_OVERFLOW);
01207         return cob_exception_code;
01208 }
01209 
01210 /*
01211  * Convenience functions
01212  */
01213 
01214 int
01215 cob_add (cob_field *f1, cob_field *f2, const int opt)
01216 {
01217         cob_decimal_set_field (&cob_d1, f1);
01218         cob_decimal_set_field (&cob_d2, f2);
01219         cob_decimal_add (&cob_d1, &cob_d2);
01220         return cob_decimal_get_field (&cob_d1, f1, opt);
01221 }
01222 
01223 int
01224 cob_sub (cob_field *f1, cob_field *f2, const int opt)
01225 {
01226         cob_decimal_set_field (&cob_d1, f1);
01227         cob_decimal_set_field (&cob_d2, f2);
01228         cob_decimal_sub (&cob_d1, &cob_d2);
01229         return cob_decimal_get_field (&cob_d1, f1, opt);
01230 }
01231 
01232 int
01233 cob_add_int (cob_field *f, const int n)
01234 {
01235         if (unlikely(n == 0)) {
01236                 return 0;
01237         }
01238         switch (COB_FIELD_TYPE (f)) {
01239         case COB_TYPE_NUMERIC_DISPLAY:
01240                 return cob_display_add_int (f, n);
01241         case COB_TYPE_NUMERIC_PACKED:
01242                 cob_add_packed (f, n);
01243                 return 0;
01244         default:
01245                 /* not optimized */
01246                 cob_decimal_set_field (&cob_d1, f);
01247                 mpz_set_si (cob_d2.value, n);
01248                 cob_d2.scale = 0;
01249                 if (cob_d1.scale) {
01250                         mpz_ui_pow_ui (cob_mexp, 10, (unsigned int)cob_d1.scale);
01251                         mpz_mul (cob_d2.value, cob_d2.value, cob_mexp);
01252                         cob_d2.scale = cob_d1.scale;
01253                 }
01254                 mpz_add (cob_d1.value, cob_d1.value, cob_d2.value);
01255                 return cob_decimal_get_field (&cob_d1, f, 0);
01256         }
01257 }
01258 
01259 int
01260 cob_sub_int (cob_field *f, const int n)
01261 {
01262         if (unlikely(n == 0)) {
01263                 return 0;
01264         }
01265         return cob_add_int (f, -n);
01266 }
01267 
01268 int
01269 cob_div_quotient (cob_field *dividend, cob_field *divisor,
01270                   cob_field *quotient, const int opt)
01271 {
01272         int     ret;
01273 
01274         cob_decimal_set_field (&cob_d1, dividend);
01275         cob_decimal_set_field (&cob_d2, divisor);
01276         cob_decimal_set (&cob_d3, &cob_d1);
01277 
01278         /* compute quotient */
01279         cob_decimal_div (&cob_d1, &cob_d2);
01280         if (cob_d1.scale == DECIMAL_NAN) {
01281                 cob_d3.scale = DECIMAL_NAN;
01282                 return cob_exception_code;
01283         }
01284 
01285         /* set quotient */
01286         cob_decimal_set (&cob_d4, &cob_d1);
01287         ret = cob_decimal_get_field (&cob_d1, quotient, opt);
01288 
01289         /* truncate digits from the quotient */
01290         shift_decimal (&cob_d4, COB_FIELD_SCALE(quotient) - cob_d4.scale);
01291 
01292         /* compute remainder */
01293         cob_decimal_mul (&cob_d4, &cob_d2);
01294         cob_decimal_sub (&cob_d3, &cob_d4);
01295 
01296         return ret;
01297 }
01298 
01299 int
01300 cob_div_remainder (cob_field *fld_remainder, const int opt)
01301 {
01302         return cob_decimal_get_field (&cob_d3, fld_remainder, opt);
01303 }
01304 
01305 int
01306 cob_cmp_int (cob_field *f1, const int n)
01307 {
01308         cob_decimal_set_field (&cob_d1, f1);
01309         mpz_set_si (cob_d2.value, n);
01310         cob_d2.scale = 0;
01311         return cob_decimal_cmp (&cob_d1, &cob_d2);
01312 }
01313 
01314 int
01315 cob_cmp_uint (cob_field *f1, const unsigned int n)
01316 {
01317         cob_decimal_set_field (&cob_d1, f1);
01318         mpz_set_ui (cob_d2.value, n);
01319         cob_d2.scale = 0;
01320         return cob_decimal_cmp (&cob_d1, &cob_d2);
01321 }
01322 
01323 int
01324 cob_numeric_cmp (cob_field *f1, cob_field *f2)
01325 {
01326         cob_decimal_set_field (&cob_d1, f1);
01327         cob_decimal_set_field (&cob_d2, f2);
01328         return cob_decimal_cmp (&cob_d1, &cob_d2);
01329 }
01330 
01331 int
01332 cob_cmp_packed (cob_field *f, int n)
01333 {
01334         static int              lastval = 0;
01335 
01336         unsigned char           *p;
01337         size_t                  size;
01338         size_t                  inc = 0;
01339         int                     sign;
01340         unsigned char           val1[20];
01341 
01342         sign = cob_packed_get_sign (f);
01343         /* Field positive, value negative */
01344         if (sign >= 0 && n < 0) {
01345                 return 1;
01346         }
01347         /* Field negative, value positive */
01348         if (sign < 0 && n >= 0) {
01349                 return -1;
01350         }
01351         /* Both positive or both negative */
01352         p = f->data;
01353         for (size = 0; size < 20; size++) {
01354                 if (size < 20 - f->size) {
01355                         val1[size] = 0;
01356                 } else {
01357                         val1[size] = p[inc++];
01358                 }
01359         }
01360         val1[19] &= 0xf0;
01361         if ((COB_FIELD_DIGITS(f) % 2) == 0) {
01362                 val1[20 - f->size] &= 0x0f;
01363         }
01364         if (n != lastval) {
01365                 lastval = n;
01366                 if (n < 0) {
01367                         n = -n;
01368                 }
01369                 memset (&packed_value[14], 0, 6);
01370                 if (n) {
01371                         p = &packed_value[19];
01372                         *p =  (n % 10) << 4;
01373                         p--;
01374                         n /= 10;
01375                         for (; n;) {
01376                                 size = n % 100;
01377                                 *p = (unsigned char)((size % 10) | ((size / 10) << 4));
01378                                 n /= 100;
01379                                 p--;
01380                         }
01381                 }
01382         }
01383         for (size = 0; size < 20; size++) {
01384                 if (val1[size] != packed_value[size]) {
01385                         if (sign < 0) {
01386                                 return packed_value[size] - val1[size];
01387                         } else {
01388                                 return val1[size] - packed_value[size];
01389                         }
01390                 }
01391         }
01392         return 0;
01393 }
01394 
01395 void
01396 cob_init_numeric (void)
01397 {
01398         size_t  i;
01399 
01400         cob_decimal_init (&cob_d1);
01401         cob_decimal_init (&cob_d2);
01402         cob_decimal_init (&cob_d3);
01403         cob_decimal_init (&cob_d4);
01404         mpz_init2 (cob_mpzt, 256);
01405         mpz_init2 (cob_mexp, 512);
01406         for (i = 0; i < COB_MAX_BINARY; i++) {
01407                 mpz_init (cob_mpze10[i]);
01408                 mpz_ui_pow_ui (cob_mpze10[i], 10, i);
01409         }
01410         num_buff_ptr = cob_malloc (2048);
01411         memset (packed_value, 0, sizeof(packed_value));
01412 }
01413 
01414 /* Numeric Display compares */
01415 
01416 int
01417 cob_cmp_numdisp (const unsigned char *data, const size_t size, const int n)
01418 {
01419         const unsigned char     *p;
01420         size_t                  inc;
01421         int                     val = 0;
01422 
01423         p = data;
01424         for (inc = 0; inc < size; inc++, p++) {
01425                 val = (val * 10) + (*p - (unsigned char)'0');
01426         }
01427         return (val < n) ? -1 : (val > n);
01428 }
01429 
01430 int
01431 cob_cmp_long_numdisp (const unsigned char *data, const size_t size, const int n)
01432 {
01433         const unsigned char     *p;
01434         long long               val = 0;
01435         size_t                  inc;
01436 
01437         p = data;
01438         for (inc = 0; inc < size; inc++, p++) {
01439                 val = (val * 10) + (*p - (unsigned char)'0');
01440         }
01441         return (val < n) ? -1 : (val > n);
01442 }
01443 
01444 #ifdef  COB_EBCDIC_MACHINE
01445 static void
01446 cob_get_ascii_sign (const unsigned char *p, int *val)
01447 {
01448         switch (*p) {
01449         case 'p':
01450                 return;
01451         case 'q':
01452                 *val += 1;
01453                 return;
01454         case 'r':
01455                 *val += 2;
01456                 return;
01457         case 's':
01458                 *val += 3;
01459                 return;
01460         case 't':
01461                 *val += 4;
01462                 return;
01463         case 'u':
01464                 *val += 5;
01465                 return;
01466         case 'v':
01467                 *val += 6;
01468                 return;
01469         case 'w':
01470                 *val += 7;
01471                 return;
01472         case 'x':
01473                 *val += 8;
01474                 return;
01475         case 'y':
01476                 *val += 9;
01477                 return;
01478         }
01479 }
01480 
01481 static void
01482 cob_get_long_ascii_sign (const unsigned char *p, long long *val)
01483 {
01484         switch (*p) {
01485         case 'p':
01486                 return;
01487         case 'q':
01488                 *val += 1;
01489                 return;
01490         case 'r':
01491                 *val += 2;
01492                 return;
01493         case 's':
01494                 *val += 3;
01495                 return;
01496         case 't':
01497                 *val += 4;
01498                 return;
01499         case 'u':
01500                 *val += 5;
01501                 return;
01502         case 'v':
01503                 *val += 6;
01504                 return;
01505         case 'w':
01506                 *val += 7;
01507                 return;
01508         case 'x':
01509                 *val += 8;
01510                 return;
01511         case 'y':
01512                 *val += 9;
01513                 return;
01514         }
01515 }
01516 #endif
01517 
01518 static int
01519 cob_get_ebcdic_sign (const unsigned char *p, int *val)
01520 {
01521         switch (*p) {
01522         case '{':
01523                 return 0;
01524         case 'A':
01525                 *val += 1;
01526                 return 0;
01527         case 'B':
01528                 *val += 2;
01529                 return 0;
01530         case 'C':
01531                 *val += 3;
01532                 return 0;
01533         case 'D':
01534                 *val += 4;
01535                 return 0;
01536         case 'E':
01537                 *val += 5;
01538                 return 0;
01539         case 'F':
01540                 *val += 6;
01541                 return 0;
01542         case 'G':
01543                 *val += 7;
01544                 return 0;
01545         case 'H':
01546                 *val += 8;
01547                 return 0;
01548         case 'I':
01549                 *val += 9;
01550                 return 0;
01551         case '}':
01552                 return 1;
01553         case 'J':
01554                 *val += 1;
01555                 return 1;
01556         case 'K':
01557                 *val += 2;
01558                 return 1;
01559         case 'L':
01560                 *val += 3;
01561                 return 1;
01562         case 'M':
01563                 *val += 4;
01564                 return 1;
01565         case 'N':
01566                 *val += 5;
01567                 return 1;
01568         case 'O':
01569                 *val += 6;
01570                 return 1;
01571         case 'P':
01572                 *val += 7;
01573                 return 1;
01574         case 'Q':
01575                 *val += 8;
01576                 return 1;
01577         case 'R':
01578                 *val += 9;
01579                 return 1;
01580         }
01581         return 0;
01582 }
01583 
01584 static int
01585 cob_get_long_ebcdic_sign (const unsigned char *p, long long *val)
01586 {
01587         switch (*p) {
01588         case '{':
01589                 return 0;
01590         case 'A':
01591                 *val += 1;
01592                 return 0;
01593         case 'B':
01594                 *val += 2;
01595                 return 0;
01596         case 'C':
01597                 *val += 3;
01598                 return 0;
01599         case 'D':
01600                 *val += 4;
01601                 return 0;
01602         case 'E':
01603                 *val += 5;
01604                 return 0;
01605         case 'F':
01606                 *val += 6;
01607                 return 0;
01608         case 'G':
01609                 *val += 7;
01610                 return 0;
01611         case 'H':
01612                 *val += 8;
01613                 return 0;
01614         case 'I':
01615                 *val += 9;
01616                 return 0;
01617         case '}':
01618                 return 1;
01619         case 'J':
01620                 *val += 1;
01621                 return 1;
01622         case 'K':
01623                 *val += 2;
01624                 return 1;
01625         case 'L':
01626                 *val += 3;
01627                 return 1;
01628         case 'M':
01629                 *val += 4;
01630                 return 1;
01631         case 'N':
01632                 *val += 5;
01633                 return 1;
01634         case 'O':
01635                 *val += 6;
01636                 return 1;
01637         case 'P':
01638                 *val += 7;
01639                 return 1;
01640         case 'Q':
01641                 *val += 8;
01642                 return 1;
01643         case 'R':
01644                 *val += 9;
01645                 return 1;
01646         }
01647         return 0;
01648 }
01649 
01650 int
01651 cob_cmp_sign_numdisp (const unsigned char *data, const size_t size, const int n)
01652 {
01653         const unsigned char     *p;
01654         int                     val = 0;
01655         size_t                  inc;
01656 
01657         p = data;
01658         for (inc = 0; inc < size - 1; inc++, p++) {
01659                 val = (val * 10) + (*p - (unsigned char)'0');
01660         }
01661         val *= 10;
01662         if (*p >= '0' && *p <= '9') {
01663                 val += (*p - (unsigned char)'0');
01664         } else {
01665                 if (unlikely(cob_current_module->display_sign)) {
01666                         if (cob_get_ebcdic_sign (p, &val)) {
01667                                 val = -val;
01668                         }
01669                 } else {
01670 #ifdef  COB_EBCDIC_MACHINE
01671                         cob_get_ascii_sign (p, &val);
01672 #else
01673                         val += (*p - (unsigned char)'p');
01674 #endif
01675                         val = -val;
01676                 }
01677         }
01678         return (val < n) ? -1 : (val > n);
01679 }
01680 
01681 int
01682 cob_cmp_long_sign_numdisp (const unsigned char *data, const size_t size, const int n)
01683 {
01684         const unsigned char     *p;
01685         long long               val = 0;
01686         size_t                  inc;
01687 
01688         p = data;
01689         for (inc = 0; inc < size - 1; inc++, p++) {
01690                 val = (val * 10) + (*p - (unsigned char)'0');
01691         }
01692         val *= 10;
01693         if (*p >= '0' && *p <= '9') {
01694                 val += (*p - (unsigned char)'0');
01695         } else {
01696                 if (unlikely(cob_current_module->display_sign)) {
01697                         if (cob_get_long_ebcdic_sign (p, &val)) {
01698                                 val = -val;
01699                         }
01700                 } else {
01701 #ifdef  COB_EBCDIC_MACHINE
01702                         cob_get_long_ascii_sign (p, &val);
01703 #else
01704                         val += (*p - (unsigned char)'p');
01705 #endif
01706                         val = -val;
01707                 }
01708         }
01709         return (val < n) ? -1 : (val > n);
01710 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines