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