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