|
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 |
}
|