Blame stdlib/mul.c

Packit Service 82fcde
/* mpn_mul -- Multiply two natural numbers.
Packit Service 82fcde
Packit Service 82fcde
Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit Service 82fcde
Packit Service 82fcde
This file is part of the GNU MP Library.
Packit Service 82fcde
Packit Service 82fcde
The GNU MP Library is free software; you can redistribute it and/or modify
Packit Service 82fcde
it under the terms of the GNU Lesser General Public License as published by
Packit Service 82fcde
the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 82fcde
option) any later version.
Packit Service 82fcde
Packit Service 82fcde
The GNU MP Library is distributed in the hope that it will be useful, but
Packit Service 82fcde
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 82fcde
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 82fcde
License for more details.
Packit Service 82fcde
Packit Service 82fcde
You should have received a copy of the GNU Lesser General Public License
Packit Service 82fcde
along with the GNU MP Library; see the file COPYING.LIB.  If not, see
Packit Service 82fcde
<http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <gmp.h>
Packit Service 82fcde
#include "gmp-impl.h"
Packit Service 82fcde
Packit Service 82fcde
/* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
Packit Service 82fcde
   and v (pointed to by VP, with VSIZE limbs), and store the result at
Packit Service 82fcde
   PRODP.  USIZE + VSIZE limbs are always stored, but if the input
Packit Service 82fcde
   operands are normalized.  Return the most significant limb of the
Packit Service 82fcde
   result.
Packit Service 82fcde
Packit Service 82fcde
   NOTE: The space pointed to by PRODP is overwritten before finished
Packit Service 82fcde
   with U and V, so overlap is an error.
Packit Service 82fcde
Packit Service 82fcde
   Argument constraints:
Packit Service 82fcde
   1. USIZE >= VSIZE.
Packit Service 82fcde
   2. PRODP != UP and PRODP != VP, i.e. the destination
Packit Service 82fcde
      must be distinct from the multiplier and the multiplicand.  */
Packit Service 82fcde
Packit Service 82fcde
/* If KARATSUBA_THRESHOLD is not already defined, define it to a
Packit Service 82fcde
   value which is good on most machines.  */
Packit Service 82fcde
#ifndef KARATSUBA_THRESHOLD
Packit Service 82fcde
#define KARATSUBA_THRESHOLD 32
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
mp_limb_t
Packit Service 82fcde
mpn_mul (mp_ptr prodp,
Packit Service 82fcde
	 mp_srcptr up, mp_size_t usize,
Packit Service 82fcde
	 mp_srcptr vp, mp_size_t vsize)
Packit Service 82fcde
{
Packit Service 82fcde
  mp_ptr prod_endp = prodp + usize + vsize - 1;
Packit Service 82fcde
  mp_limb_t cy;
Packit Service 82fcde
  mp_ptr tspace;
Packit Service 82fcde
  TMP_DECL (marker);
Packit Service 82fcde
Packit Service 82fcde
  if (vsize < KARATSUBA_THRESHOLD)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Handle simple cases with traditional multiplication.
Packit Service 82fcde
Packit Service 82fcde
	 This is the most critical code of the entire function.  All
Packit Service 82fcde
	 multiplies rely on this, both small and huge.  Small ones arrive
Packit Service 82fcde
	 here immediately.  Huge ones arrive here as this is the base case
Packit Service 82fcde
	 for Karatsuba's recursive algorithm below.  */
Packit Service 82fcde
      mp_size_t i;
Packit Service 82fcde
      mp_limb_t cy_limb;
Packit Service 82fcde
      mp_limb_t v_limb;
Packit Service 82fcde
Packit Service 82fcde
      if (vsize == 0)
Packit Service 82fcde
	return 0;
Packit Service 82fcde
Packit Service 82fcde
      /* Multiply by the first limb in V separately, as the result can be
Packit Service 82fcde
	 stored (not added) to PROD.  We also avoid a loop for zeroing.  */
Packit Service 82fcde
      v_limb = vp[0];
Packit Service 82fcde
      if (v_limb <= 1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (v_limb == 1)
Packit Service 82fcde
	    MPN_COPY (prodp, up, usize);
Packit Service 82fcde
	  else
Packit Service 82fcde
	    MPN_ZERO (prodp, usize);
Packit Service 82fcde
	  cy_limb = 0;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	cy_limb = mpn_mul_1 (prodp, up, usize, v_limb);
Packit Service 82fcde
Packit Service 82fcde
      prodp[usize] = cy_limb;
Packit Service 82fcde
      prodp++;
Packit Service 82fcde
Packit Service 82fcde
      /* For each iteration in the outer loop, multiply one limb from
Packit Service 82fcde
	 U with one limb from V, and add it to PROD.  */
Packit Service 82fcde
      for (i = 1; i < vsize; i++)
Packit Service 82fcde
	{
Packit Service 82fcde
	  v_limb = vp[i];
Packit Service 82fcde
	  if (v_limb <= 1)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      cy_limb = 0;
Packit Service 82fcde
	      if (v_limb == 1)
Packit Service 82fcde
		cy_limb = mpn_add_n (prodp, prodp, up, usize);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    cy_limb = mpn_addmul_1 (prodp, up, usize, v_limb);
Packit Service 82fcde
Packit Service 82fcde
	  prodp[usize] = cy_limb;
Packit Service 82fcde
	  prodp++;
Packit Service 82fcde
	}
Packit Service 82fcde
      return cy_limb;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  TMP_MARK (marker);
Packit Service 82fcde
Packit Service 82fcde
  tspace = (mp_ptr) TMP_ALLOC (2 * vsize * BYTES_PER_MP_LIMB);
Packit Service 82fcde
  MPN_MUL_N_RECURSE (prodp, up, vp, vsize, tspace);
Packit Service 82fcde
Packit Service 82fcde
  prodp += vsize;
Packit Service 82fcde
  up += vsize;
Packit Service 82fcde
  usize -= vsize;
Packit Service 82fcde
  if (usize >= vsize)
Packit Service 82fcde
    {
Packit Service 82fcde
      mp_ptr tp = (mp_ptr) TMP_ALLOC (2 * vsize * BYTES_PER_MP_LIMB);
Packit Service 82fcde
      do
Packit Service 82fcde
	{
Packit Service 82fcde
	  MPN_MUL_N_RECURSE (tp, up, vp, vsize, tspace);
Packit Service 82fcde
	  cy = mpn_add_n (prodp, prodp, tp, vsize);
Packit Service 82fcde
	  mpn_add_1 (prodp + vsize, tp + vsize, vsize, cy);
Packit Service 82fcde
	  prodp += vsize;
Packit Service 82fcde
	  up += vsize;
Packit Service 82fcde
	  usize -= vsize;
Packit Service 82fcde
	}
Packit Service 82fcde
      while (usize >= vsize);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* True: usize < vsize.  */
Packit Service 82fcde
Packit Service 82fcde
  /* Make life simple: Recurse.  */
Packit Service 82fcde
Packit Service 82fcde
  if (usize != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      mpn_mul (tspace, vp, vsize, up, usize);
Packit Service 82fcde
      cy = mpn_add_n (prodp, prodp, tspace, vsize);
Packit Service 82fcde
      mpn_add_1 (prodp + vsize, tspace + vsize, usize, cy);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  TMP_FREE (marker);
Packit Service 82fcde
  return *prod_endp;
Packit Service 82fcde
}