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>