xref: /dragonfly/contrib/gmp/mpz/mul.c (revision dcd37f7d)
1 /* mpz_mul -- Multiply two integers.
2 
3 Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005 Free Software Foundation,
4 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 3 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.  If not, see http://www.gnu.org/licenses/.  */
20 
21 #include <stdio.h> /* for NULL */
22 #include "gmp.h"
23 #include "gmp-impl.h"
24 #ifdef BERKELEY_MP
25 #include "mp.h"
26 #endif
27 
28 
29 void
30 #ifndef BERKELEY_MP
31 mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
32 #else /* BERKELEY_MP */
33 mult (mpz_srcptr u, mpz_srcptr v, mpz_ptr w)
34 #endif /* BERKELEY_MP */
35 {
36   mp_size_t usize = u->_mp_size;
37   mp_size_t vsize = v->_mp_size;
38   mp_size_t wsize;
39   mp_size_t sign_product;
40   mp_ptr up, vp;
41   mp_ptr wp;
42   mp_ptr free_me;
43   size_t free_me_size;
44   mp_limb_t cy_limb;
45   TMP_DECL;
46 
47   sign_product = usize ^ vsize;
48   usize = ABS (usize);
49   vsize = ABS (vsize);
50 
51   if (usize < vsize)
52     {
53       MPZ_SRCPTR_SWAP (u, v);
54       MP_SIZE_T_SWAP (usize, vsize);
55     }
56 
57   if (vsize == 0)
58     {
59       SIZ(w) = 0;
60       return;
61     }
62 
63 #if HAVE_NATIVE_mpn_mul_2
64   if (vsize <= 2)
65     {
66       MPZ_REALLOC (w, usize+vsize);
67       wp = PTR(w);
68       if (vsize == 1)
69         cy_limb = mpn_mul_1 (wp, PTR(u), usize, PTR(v)[0]);
70       else
71         {
72           cy_limb = mpn_mul_2 (wp, PTR(u), usize, PTR(v));
73           usize++;
74         }
75       wp[usize] = cy_limb;
76       usize += (cy_limb != 0);
77       SIZ(w) = (sign_product >= 0 ? usize : -usize);
78       return;
79     }
80 #else
81   if (vsize == 1)
82     {
83       MPZ_REALLOC (w, usize+1);
84       wp = PTR(w);
85       cy_limb = mpn_mul_1 (wp, PTR(u), usize, PTR(v)[0]);
86       wp[usize] = cy_limb;
87       usize += (cy_limb != 0);
88       SIZ(w) = (sign_product >= 0 ? usize : -usize);
89       return;
90     }
91 #endif
92 
93   TMP_MARK;
94   free_me = NULL;
95   up = u->_mp_d;
96   vp = v->_mp_d;
97   wp = w->_mp_d;
98 
99   /* Ensure W has space enough to store the result.  */
100   wsize = usize + vsize;
101   if (w->_mp_alloc < wsize)
102     {
103       if (wp == up || wp == vp)
104 	{
105 	  free_me = wp;
106 	  free_me_size = w->_mp_alloc;
107 	}
108       else
109 	(*__gmp_free_func) (wp, w->_mp_alloc * BYTES_PER_MP_LIMB);
110 
111       w->_mp_alloc = wsize;
112       wp = (mp_ptr) (*__gmp_allocate_func) (wsize * BYTES_PER_MP_LIMB);
113       w->_mp_d = wp;
114     }
115   else
116     {
117       /* Make U and V not overlap with W.  */
118       if (wp == up)
119 	{
120 	  /* W and U are identical.  Allocate temporary space for U.  */
121 	  up = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB);
122 	  /* Is V identical too?  Keep it identical with U.  */
123 	  if (wp == vp)
124 	    vp = up;
125 	  /* Copy to the temporary space.  */
126 	  MPN_COPY (up, wp, usize);
127 	}
128       else if (wp == vp)
129 	{
130 	  /* W and V are identical.  Allocate temporary space for V.  */
131 	  vp = (mp_ptr) TMP_ALLOC (vsize * BYTES_PER_MP_LIMB);
132 	  /* Copy to the temporary space.  */
133 	  MPN_COPY (vp, wp, vsize);
134 	}
135     }
136 
137   cy_limb = mpn_mul (wp, up, usize, vp, vsize);
138   wsize = usize + vsize;
139   wsize -= cy_limb == 0;
140 
141   w->_mp_size = sign_product < 0 ? -wsize : wsize;
142   if (free_me != NULL)
143     (*__gmp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
144   TMP_FREE;
145 }
146