Annotation of OpenXM_contrib/gmp/mpz/tests/t-mul.c, Revision 1.1
1.1 ! maekawa 1: /* Test mpz_add, mpz_cmp, mpz_cmp_ui, mpz_divmod, mpz_mul.
! 2:
! 3: Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
! 4:
! 5: This file is part of the GNU MP Library.
! 6:
! 7: The GNU MP Library is free software; you can redistribute it and/or modify
! 8: it under the terms of the GNU Library General Public License as published by
! 9: the Free Software Foundation; either version 2 of the License, or (at your
! 10: option) any later version.
! 11:
! 12: The GNU MP Library is distributed in the hope that it will be useful, but
! 13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
! 15: License for more details.
! 16:
! 17: You should have received a copy of the GNU Library General Public License
! 18: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
! 19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
! 20: MA 02111-1307, USA. */
! 21:
! 22: #include <stdio.h>
! 23: #include "gmp.h"
! 24: #include "gmp-impl.h"
! 25: #include "longlong.h"
! 26: #include "urandom.h"
! 27:
! 28: void debug_mp ();
! 29: mp_size_t _mpn_mul_classic ();
! 30: void mpz_refmul ();
! 31:
! 32: #ifndef SIZE
! 33: #define SIZE 128
! 34: #endif
! 35:
! 36: main (argc, argv)
! 37: int argc;
! 38: char **argv;
! 39: {
! 40: mpz_t multiplier, multiplicand;
! 41: mpz_t product, ref_product;
! 42: mpz_t quotient, remainder;
! 43: mp_size_t multiplier_size, multiplicand_size;
! 44: int i;
! 45: int reps = 10000;
! 46:
! 47: if (argc == 2)
! 48: reps = atoi (argv[1]);
! 49:
! 50: mpz_init (multiplier);
! 51: mpz_init (multiplicand);
! 52: mpz_init (product);
! 53: mpz_init (ref_product);
! 54: mpz_init (quotient);
! 55: mpz_init (remainder);
! 56:
! 57: for (i = 0; i < reps; i++)
! 58: {
! 59: multiplier_size = urandom () % SIZE - SIZE/2;
! 60: multiplicand_size = urandom () % SIZE - SIZE/2;
! 61:
! 62: mpz_random2 (multiplier, multiplier_size);
! 63: mpz_random2 (multiplicand, multiplicand_size);
! 64:
! 65: mpz_mul (product, multiplier, multiplicand);
! 66: mpz_refmul (ref_product, multiplier, multiplicand);
! 67: if (mpz_cmp_ui (multiplicand, 0) != 0)
! 68: mpz_divmod (quotient, remainder, product, multiplicand);
! 69:
! 70: if (mpz_cmp (product, ref_product))
! 71: dump_abort (multiplier, multiplicand);
! 72:
! 73: if (mpz_cmp_ui (multiplicand, 0) != 0)
! 74: if (mpz_cmp_ui (remainder, 0) || mpz_cmp (quotient, multiplier))
! 75: dump_abort (multiplier, multiplicand);
! 76: }
! 77:
! 78: exit (0);
! 79: }
! 80:
! 81: void
! 82: mpz_refmul (w, u, v)
! 83: mpz_t w;
! 84: const mpz_t u;
! 85: const mpz_t v;
! 86: {
! 87: mp_size_t usize = u->_mp_size;
! 88: mp_size_t vsize = v->_mp_size;
! 89: mp_size_t wsize;
! 90: mp_size_t sign_product;
! 91: mp_ptr up, vp;
! 92: mp_ptr wp;
! 93: mp_ptr free_me = NULL;
! 94: size_t free_me_size;
! 95: TMP_DECL (marker);
! 96:
! 97: TMP_MARK (marker);
! 98: sign_product = usize ^ vsize;
! 99: usize = ABS (usize);
! 100: vsize = ABS (vsize);
! 101:
! 102: if (usize < vsize)
! 103: {
! 104: /* Swap U and V. */
! 105: {const __mpz_struct *t = u; u = v; v = t;}
! 106: {mp_size_t t = usize; usize = vsize; vsize = t;}
! 107: }
! 108:
! 109: up = u->_mp_d;
! 110: vp = v->_mp_d;
! 111: wp = w->_mp_d;
! 112:
! 113: /* Ensure W has space enough to store the result. */
! 114: wsize = usize + vsize;
! 115: if (w->_mp_alloc < wsize)
! 116: {
! 117: if (wp == up || wp == vp)
! 118: {
! 119: free_me = wp;
! 120: free_me_size = w->_mp_alloc;
! 121: }
! 122: else
! 123: (*_mp_free_func) (wp, w->_mp_alloc * BYTES_PER_MP_LIMB);
! 124:
! 125: w->_mp_alloc = wsize;
! 126: wp = (mp_ptr) (*_mp_allocate_func) (wsize * BYTES_PER_MP_LIMB);
! 127: w->_mp_d = wp;
! 128: }
! 129: else
! 130: {
! 131: /* Make U and V not overlap with W. */
! 132: if (wp == up)
! 133: {
! 134: /* W and U are identical. Allocate temporary space for U. */
! 135: up = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB);
! 136: /* Is V identical too? Keep it identical with U. */
! 137: if (wp == vp)
! 138: vp = up;
! 139: /* Copy to the temporary space. */
! 140: MPN_COPY (up, wp, usize);
! 141: }
! 142: else if (wp == vp)
! 143: {
! 144: /* W and V are identical. Allocate temporary space for V. */
! 145: vp = (mp_ptr) TMP_ALLOC (vsize * BYTES_PER_MP_LIMB);
! 146: /* Copy to the temporary space. */
! 147: MPN_COPY (vp, wp, vsize);
! 148: }
! 149: }
! 150:
! 151: wsize = _mpn_mul_classic (wp, up, usize, vp, vsize);
! 152: w->_mp_size = sign_product < 0 ? -wsize : wsize;
! 153: if (free_me != NULL)
! 154: (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
! 155:
! 156: TMP_FREE (marker);
! 157: }
! 158:
! 159: mp_size_t
! 160: _mpn_mul_classic (prodp, up, usize, vp, vsize)
! 161: mp_ptr prodp;
! 162: mp_srcptr up;
! 163: mp_size_t usize;
! 164: mp_srcptr vp;
! 165: mp_size_t vsize;
! 166: {
! 167: mp_size_t i, j;
! 168: mp_limb_t prod_low, prod_high;
! 169: mp_limb_t cy_dig;
! 170: mp_limb_t v_limb, c;
! 171:
! 172: if (vsize == 0)
! 173: return 0;
! 174:
! 175: /* Offset UP and PRODP so that the inner loop can be faster. */
! 176: up += usize;
! 177: prodp += usize;
! 178:
! 179: /* Multiply by the first limb in V separately, as the result can
! 180: be stored (not added) to PROD. We also avoid a loop for zeroing. */
! 181: v_limb = vp[0];
! 182: cy_dig = 0;
! 183: j = -usize;
! 184: do
! 185: {
! 186: umul_ppmm (prod_high, prod_low, up[j], v_limb);
! 187: add_ssaaaa (cy_dig, prodp[j], prod_high, prod_low, 0, cy_dig);
! 188: j++;
! 189: }
! 190: while (j < 0);
! 191:
! 192: prodp[j] = cy_dig;
! 193: prodp++;
! 194:
! 195: /* For each iteration in the outer loop, multiply one limb from
! 196: U with one limb from V, and add it to PROD. */
! 197: for (i = 1; i < vsize; i++)
! 198: {
! 199: v_limb = vp[i];
! 200: cy_dig = 0;
! 201: j = -usize;
! 202:
! 203: /* Inner loops. Simulate the carry flag by jumping between
! 204: these loops. The first is used when there was no carry
! 205: in the previois iteration; the second when there was carry. */
! 206:
! 207: do
! 208: {
! 209: umul_ppmm (prod_high, prod_low, up[j], v_limb);
! 210: add_ssaaaa (cy_dig, prod_low, prod_high, prod_low, 0, cy_dig);
! 211: c = prodp[j];
! 212: prod_low += c;
! 213: prodp[j] = prod_low;
! 214: if (prod_low < c)
! 215: goto cy_loop;
! 216: ncy_loop:
! 217: j++;
! 218: }
! 219: while (j < 0);
! 220:
! 221: prodp[j] = cy_dig;
! 222: prodp++;
! 223: continue;
! 224:
! 225: do
! 226: {
! 227: umul_ppmm (prod_high, prod_low, up[j], v_limb);
! 228: add_ssaaaa (cy_dig, prod_low, prod_high, prod_low, 0, cy_dig);
! 229: c = prodp[j];
! 230: prod_low += c + 1;
! 231: prodp[j] = prod_low;
! 232: if (prod_low > c)
! 233: goto ncy_loop;
! 234: cy_loop:
! 235: j++;
! 236: }
! 237: while (j < 0);
! 238:
! 239: cy_dig += 1;
! 240: prodp[j] = cy_dig;
! 241: prodp++;
! 242: }
! 243:
! 244: return usize + vsize - (cy_dig == 0);
! 245: }
! 246:
! 247: dump_abort (multiplier, multiplicand)
! 248: mpz_t multiplier, multiplicand;
! 249: {
! 250: fprintf (stderr, "ERROR\n");
! 251: fprintf (stderr, "multiplier = "); debug_mp (multiplier, -16);
! 252: fprintf (stderr, "multiplicand = "); debug_mp (multiplicand, -16);
! 253: abort();
! 254: }
! 255:
! 256: void
! 257: debug_mp (x, base)
! 258: mpz_t x;
! 259: {
! 260: mpz_out_str (stderr, base, x); fputc ('\n', stderr);
! 261: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>