Import gmp-4.3.1
[dragonfly.git] / contrib / gmp / mpz / mul.c
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 }