[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     ! 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>