Blame mpf/mul_ui.c

Packit 5c3484
/* mpf_mul_ui -- Multiply a float and an unsigned integer.
Packit 5c3484
Packit 5c3484
Copyright 1993, 1994, 1996, 2001, 2003, 2004 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The core operation is a multiply of PREC(r) limbs from u by v, producing
Packit 5c3484
   either PREC(r) or PREC(r)+1 result limbs.  If u is shorter than PREC(r),
Packit 5c3484
   then we take only as much as it has.  If u is longer we incorporate a
Packit 5c3484
   carry from the lower limbs.
Packit 5c3484
Packit 5c3484
   If u has just 1 extra limb, then the carry to add is high(up[0]*v).  That
Packit 5c3484
   is of course what mpn_mul_1 would do if it was called with PREC(r)+1
Packit 5c3484
   limbs of input.
Packit 5c3484
Packit 5c3484
   If u has more than 1 extra limb, then there can be a further carry bit
Packit 5c3484
   out of lower uncalculated limbs (the way the low of one product adds to
Packit 5c3484
   the high of the product below it).  This is of course what an mpn_mul_1
Packit 5c3484
   would do if it was called with the full u operand.  But we instead work
Packit 5c3484
   downwards explicitly, until a carry occurs or until a value other than
Packit 5c3484
   GMP_NUMB_MAX occurs (that being the only value a carry bit can propagate
Packit 5c3484
   across).
Packit 5c3484
Packit 5c3484
   The carry determination normally requires two umul_ppmm's, only rarely
Packit 5c3484
   will GMP_NUMB_MAX occur and require further products.
Packit 5c3484
Packit 5c3484
   The carry limb is conveniently added into the mul_1 using mpn_mul_1c when
Packit 5c3484
   that function exists, otherwise a subsequent mpn_add_1 is needed.
Packit 5c3484
Packit 5c3484
   Clearly when mpn_mul_1c is used the carry must be calculated first.  But
Packit 5c3484
   this is also the case when add_1 is used, since if r==u and ABSIZ(r) >
Packit 5c3484
   PREC(r) then the mpn_mul_1 overwrites the low part of the input.
Packit 5c3484
Packit 5c3484
   A reuse r==u with size > prec can occur from a size PREC(r)+1 in the
Packit 5c3484
   usual way, or it can occur from an mpf_set_prec_raw leaving a bigger
Packit 5c3484
   sized value.  In both cases we can end up calling mpn_mul_1 with
Packit 5c3484
   overlapping src and dst regions, but this will be with dst < src and such
Packit 5c3484
   an overlap is permitted.
Packit 5c3484
Packit 5c3484
   Not done:
Packit 5c3484
Packit 5c3484
   No attempt is made to determine in advance whether the result will be
Packit 5c3484
   PREC(r) or PREC(r)+1 limbs.  If it's going to be PREC(r)+1 then we could
Packit 5c3484
   take one less limb from u and generate just PREC(r), that of course
Packit 5c3484
   satisfying application requested precision.  But any test counting bits
Packit 5c3484
   or forming the high product would almost certainly take longer than the
Packit 5c3484
   incremental cost of an extra limb in mpn_mul_1.
Packit 5c3484
Packit 5c3484
   Enhancements:
Packit 5c3484
Packit 5c3484
   Repeated mpf_mul_ui's with an even v will accumulate low zero bits on the
Packit 5c3484
   result, leaving low zero limbs after a while, which it might be nice to
Packit 5c3484
   strip to save work in subsequent operations.  Calculating the low limb
Packit 5c3484
   explicitly would let us direct mpn_mul_1 to put the balance at rp when
Packit 5c3484
   the low is zero (instead of normally rp+1).  But it's not clear whether
Packit 5c3484
   this would be worthwhile.  Explicit code for the low limb will probably
Packit 5c3484
   be slower than having it done in mpn_mul_1, so we need to consider how
Packit 5c3484
   often a zero will be stripped and how much that's likely to save
Packit 5c3484
   later.  */
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
mpf_mul_ui (mpf_ptr r, mpf_srcptr u, unsigned long int v)
Packit 5c3484
{
Packit 5c3484
  mp_srcptr up;
Packit 5c3484
  mp_size_t usize;
Packit 5c3484
  mp_size_t size;
Packit 5c3484
  mp_size_t prec, excess;
Packit 5c3484
  mp_limb_t cy_limb, vl, cbit, cin;
Packit 5c3484
  mp_ptr rp;
Packit 5c3484
Packit 5c3484
  usize = u->_mp_size;
Packit 5c3484
  if (UNLIKELY (v == 0) || UNLIKELY (usize == 0))
Packit 5c3484
    {
Packit 5c3484
      r->_mp_size = 0;
Packit 5c3484
      r->_mp_exp = 0;
Packit 5c3484
      return;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
Packit 5c3484
  if (v > GMP_NUMB_MAX)
Packit 5c3484
    {
Packit 5c3484
      mpf_t     vf;
Packit 5c3484
      mp_limb_t vp[2];
Packit 5c3484
      vp[0] = v & GMP_NUMB_MASK;
Packit 5c3484
      vp[1] = v >> GMP_NUMB_BITS;
Packit 5c3484
      PTR(vf) = vp;
Packit 5c3484
      SIZ(vf) = 2;
Packit 5c3484
      ASSERT_CODE (PREC(vf) = 2);
Packit 5c3484
      EXP(vf) = 2;
Packit 5c3484
      mpf_mul (r, u, vf);
Packit 5c3484
      return;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
  size = ABS (usize);
Packit 5c3484
  prec = r->_mp_prec;
Packit 5c3484
  up = u->_mp_d;
Packit 5c3484
  vl = v;
Packit 5c3484
  excess = size - prec;
Packit 5c3484
  cin = 0;
Packit 5c3484
Packit 5c3484
  if (excess > 0)
Packit 5c3484
    {
Packit 5c3484
      /* up is bigger than desired rp, shorten it to prec limbs and
Packit 5c3484
         determine a carry-in */
Packit 5c3484
Packit 5c3484
      mp_limb_t  vl_shifted = vl << GMP_NAIL_BITS;
Packit 5c3484
      mp_limb_t  hi, lo, next_lo, sum;
Packit 5c3484
      mp_size_t  i;
Packit 5c3484
Packit 5c3484
      /* high limb of top product */
Packit 5c3484
      i = excess - 1;
Packit 5c3484
      umul_ppmm (cin, lo, up[i], vl_shifted);
Packit 5c3484
Packit 5c3484
      /* and carry bit out of products below that, if any */
Packit 5c3484
      for (;;)
Packit 5c3484
        {
Packit 5c3484
          i--;
Packit 5c3484
          if (i < 0)
Packit 5c3484
            break;
Packit 5c3484
Packit 5c3484
          umul_ppmm (hi, next_lo, up[i], vl_shifted);
Packit 5c3484
          lo >>= GMP_NAIL_BITS;
Packit 5c3484
          ADDC_LIMB (cbit, sum, hi, lo);
Packit 5c3484
          cin += cbit;
Packit 5c3484
          lo = next_lo;
Packit 5c3484
Packit 5c3484
          /* Continue only if the sum is GMP_NUMB_MAX.  GMP_NUMB_MAX is the
Packit 5c3484
             only value a carry from below can propagate across.  If we've
Packit 5c3484
             just seen the carry out (ie. cbit!=0) then sum!=GMP_NUMB_MAX,
Packit 5c3484
             so this test stops us for that case too.  */
Packit 5c3484
          if (LIKELY (sum != GMP_NUMB_MAX))
Packit 5c3484
            break;
Packit 5c3484
        }
Packit 5c3484
Packit 5c3484
      up += excess;
Packit 5c3484
      size = prec;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  rp = r->_mp_d;
Packit 5c3484
#if HAVE_NATIVE_mpn_mul_1c
Packit 5c3484
  cy_limb = mpn_mul_1c (rp, up, size, vl, cin);
Packit 5c3484
#else
Packit 5c3484
  cy_limb = mpn_mul_1 (rp, up, size, vl);
Packit 5c3484
  __GMPN_ADD_1 (cbit, rp, rp, size, cin);
Packit 5c3484
  cy_limb += cbit;
Packit 5c3484
#endif
Packit 5c3484
  rp[size] = cy_limb;
Packit 5c3484
  cy_limb = cy_limb != 0;
Packit 5c3484
  r->_mp_exp = u->_mp_exp + cy_limb;
Packit 5c3484
  size += cy_limb;
Packit 5c3484
  r->_mp_size = usize >= 0 ? size : -size;
Packit 5c3484
}