xref: /dflybsd-src/contrib/gmp/mpz/mul.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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