Line | Count | Source (jump to first uncovered line) |
1 | | /* mpz_mul -- Multiply two integers. |
2 | | |
3 | | Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2009, 2011, 2012, |
4 | | 2015 Free Software 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 either: |
10 | | |
11 | | * the GNU Lesser General Public License as published by the Free |
12 | | Software Foundation; either version 3 of the License, or (at your |
13 | | option) any later version. |
14 | | |
15 | | or |
16 | | |
17 | | * the GNU General Public License as published by the Free Software |
18 | | Foundation; either version 2 of the License, or (at your option) any |
19 | | later version. |
20 | | |
21 | | or both in parallel, as here. |
22 | | |
23 | | The GNU MP Library is distributed in the hope that it will be useful, but |
24 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
25 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
26 | | for more details. |
27 | | |
28 | | You should have received copies of the GNU General Public License and the |
29 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
30 | | see https://www.gnu.org/licenses/. */ |
31 | | |
32 | | #include <stdio.h> /* for NULL */ |
33 | | #include "gmp-impl.h" |
34 | | |
35 | | |
36 | | void |
37 | | mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v) |
38 | 0 | { |
39 | 0 | mp_size_t usize; |
40 | 0 | mp_size_t vsize; |
41 | 0 | mp_size_t wsize; |
42 | 0 | mp_size_t sign_product; |
43 | 0 | mp_ptr up, vp; |
44 | 0 | mp_ptr wp; |
45 | 0 | mp_ptr free_me; |
46 | 0 | size_t free_me_size; |
47 | 0 | mp_limb_t cy_limb; |
48 | 0 | TMP_DECL; |
49 | |
|
50 | 0 | usize = SIZ (u); |
51 | 0 | vsize = SIZ (v); |
52 | 0 | sign_product = usize ^ vsize; |
53 | 0 | usize = ABS (usize); |
54 | 0 | vsize = ABS (vsize); |
55 | |
|
56 | 0 | if (usize < vsize) |
57 | 0 | { |
58 | 0 | MPZ_SRCPTR_SWAP (u, v); |
59 | 0 | MP_SIZE_T_SWAP (usize, vsize); |
60 | 0 | } |
61 | |
|
62 | 0 | if (vsize == 0) |
63 | 0 | { |
64 | 0 | SIZ (w) = 0; |
65 | 0 | return; |
66 | 0 | } |
67 | | |
68 | | #if HAVE_NATIVE_mpn_mul_2 |
69 | | if (vsize <= 2) |
70 | | { |
71 | | wp = MPZ_REALLOC (w, usize+vsize); |
72 | | if (vsize == 1) |
73 | | cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]); |
74 | | else |
75 | | { |
76 | | cy_limb = mpn_mul_2 (wp, PTR (u), usize, PTR (v)); |
77 | | usize++; |
78 | | } |
79 | | wp[usize] = cy_limb; |
80 | | usize += (cy_limb != 0); |
81 | | SIZ (w) = (sign_product >= 0 ? usize : -usize); |
82 | | return; |
83 | | } |
84 | | #else |
85 | 0 | if (vsize == 1) |
86 | 0 | { |
87 | 0 | wp = MPZ_REALLOC (w, usize+1); |
88 | 0 | cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]); |
89 | 0 | wp[usize] = cy_limb; |
90 | 0 | usize += (cy_limb != 0); |
91 | 0 | SIZ (w) = (sign_product >= 0 ? usize : -usize); |
92 | 0 | return; |
93 | 0 | } |
94 | 0 | #endif |
95 | | |
96 | 0 | TMP_MARK; |
97 | 0 | free_me = NULL; |
98 | 0 | up = PTR (u); |
99 | 0 | vp = PTR (v); |
100 | 0 | wp = PTR (w); |
101 | | |
102 | | /* Ensure W has space enough to store the result. */ |
103 | 0 | wsize = usize + vsize; |
104 | 0 | if (ALLOC (w) < wsize) |
105 | 0 | { |
106 | 0 | if (ALLOC (w) != 0) |
107 | 0 | { |
108 | 0 | if (wp == up || wp == vp) |
109 | 0 | { |
110 | 0 | free_me = wp; |
111 | 0 | free_me_size = ALLOC (w); |
112 | 0 | } |
113 | 0 | else |
114 | 0 | (*__gmp_free_func) (wp, (size_t) ALLOC (w) * GMP_LIMB_BYTES); |
115 | 0 | } |
116 | |
|
117 | 0 | ALLOC (w) = wsize; |
118 | 0 | wp = __GMP_ALLOCATE_FUNC_LIMBS (wsize); |
119 | 0 | PTR (w) = wp; |
120 | 0 | } |
121 | 0 | else |
122 | 0 | { |
123 | | /* Make U and V not overlap with W. */ |
124 | 0 | if (wp == up) |
125 | 0 | { |
126 | | /* W and U are identical. Allocate temporary space for U. */ |
127 | 0 | up = TMP_ALLOC_LIMBS (usize); |
128 | | /* Is V identical too? Keep it identical with U. */ |
129 | 0 | if (wp == vp) |
130 | 0 | vp = up; |
131 | | /* Copy to the temporary space. */ |
132 | 0 | MPN_COPY (up, wp, usize); |
133 | 0 | } |
134 | 0 | else if (wp == vp) |
135 | 0 | { |
136 | | /* W and V are identical. Allocate temporary space for V. */ |
137 | 0 | vp = TMP_ALLOC_LIMBS (vsize); |
138 | | /* Copy to the temporary space. */ |
139 | 0 | MPN_COPY (vp, wp, vsize); |
140 | 0 | } |
141 | 0 | } |
142 | |
|
143 | 0 | if (up == vp) |
144 | 0 | { |
145 | 0 | mpn_sqr (wp, up, usize); |
146 | 0 | cy_limb = wp[wsize - 1]; |
147 | 0 | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | cy_limb = mpn_mul (wp, up, usize, vp, vsize); |
151 | 0 | } |
152 | |
|
153 | 0 | wsize -= cy_limb == 0; |
154 | |
|
155 | 0 | SIZ (w) = sign_product < 0 ? -wsize : wsize; |
156 | 0 | if (free_me != NULL) |
157 | 0 | (*__gmp_free_func) (free_me, free_me_size * GMP_LIMB_BYTES); |
158 | 0 | TMP_FREE; |
159 | 0 | } |