[BACK]Return to t-mul.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / tests / mpz

Annotation of OpenXM_contrib/gmp/tests/mpz/t-mul.c, Revision 1.1.1.1

1.1       ohara       1: /* Test mpz_cmp, mpz_cmp_ui, mpz_tdiv_qr, mpz_mul.
                      2:
                      3: Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002 Free Software
                      4: Foundation, Inc.
                      5:
                      6: This file is part of the GNU MP Library.
                      7:
                      8: The GNU MP Library is free software; you can redistribute it and/or modify
                      9: it under the terms of the GNU Lesser General Public License as published by
                     10: the Free Software Foundation; either version 2.1 of the License, or (at your
                     11: option) any later version.
                     12:
                     13: The GNU MP Library is distributed in the hope that it will be useful, but
                     14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     15: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     16: License for more details.
                     17:
                     18: You should have received a copy of the GNU Lesser General Public License
                     19: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     21: MA 02111-1307, USA. */
                     22:
                     23: #include <stdio.h>
                     24: #include <stdlib.h>
                     25:
                     26: #include "gmp.h"
                     27: #include "gmp-impl.h"
                     28: #include "longlong.h"
                     29: #include "tests.h"
                     30:
                     31: void debug_mp _PROTO ((mpz_t, int));
                     32: static void base_mul _PROTO ((mp_ptr,mp_srcptr,mp_size_t,mp_srcptr,mp_size_t));
                     33: static void ref_mpz_mul _PROTO ((mpz_t, const mpz_t, const mpz_t));
                     34: void dump_abort _PROTO ((int, char *, mpz_t, mpz_t, mpz_t, mpz_t));
                     35:
                     36: int
                     37: main (int argc, char **argv)
                     38: {
                     39:   mpz_t multiplier, multiplicand;
                     40:   mpz_t product, ref_product;
                     41:   mpz_t quotient, remainder;
                     42:   mp_size_t multiplier_size, multiplicand_size;
                     43:   int i;
                     44:   int reps = 100;
                     45:   gmp_randstate_ptr rands;
                     46:   mpz_t bs;
                     47:   unsigned long bsi, size_range;
                     48:
                     49:   tests_start ();
                     50:   rands = RANDS;
                     51:
                     52:   mpz_init (bs);
                     53:
                     54:   if (argc == 2)
                     55:      reps = atoi (argv[1]);
                     56:
                     57:   mpz_init (multiplier);
                     58:   mpz_init (multiplicand);
                     59:   mpz_init (product);
                     60:   mpz_init (ref_product);
                     61:   mpz_init (quotient);
                     62:   mpz_init (remainder);
                     63:
                     64:   for (i = 0; i < reps; i++)
                     65:     {
                     66:       mpz_urandomb (bs, rands, 32);
                     67:       size_range = mpz_get_ui (bs) % 18 + 2;
                     68:
                     69:       mpz_urandomb (bs, rands, size_range);
                     70:       multiplier_size = mpz_get_ui (bs);
                     71:       mpz_rrandomb (multiplier, rands, multiplier_size);
                     72:
                     73:       mpz_urandomb (bs, rands, size_range);
                     74:       multiplicand_size = mpz_get_ui (bs);
                     75:       mpz_rrandomb (multiplicand, rands, multiplicand_size);
                     76:
                     77:       mpz_urandomb (bs, rands, 2);
                     78:       bsi = mpz_get_ui (bs);
                     79:       if ((bsi & 1) != 0)
                     80:        mpz_neg (multiplier, multiplier);
                     81:       if ((bsi & 2) != 0)
                     82:        mpz_neg (multiplicand, multiplicand);
                     83:
                     84:       /* printf ("%ld %ld\n", SIZ (multiplier), SIZ (multiplicand)); */
                     85:
                     86:       mpz_mul (product, multiplier, multiplicand);
                     87:
                     88:       if (size_range <= 16)  /* avoid calling ref_mpz_mul for huge operands */
                     89:        {
                     90:          ref_mpz_mul (ref_product, multiplier, multiplicand);
                     91:          if (mpz_cmp (product, ref_product))
                     92:            dump_abort (i, "incorrect plain product",
                     93:                        multiplier, multiplicand, product, ref_product);
                     94:        }
                     95:
                     96:       if (mpz_cmp_ui (multiplicand, 0) != 0)
                     97:        {
                     98:          mpz_tdiv_qr (quotient, remainder, product, multiplicand);
                     99:          if (mpz_cmp_ui (remainder, 0) || mpz_cmp (quotient, multiplier))
                    100:            {
                    101:              debug_mp (quotient, -16);
                    102:              debug_mp (remainder, -16);
                    103:              dump_abort (i, "incorrect quotient or remainder",
                    104:                          multiplier, multiplicand, product, ref_product);
                    105:            }
                    106:        }
                    107:
                    108:       /* Test squaring.  */
                    109:       if (size_range <= 16)  /* avoid calling ref_mpz_mul for huge operands */
                    110:        {
                    111:          mpz_mul (product, multiplier, multiplier);
                    112:          ref_mpz_mul (ref_product, multiplier, multiplier);
                    113:        }
                    114:       else
                    115:        {
                    116:          mpz_mul (product, multiplier, multiplier);
                    117:          mpz_set (multiplicand, multiplier);
                    118:          mpz_mul (ref_product, multiplier, multiplicand);
                    119:        }
                    120:
                    121:       if (mpz_cmp (product, ref_product))
                    122:        dump_abort (i, "incorrect square product",
                    123:                    multiplier, multiplier, product, ref_product);
                    124:     }
                    125:
                    126:   mpz_clear (bs);
                    127:   mpz_clear (multiplier);
                    128:   mpz_clear (multiplicand);
                    129:   mpz_clear (product);
                    130:   mpz_clear (ref_product);
                    131:   mpz_clear (quotient);
                    132:   mpz_clear (remainder);
                    133:
                    134:   tests_end ();
                    135:   exit (0);
                    136: }
                    137:
                    138: static void
                    139: ref_mpz_mul (mpz_t w, const mpz_t u, const mpz_t v)
                    140: {
                    141:   mp_size_t usize = u->_mp_size;
                    142:   mp_size_t vsize = v->_mp_size;
                    143:   mp_size_t wsize;
                    144:   mp_size_t sign_product;
                    145:   mp_ptr up, vp;
                    146:   mp_ptr wp;
                    147:   mp_ptr free_me = NULL;
                    148:   size_t free_me_size;
                    149:   TMP_DECL (marker);
                    150:
                    151:   TMP_MARK (marker);
                    152:   sign_product = usize ^ vsize;
                    153:   usize = ABS (usize);
                    154:   vsize = ABS (vsize);
                    155:
                    156:   if (usize < vsize)
                    157:     {
                    158:       /* Swap U and V.  */
                    159:       {const __mpz_struct *t = u; u = v; v = t;}
                    160:       {mp_size_t t = usize; usize = vsize; vsize = t;}
                    161:     }
                    162:
                    163:   if (vsize == 0)
                    164:     {
                    165:       SIZ (w) = 0;
                    166:       return;
                    167:     }
                    168:
                    169:   up = u->_mp_d;
                    170:   vp = v->_mp_d;
                    171:   wp = w->_mp_d;
                    172:
                    173:   /* Ensure W has space enough to store the result.  */
                    174:   wsize = usize + vsize;
                    175:   if (w->_mp_alloc < wsize)
                    176:     {
                    177:       if (wp == up || wp == vp)
                    178:        {
                    179:          free_me = wp;
                    180:          free_me_size = w->_mp_alloc;
                    181:        }
                    182:       else
                    183:        (*__gmp_free_func) (wp, w->_mp_alloc * BYTES_PER_MP_LIMB);
                    184:
                    185:       w->_mp_alloc = wsize;
                    186:       wp = (mp_ptr) (*__gmp_allocate_func) (wsize * BYTES_PER_MP_LIMB);
                    187:       w->_mp_d = wp;
                    188:     }
                    189:   else
                    190:     {
                    191:       /* Make U and V not overlap with W.  */
                    192:       if (wp == up)
                    193:        {
                    194:          /* W and U are identical.  Allocate temporary space for U.  */
                    195:          up = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB);
                    196:          /* Is V identical too?  Keep it identical with U.  */
                    197:          if (wp == vp)
                    198:            vp = up;
                    199:          /* Copy to the temporary space.  */
                    200:          MPN_COPY (up, wp, usize);
                    201:        }
                    202:       else if (wp == vp)
                    203:        {
                    204:          /* W and V are identical.  Allocate temporary space for V.  */
                    205:          vp = (mp_ptr) TMP_ALLOC (vsize * BYTES_PER_MP_LIMB);
                    206:          /* Copy to the temporary space.  */
                    207:          MPN_COPY (vp, wp, vsize);
                    208:        }
                    209:     }
                    210:
                    211:   base_mul (wp, up, usize, vp, vsize);
                    212:   wsize = usize + vsize;
                    213:   wsize -= wp[wsize - 1] == 0;
                    214:   w->_mp_size = sign_product < 0 ? -wsize : wsize;
                    215:   if (free_me != NULL)
                    216:     (*__gmp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
                    217:
                    218:   TMP_FREE (marker);
                    219: }
                    220:
                    221: static void
                    222: base_mul (mp_ptr wp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
                    223: {
                    224:   mp_size_t i, j;
                    225:   mp_limb_t prod_low, prod_high;
                    226:   mp_limb_t cy_dig;
                    227:   mp_limb_t v_limb;
                    228:
                    229:   /* Multiply by the first limb in V separately, as the result can
                    230:      be stored (not added) to PROD.  We also avoid a loop for zeroing.  */
                    231:   v_limb = vp[0];
                    232:   cy_dig = 0;
                    233:   for (j = un; j > 0; j--)
                    234:     {
                    235:       mp_limb_t u_limb, w_limb;
                    236:       u_limb = *up++;
                    237:       umul_ppmm (prod_high, prod_low, u_limb, v_limb << GMP_NAIL_BITS);
                    238:       add_ssaaaa (cy_dig, w_limb, prod_high, prod_low, 0, cy_dig << GMP_NAIL_BITS);
                    239:       *wp++ = w_limb >> GMP_NAIL_BITS;
                    240:     }
                    241:
                    242:   *wp++ = cy_dig;
                    243:   wp -= un;
                    244:   up -= un;
                    245:
                    246:   /* For each iteration in the outer loop, multiply one limb from
                    247:      U with one limb from V, and add it to PROD.  */
                    248:   for (i = 1; i < vn; i++)
                    249:     {
                    250:       v_limb = vp[i];
                    251:       cy_dig = 0;
                    252:
                    253:       for (j = un; j > 0; j--)
                    254:        {
                    255:          mp_limb_t u_limb, w_limb;
                    256:          u_limb = *up++;
                    257:          umul_ppmm (prod_high, prod_low, u_limb, v_limb << GMP_NAIL_BITS);
                    258:          w_limb = *wp;
                    259:          add_ssaaaa (prod_high, prod_low, prod_high, prod_low, 0, w_limb << GMP_NAIL_BITS);
                    260:          prod_low >>= GMP_NAIL_BITS;
                    261:          prod_low += cy_dig;
                    262: #if GMP_NAIL_BITS == 0
                    263:          cy_dig = prod_high + (prod_low < cy_dig);
                    264: #else
                    265:          cy_dig = prod_high;
                    266:          cy_dig += prod_low >> GMP_NUMB_BITS;
                    267: #endif
                    268:          *wp++ = prod_low & GMP_NUMB_MASK;
                    269:        }
                    270:
                    271:       *wp++ = cy_dig;
                    272:       wp -= un;
                    273:       up -= un;
                    274:     }
                    275: }
                    276:
                    277: void
                    278: dump_abort (int i, char *s,
                    279:            mpz_t multiplier, mpz_t multiplicand, mpz_t product, mpz_t ref_product)
                    280: {
                    281:   mpz_t diff;
                    282:   fprintf (stderr, "ERROR: %s in test %d\n", s, i);
                    283:   fprintf (stderr, "multiplier   = "); debug_mp (multiplier, -16);
                    284:   fprintf (stderr, "multiplicand = "); debug_mp (multiplicand, -16);
                    285:   fprintf (stderr, "    product  = "); debug_mp (product, -16);
                    286:   fprintf (stderr, "ref_product  = "); debug_mp (ref_product, -16);
                    287:   mpz_init (diff);
                    288:   mpz_sub (diff, ref_product, product);
                    289:   fprintf (stderr, "diff:         "); debug_mp (diff, -16);
                    290:   abort();
                    291: }
                    292:
                    293: void
                    294: debug_mp (mpz_t x, int base)
                    295: {
                    296:   mpz_out_str (stderr, base, x); fputc ('\n', stderr);
                    297: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>