186d7f5d3SJohn Marino /* mpz_mul -- Multiply two integers.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2009, 2011 Free
486d7f5d3SJohn Marino Software Foundation, Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino This file is part of the GNU MP Library.
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1186d7f5d3SJohn Marino option) any later version.
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1486d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1586d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
1686d7f5d3SJohn Marino License for more details.
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
1986d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino #include <stdio.h> /* for NULL */
2286d7f5d3SJohn Marino #include "gmp.h"
2386d7f5d3SJohn Marino #include "gmp-impl.h"
2486d7f5d3SJohn Marino #ifdef BERKELEY_MP
2586d7f5d3SJohn Marino #include "mp.h"
2686d7f5d3SJohn Marino #endif
2786d7f5d3SJohn Marino
2886d7f5d3SJohn Marino
2986d7f5d3SJohn Marino void
3086d7f5d3SJohn Marino #ifndef BERKELEY_MP
mpz_mul(mpz_ptr w,mpz_srcptr u,mpz_srcptr v)3186d7f5d3SJohn Marino mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
3286d7f5d3SJohn Marino #else /* BERKELEY_MP */
3386d7f5d3SJohn Marino mult (mpz_srcptr u, mpz_srcptr v, mpz_ptr w)
3486d7f5d3SJohn Marino #endif /* BERKELEY_MP */
3586d7f5d3SJohn Marino {
3686d7f5d3SJohn Marino mp_size_t usize;
3786d7f5d3SJohn Marino mp_size_t vsize;
3886d7f5d3SJohn Marino mp_size_t wsize;
3986d7f5d3SJohn Marino mp_size_t sign_product;
4086d7f5d3SJohn Marino mp_ptr up, vp;
4186d7f5d3SJohn Marino mp_ptr wp;
4286d7f5d3SJohn Marino mp_ptr free_me;
4386d7f5d3SJohn Marino size_t free_me_size;
4486d7f5d3SJohn Marino mp_limb_t cy_limb;
4586d7f5d3SJohn Marino TMP_DECL;
4686d7f5d3SJohn Marino
4786d7f5d3SJohn Marino usize = SIZ (u);
4886d7f5d3SJohn Marino vsize = SIZ (v);
4986d7f5d3SJohn Marino sign_product = usize ^ vsize;
5086d7f5d3SJohn Marino usize = ABS (usize);
5186d7f5d3SJohn Marino vsize = ABS (vsize);
5286d7f5d3SJohn Marino
5386d7f5d3SJohn Marino if (usize < vsize)
5486d7f5d3SJohn Marino {
5586d7f5d3SJohn Marino MPZ_SRCPTR_SWAP (u, v);
5686d7f5d3SJohn Marino MP_SIZE_T_SWAP (usize, vsize);
5786d7f5d3SJohn Marino }
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino if (vsize == 0)
6086d7f5d3SJohn Marino {
6186d7f5d3SJohn Marino SIZ(w) = 0;
6286d7f5d3SJohn Marino return;
6386d7f5d3SJohn Marino }
6486d7f5d3SJohn Marino
6586d7f5d3SJohn Marino #if HAVE_NATIVE_mpn_mul_2
6686d7f5d3SJohn Marino if (vsize <= 2)
6786d7f5d3SJohn Marino {
6886d7f5d3SJohn Marino MPZ_REALLOC (w, usize+vsize);
6986d7f5d3SJohn Marino wp = PTR(w);
7086d7f5d3SJohn Marino if (vsize == 1)
7186d7f5d3SJohn Marino cy_limb = mpn_mul_1 (wp, PTR(u), usize, PTR(v)[0]);
7286d7f5d3SJohn Marino else
7386d7f5d3SJohn Marino {
7486d7f5d3SJohn Marino cy_limb = mpn_mul_2 (wp, PTR(u), usize, PTR(v));
7586d7f5d3SJohn Marino usize++;
7686d7f5d3SJohn Marino }
7786d7f5d3SJohn Marino wp[usize] = cy_limb;
7886d7f5d3SJohn Marino usize += (cy_limb != 0);
7986d7f5d3SJohn Marino SIZ(w) = (sign_product >= 0 ? usize : -usize);
8086d7f5d3SJohn Marino return;
8186d7f5d3SJohn Marino }
8286d7f5d3SJohn Marino #else
8386d7f5d3SJohn Marino if (vsize == 1)
8486d7f5d3SJohn Marino {
8586d7f5d3SJohn Marino MPZ_REALLOC (w, usize+1);
8686d7f5d3SJohn Marino wp = PTR(w);
8786d7f5d3SJohn Marino cy_limb = mpn_mul_1 (wp, PTR(u), usize, PTR(v)[0]);
8886d7f5d3SJohn Marino wp[usize] = cy_limb;
8986d7f5d3SJohn Marino usize += (cy_limb != 0);
9086d7f5d3SJohn Marino SIZ(w) = (sign_product >= 0 ? usize : -usize);
9186d7f5d3SJohn Marino return;
9286d7f5d3SJohn Marino }
9386d7f5d3SJohn Marino #endif
9486d7f5d3SJohn Marino
9586d7f5d3SJohn Marino TMP_MARK;
9686d7f5d3SJohn Marino free_me = NULL;
9786d7f5d3SJohn Marino up = PTR(u);
9886d7f5d3SJohn Marino vp = PTR(v);
9986d7f5d3SJohn Marino wp = PTR(w);
10086d7f5d3SJohn Marino
10186d7f5d3SJohn Marino /* Ensure W has space enough to store the result. */
10286d7f5d3SJohn Marino wsize = usize + vsize;
10386d7f5d3SJohn Marino if (ALLOC(w) < wsize)
10486d7f5d3SJohn Marino {
10586d7f5d3SJohn Marino if (wp == up || wp == vp)
10686d7f5d3SJohn Marino {
10786d7f5d3SJohn Marino free_me = wp;
10886d7f5d3SJohn Marino free_me_size = ALLOC(w);
10986d7f5d3SJohn Marino }
11086d7f5d3SJohn Marino else
11186d7f5d3SJohn Marino (*__gmp_free_func) (wp, ALLOC(w) * BYTES_PER_MP_LIMB);
11286d7f5d3SJohn Marino
11386d7f5d3SJohn Marino ALLOC(w) = wsize;
11486d7f5d3SJohn Marino wp = (mp_ptr) (*__gmp_allocate_func) (wsize * BYTES_PER_MP_LIMB);
11586d7f5d3SJohn Marino PTR(w) = wp;
11686d7f5d3SJohn Marino }
11786d7f5d3SJohn Marino else
11886d7f5d3SJohn Marino {
11986d7f5d3SJohn Marino /* Make U and V not overlap with W. */
12086d7f5d3SJohn Marino if (wp == up)
12186d7f5d3SJohn Marino {
12286d7f5d3SJohn Marino /* W and U are identical. Allocate temporary space for U. */
12386d7f5d3SJohn Marino up = TMP_ALLOC_LIMBS (usize);
12486d7f5d3SJohn Marino /* Is V identical too? Keep it identical with U. */
12586d7f5d3SJohn Marino if (wp == vp)
12686d7f5d3SJohn Marino vp = up;
12786d7f5d3SJohn Marino /* Copy to the temporary space. */
12886d7f5d3SJohn Marino MPN_COPY (up, wp, usize);
12986d7f5d3SJohn Marino }
13086d7f5d3SJohn Marino else if (wp == vp)
13186d7f5d3SJohn Marino {
13286d7f5d3SJohn Marino /* W and V are identical. Allocate temporary space for V. */
13386d7f5d3SJohn Marino vp = TMP_ALLOC_LIMBS (vsize);
13486d7f5d3SJohn Marino /* Copy to the temporary space. */
13586d7f5d3SJohn Marino MPN_COPY (vp, wp, vsize);
13686d7f5d3SJohn Marino }
13786d7f5d3SJohn Marino }
13886d7f5d3SJohn Marino
13986d7f5d3SJohn Marino if (up == vp)
14086d7f5d3SJohn Marino {
14186d7f5d3SJohn Marino mpn_sqr (wp, up, usize);
14286d7f5d3SJohn Marino cy_limb = wp[wsize - 1];
14386d7f5d3SJohn Marino }
14486d7f5d3SJohn Marino else
14586d7f5d3SJohn Marino {
14686d7f5d3SJohn Marino cy_limb = mpn_mul (wp, up, usize, vp, vsize);
14786d7f5d3SJohn Marino }
14886d7f5d3SJohn Marino
14986d7f5d3SJohn Marino wsize -= cy_limb == 0;
15086d7f5d3SJohn Marino
15186d7f5d3SJohn Marino SIZ(w) = sign_product < 0 ? -wsize : wsize;
15286d7f5d3SJohn Marino if (free_me != NULL)
15386d7f5d3SJohn Marino (*__gmp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
15486d7f5d3SJohn Marino TMP_FREE;
15586d7f5d3SJohn Marino }
156