efee5258bc
The MPFR library is a C library for multiple-precision floating-point computations with exact rounding (also called correct rounding). It is based on the GMP multiple-precision library and should replace the MPF class in further releases of GMP. GCC >= 4.2 requires MPFR.
810 lines
28 KiB
C
810 lines
28 KiB
C
/* mpfr_sub1sp -- internal function to perform a "real" substraction
|
|
All the op must have the same precision
|
|
|
|
Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
|
Contributed by the Arenaire and Cacao projects, INRIA.
|
|
|
|
This file is part of the GNU MPFR Library.
|
|
|
|
The GNU MPFR 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 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
The GNU MPFR 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 MPFR Library; see the file COPYING.LESSER. If not, see
|
|
http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
|
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|
|
|
#define MPFR_NEED_LONGLONG_H
|
|
#include "mpfr-impl.h"
|
|
|
|
/* Check if we have to check the result of mpfr_sub1sp with mpfr_sub1 */
|
|
#ifdef WANT_ASSERT
|
|
# if WANT_ASSERT >= 2
|
|
|
|
int mpfr_sub1sp2 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode);
|
|
int mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
|
|
{
|
|
mpfr_t tmpa, tmpb, tmpc;
|
|
int inexb, inexc, inexact, inexact2;
|
|
|
|
mpfr_init2 (tmpa, MPFR_PREC (a));
|
|
mpfr_init2 (tmpb, MPFR_PREC (b));
|
|
mpfr_init2 (tmpc, MPFR_PREC (c));
|
|
|
|
inexb = mpfr_set (tmpb, b, MPFR_RNDN);
|
|
MPFR_ASSERTN (inexb == 0);
|
|
|
|
inexc = mpfr_set (tmpc, c, MPFR_RNDN);
|
|
MPFR_ASSERTN (inexc == 0);
|
|
|
|
inexact2 = mpfr_sub1 (tmpa, tmpb, tmpc, rnd_mode);
|
|
inexact = mpfr_sub1sp2(a, b, c, rnd_mode);
|
|
|
|
if (mpfr_cmp (tmpa, a) || inexact != inexact2)
|
|
{
|
|
fprintf (stderr, "sub1 & sub1sp return different values for %s\n"
|
|
"Prec_a = %lu, Prec_b = %lu, Prec_c = %lu\nB = ",
|
|
mpfr_print_rnd_mode (rnd_mode), (unsigned long) MPFR_PREC (a),
|
|
(unsigned long) MPFR_PREC (b), (unsigned long) MPFR_PREC (c));
|
|
mpfr_fprint_binary (stderr, tmpb);
|
|
fprintf (stderr, "\nC = ");
|
|
mpfr_fprint_binary (stderr, tmpc);
|
|
fprintf (stderr, "\nSub1 : ");
|
|
mpfr_fprint_binary (stderr, tmpa);
|
|
fprintf (stderr, "\nSub1sp: ");
|
|
mpfr_fprint_binary (stderr, a);
|
|
fprintf (stderr, "\nInexact sp = %d | Inexact = %d\n",
|
|
inexact, inexact2);
|
|
MPFR_ASSERTN (0);
|
|
}
|
|
mpfr_clears (tmpa, tmpb, tmpc, (mpfr_ptr) 0);
|
|
return inexact;
|
|
}
|
|
# define mpfr_sub1sp mpfr_sub1sp2
|
|
# endif
|
|
#endif
|
|
|
|
/* Debugging support */
|
|
#ifdef DEBUG
|
|
# undef DEBUG
|
|
# define DEBUG(x) (x)
|
|
#else
|
|
# define DEBUG(x) /**/
|
|
#endif
|
|
|
|
/* Rounding Sub */
|
|
|
|
/*
|
|
compute sgn(b)*(|b| - |c|) if |b|>|c| else -sgn(b)*(|c| -|b|)
|
|
Returns 0 iff result is exact,
|
|
a negative value when the result is less than the exact value,
|
|
a positive value otherwise.
|
|
*/
|
|
|
|
/* A0...Ap-1
|
|
* Cp Cp+1 ....
|
|
* <- C'p+1 ->
|
|
* Cp = -1 if calculated from c mantissa
|
|
* Cp = 0 if 0 from a or c
|
|
* Cp = 1 if calculated from a.
|
|
* C'p+1 = First bit not null or 0 if there isn't one
|
|
*
|
|
* Can't have Cp=-1 and C'p+1=1*/
|
|
|
|
/* RND = MPFR_RNDZ:
|
|
* + if Cp=0 and C'p+1=0,1, Truncate.
|
|
* + if Cp=0 and C'p+1=-1, SubOneUlp
|
|
* + if Cp=-1, SubOneUlp
|
|
* + if Cp=1, AddOneUlp
|
|
* RND = MPFR_RNDA (Away)
|
|
* + if Cp=0 and C'p+1=0,-1, Truncate
|
|
* + if Cp=0 and C'p+1=1, AddOneUlp
|
|
* + if Cp=1, AddOneUlp
|
|
* + if Cp=-1, Truncate
|
|
* RND = MPFR_RNDN
|
|
* + if Cp=0, Truncate
|
|
* + if Cp=1 and C'p+1=1, AddOneUlp
|
|
* + if Cp=1 and C'p+1=-1, Truncate
|
|
* + if Cp=1 and C'p+1=0, Truncate if Ap-1=0, AddOneUlp else
|
|
* + if Cp=-1 and C'p+1=-1, SubOneUlp
|
|
* + if Cp=-1 and C'p+1=0, Truncate if Ap-1=0, SubOneUlp else
|
|
*
|
|
* If AddOneUlp:
|
|
* If carry, then it is 11111111111 + 1 = 10000000000000
|
|
* ap[n-1]=MPFR_HIGHT_BIT
|
|
* If SubOneUlp:
|
|
* If we lose one bit, it is 1000000000 - 1 = 0111111111111
|
|
* Then shift, and put as last bit x which is calculated
|
|
* according Cp, Cp-1 and rnd_mode.
|
|
* If Truncate,
|
|
* If it is a power of 2,
|
|
* we may have to suboneulp in some special cases.
|
|
*
|
|
* To simplify, we don't use Cp = 1.
|
|
*
|
|
*/
|
|
|
|
int
|
|
mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
|
|
{
|
|
mpfr_exp_t bx,cx;
|
|
mpfr_uexp_t d;
|
|
mpfr_prec_t p, sh, cnt;
|
|
mp_size_t n;
|
|
mp_limb_t *ap, *bp, *cp;
|
|
mp_limb_t limb;
|
|
int inexact;
|
|
mp_limb_t bcp,bcp1; /* Cp and C'p+1 */
|
|
mp_limb_t bbcp = (mp_limb_t) -1, bbcp1 = (mp_limb_t) -1; /* Cp+1 and C'p+2,
|
|
gcc claims that they might be used uninitialized. We fill them with invalid
|
|
values, which should produce a failure if so. See README.dev file. */
|
|
|
|
MPFR_TMP_DECL(marker);
|
|
|
|
MPFR_TMP_MARK(marker);
|
|
|
|
MPFR_ASSERTD(MPFR_PREC(a) == MPFR_PREC(b) && MPFR_PREC(b) == MPFR_PREC(c));
|
|
MPFR_ASSERTD(MPFR_IS_PURE_FP(b) && MPFR_IS_PURE_FP(c));
|
|
|
|
/* Read prec and num of limbs */
|
|
p = MPFR_PREC(b);
|
|
n = (p-1)/GMP_NUMB_BITS+1;
|
|
|
|
/* Fast cmp of |b| and |c|*/
|
|
bx = MPFR_GET_EXP (b);
|
|
cx = MPFR_GET_EXP (c);
|
|
if (MPFR_UNLIKELY(bx == cx))
|
|
{
|
|
mp_size_t k = n - 1;
|
|
/* Check mantissa since exponent are equals */
|
|
bp = MPFR_MANT(b);
|
|
cp = MPFR_MANT(c);
|
|
while (k>=0 && MPFR_UNLIKELY(bp[k] == cp[k]))
|
|
k--;
|
|
if (MPFR_UNLIKELY(k < 0))
|
|
/* b == c ! */
|
|
{
|
|
/* Return exact number 0 */
|
|
if (rnd_mode == MPFR_RNDD)
|
|
MPFR_SET_NEG(a);
|
|
else
|
|
MPFR_SET_POS(a);
|
|
MPFR_SET_ZERO(a);
|
|
MPFR_RET(0);
|
|
}
|
|
else if (bp[k] > cp[k])
|
|
goto BGreater;
|
|
else
|
|
{
|
|
MPFR_ASSERTD(bp[k]<cp[k]);
|
|
goto CGreater;
|
|
}
|
|
}
|
|
else if (MPFR_UNLIKELY(bx < cx))
|
|
{
|
|
/* Swap b and c and set sign */
|
|
mpfr_srcptr t;
|
|
mpfr_exp_t tx;
|
|
CGreater:
|
|
MPFR_SET_OPPOSITE_SIGN(a,b);
|
|
t = b; b = c; c = t;
|
|
tx = bx; bx = cx; cx = tx;
|
|
}
|
|
else
|
|
{
|
|
/* b > c */
|
|
BGreater:
|
|
MPFR_SET_SAME_SIGN(a,b);
|
|
}
|
|
|
|
/* Now b > c */
|
|
MPFR_ASSERTD(bx >= cx);
|
|
d = (mpfr_uexp_t) bx - cx;
|
|
DEBUG (printf ("New with diff=%lu\n", (unsigned long) d));
|
|
|
|
if (MPFR_UNLIKELY(d <= 1))
|
|
{
|
|
if (MPFR_LIKELY(d < 1))
|
|
{
|
|
/* <-- b -->
|
|
<-- c --> : exact sub */
|
|
ap = MPFR_MANT(a);
|
|
mpn_sub_n (ap, MPFR_MANT(b), MPFR_MANT(c), n);
|
|
/* Normalize */
|
|
ExactNormalize:
|
|
limb = ap[n-1];
|
|
if (MPFR_LIKELY(limb))
|
|
{
|
|
/* First limb is not zero. */
|
|
count_leading_zeros(cnt, limb);
|
|
/* cnt could be == 0 <= SubD1Lose */
|
|
if (MPFR_LIKELY(cnt))
|
|
{
|
|
mpn_lshift(ap, ap, n, cnt); /* Normalize number */
|
|
bx -= cnt; /* Update final expo */
|
|
}
|
|
/* Last limb should be ok */
|
|
MPFR_ASSERTD(!(ap[0] & MPFR_LIMB_MASK((unsigned int) (-p)
|
|
% GMP_NUMB_BITS)));
|
|
}
|
|
else
|
|
{
|
|
/* First limb is zero */
|
|
mp_size_t k = n-1, len;
|
|
/* Find the first limb not equal to zero.
|
|
FIXME:It is assume it exists (since |b| > |c| and same prec)*/
|
|
do
|
|
{
|
|
MPFR_ASSERTD( k > 0 );
|
|
limb = ap[--k];
|
|
}
|
|
while (limb == 0);
|
|
MPFR_ASSERTD(limb != 0);
|
|
count_leading_zeros(cnt, limb);
|
|
k++;
|
|
len = n - k; /* Number of last limb */
|
|
MPFR_ASSERTD(k >= 0);
|
|
if (MPFR_LIKELY(cnt))
|
|
mpn_lshift(ap+len, ap, k, cnt); /* Normalize the High Limb*/
|
|
else
|
|
{
|
|
/* Must use DECR since src and dest may overlap & dest>=src*/
|
|
MPN_COPY_DECR(ap+len, ap, k);
|
|
}
|
|
MPN_ZERO(ap, len); /* Zeroing the last limbs */
|
|
bx -= cnt + len*GMP_NUMB_BITS; /* Update Expo */
|
|
/* Last limb should be ok */
|
|
MPFR_ASSERTD(!(ap[len]&MPFR_LIMB_MASK((unsigned int) (-p)
|
|
% GMP_NUMB_BITS)));
|
|
}
|
|
/* Check expo underflow */
|
|
if (MPFR_UNLIKELY(bx < __gmpfr_emin))
|
|
{
|
|
MPFR_TMP_FREE(marker);
|
|
/* inexact=0 */
|
|
DEBUG( printf("(D==0 Underflow)\n") );
|
|
if (rnd_mode == MPFR_RNDN &&
|
|
(bx < __gmpfr_emin - 1 ||
|
|
(/*inexact >= 0 &&*/ mpfr_powerof2_raw (a))))
|
|
rnd_mode = MPFR_RNDZ;
|
|
return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
|
|
}
|
|
MPFR_SET_EXP (a, bx);
|
|
/* No rounding is necessary since the result is exact */
|
|
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
|
|
MPFR_TMP_FREE(marker);
|
|
return 0;
|
|
}
|
|
else /* if (d == 1) */
|
|
{
|
|
/* | <-- b -->
|
|
| <-- c --> */
|
|
mp_limb_t c0, mask;
|
|
mp_size_t k;
|
|
MPFR_UNSIGNED_MINUS_MODULO(sh, p);
|
|
/* If we lose at least one bit, compute 2*b-c (Exact)
|
|
* else compute b-c/2 */
|
|
bp = MPFR_MANT(b);
|
|
cp = MPFR_MANT(c);
|
|
k = n-1;
|
|
limb = bp[k] - cp[k]/2;
|
|
if (limb > MPFR_LIMB_HIGHBIT)
|
|
{
|
|
/* We can't lose precision: compute b-c/2 */
|
|
/* Shift c in the allocated temporary block */
|
|
SubD1NoLose:
|
|
c0 = cp[0] & (MPFR_LIMB_ONE<<sh);
|
|
cp = (mp_limb_t*) MPFR_TMP_ALLOC(n * BYTES_PER_MP_LIMB);
|
|
mpn_rshift(cp, MPFR_MANT(c), n, 1);
|
|
if (MPFR_LIKELY(c0 == 0))
|
|
{
|
|
/* Result is exact: no need of rounding! */
|
|
ap = MPFR_MANT(a);
|
|
mpn_sub_n (ap, bp, cp, n);
|
|
MPFR_SET_EXP(a, bx); /* No expo overflow! */
|
|
/* No truncate or normalize is needed */
|
|
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
|
|
/* No rounding is necessary since the result is exact */
|
|
MPFR_TMP_FREE(marker);
|
|
return 0;
|
|
}
|
|
ap = MPFR_MANT(a);
|
|
mask = ~MPFR_LIMB_MASK(sh);
|
|
cp[0] &= mask; /* Delete last bit of c */
|
|
mpn_sub_n (ap, bp, cp, n);
|
|
MPFR_SET_EXP(a, bx); /* No expo overflow! */
|
|
MPFR_ASSERTD( !(ap[0] & ~mask) ); /* Check last bits */
|
|
/* No normalize is needed */
|
|
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
|
|
/* Rounding is necessary since c0 = 1*/
|
|
/* Cp =-1 and C'p+1=0 */
|
|
bcp = 1; bcp1 = 0;
|
|
if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
|
|
{
|
|
/* Even Rule apply: Check Ap-1 */
|
|
if (MPFR_LIKELY( (ap[0] & (MPFR_LIMB_ONE<<sh)) == 0) )
|
|
goto truncate;
|
|
else
|
|
goto sub_one_ulp;
|
|
}
|
|
MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
|
|
if (rnd_mode == MPFR_RNDZ)
|
|
goto sub_one_ulp;
|
|
else
|
|
goto truncate;
|
|
}
|
|
else if (MPFR_LIKELY(limb < MPFR_LIMB_HIGHBIT))
|
|
{
|
|
/* We lose at least one bit of prec */
|
|
/* Calcul of 2*b-c (Exact) */
|
|
/* Shift b in the allocated temporary block */
|
|
SubD1Lose:
|
|
bp = (mp_limb_t*) MPFR_TMP_ALLOC (n * BYTES_PER_MP_LIMB);
|
|
mpn_lshift (bp, MPFR_MANT(b), n, 1);
|
|
ap = MPFR_MANT(a);
|
|
mpn_sub_n (ap, bp, cp, n);
|
|
bx--;
|
|
goto ExactNormalize;
|
|
}
|
|
else
|
|
{
|
|
/* Case: limb = 100000000000 */
|
|
/* Check while b[k] == c'[k] (C' is C shifted by 1) */
|
|
/* If b[k]<c'[k] => We lose at least one bit*/
|
|
/* If b[k]>c'[k] => We don't lose any bit */
|
|
/* If k==-1 => We don't lose any bit
|
|
AND the result is 100000000000 0000000000 00000000000 */
|
|
mp_limb_t carry;
|
|
do {
|
|
carry = cp[k]&MPFR_LIMB_ONE;
|
|
k--;
|
|
} while (k>=0 &&
|
|
bp[k]==(carry=cp[k]/2+(carry<<(GMP_NUMB_BITS-1))));
|
|
if (MPFR_UNLIKELY(k<0))
|
|
{
|
|
/*If carry then (sh==0 and Virtual c'[-1] > Virtual b[-1]) */
|
|
if (MPFR_UNLIKELY(carry)) /* carry = cp[0]&MPFR_LIMB_ONE */
|
|
{
|
|
/* FIXME: Can be faster? */
|
|
MPFR_ASSERTD(sh == 0);
|
|
goto SubD1Lose;
|
|
}
|
|
/* Result is a power of 2 */
|
|
ap = MPFR_MANT (a);
|
|
MPN_ZERO (ap, n);
|
|
ap[n-1] = MPFR_LIMB_HIGHBIT;
|
|
MPFR_SET_EXP (a, bx); /* No expo overflow! */
|
|
/* No Normalize is needed*/
|
|
/* No Rounding is needed */
|
|
MPFR_TMP_FREE (marker);
|
|
return 0;
|
|
}
|
|
/* carry = cp[k]/2+(cp[k-1]&1)<<(GMP_NUMB_BITS-1) = c'[k]*/
|
|
else if (bp[k] > carry)
|
|
goto SubD1NoLose;
|
|
else
|
|
{
|
|
MPFR_ASSERTD(bp[k]<carry);
|
|
goto SubD1Lose;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (MPFR_UNLIKELY(d >= p))
|
|
{
|
|
ap = MPFR_MANT(a);
|
|
MPFR_UNSIGNED_MINUS_MODULO(sh, p);
|
|
/* We can't set A before since we use cp for rounding... */
|
|
/* Perform rounding: check if a=b or a=b-ulp(b) */
|
|
if (MPFR_UNLIKELY(d == p))
|
|
{
|
|
/* cp == -1 and c'p+1 = ? */
|
|
bcp = 1;
|
|
/* We need Cp+1 later for a very improbable case. */
|
|
bbcp = (MPFR_MANT(c)[n-1] & (MPFR_LIMB_ONE<<(GMP_NUMB_BITS-2)));
|
|
/* We need also C'p+1 for an even more unprobable case... */
|
|
if (MPFR_LIKELY( bbcp ))
|
|
bcp1 = 1;
|
|
else
|
|
{
|
|
cp = MPFR_MANT(c);
|
|
if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT))
|
|
{
|
|
mp_size_t k = n-1;
|
|
do {
|
|
k--;
|
|
} while (k>=0 && cp[k]==0);
|
|
bcp1 = (k>=0);
|
|
}
|
|
else
|
|
bcp1 = 1;
|
|
}
|
|
DEBUG( printf("(D=P) Cp=-1 Cp+1=%d C'p+1=%d \n", bbcp!=0, bcp1!=0) );
|
|
bp = MPFR_MANT (b);
|
|
|
|
/* Even if src and dest overlap, it is ok using MPN_COPY */
|
|
if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
|
|
{
|
|
if (MPFR_UNLIKELY( bcp && bcp1==0 ))
|
|
/* Cp=-1 and C'p+1=0: Even rule Apply! */
|
|
/* Check Ap-1 = Bp-1 */
|
|
if ((bp[0] & (MPFR_LIMB_ONE<<sh)) == 0)
|
|
{
|
|
MPN_COPY(ap, bp, n);
|
|
goto truncate;
|
|
}
|
|
MPN_COPY(ap, bp, n);
|
|
goto sub_one_ulp;
|
|
}
|
|
MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
|
|
if (rnd_mode == MPFR_RNDZ)
|
|
{
|
|
MPN_COPY(ap, bp, n);
|
|
goto sub_one_ulp;
|
|
}
|
|
else
|
|
{
|
|
MPN_COPY(ap, bp, n);
|
|
goto truncate;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Cp=0, Cp+1=-1 if d==p+1, C'p+1=-1 */
|
|
bcp = 0; bbcp = (d==p+1); bcp1 = 1;
|
|
DEBUG( printf("(D>P) Cp=%d Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0) );
|
|
/* Need to compute C'p+2 if d==p+1 and if rnd_mode=NEAREST
|
|
(Because of a very improbable case) */
|
|
if (MPFR_UNLIKELY(d==p+1 && rnd_mode==MPFR_RNDN))
|
|
{
|
|
cp = MPFR_MANT(c);
|
|
if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT))
|
|
{
|
|
mp_size_t k = n-1;
|
|
do {
|
|
k--;
|
|
} while (k>=0 && cp[k]==0);
|
|
bbcp1 = (k>=0);
|
|
}
|
|
else
|
|
bbcp1 = 1;
|
|
DEBUG( printf("(D>P) C'p+2=%d\n", bbcp1!=0) );
|
|
}
|
|
/* Copy mantissa B in A */
|
|
MPN_COPY(ap, MPFR_MANT(b), n);
|
|
/* Round */
|
|
if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
|
|
goto truncate;
|
|
MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
|
|
if (rnd_mode == MPFR_RNDZ)
|
|
goto sub_one_ulp;
|
|
else /* rnd_mode = AWAY */
|
|
goto truncate;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mpfr_uexp_t dm;
|
|
mp_size_t m;
|
|
mp_limb_t mask;
|
|
|
|
/* General case: 2 <= d < p */
|
|
MPFR_UNSIGNED_MINUS_MODULO(sh, p);
|
|
cp = (mp_limb_t*) MPFR_TMP_ALLOC(n * BYTES_PER_MP_LIMB);
|
|
|
|
/* Shift c in temporary allocated place */
|
|
dm = d % GMP_NUMB_BITS;
|
|
m = d / GMP_NUMB_BITS;
|
|
if (MPFR_UNLIKELY(dm == 0))
|
|
{
|
|
/* dm = 0 and m > 0: Just copy */
|
|
MPFR_ASSERTD(m!=0);
|
|
MPN_COPY(cp, MPFR_MANT(c)+m, n-m);
|
|
MPN_ZERO(cp+n-m, m);
|
|
}
|
|
else if (MPFR_LIKELY(m == 0))
|
|
{
|
|
/* dm >=2 and m == 0: just shift */
|
|
MPFR_ASSERTD(dm >= 2);
|
|
mpn_rshift(cp, MPFR_MANT(c), n, dm);
|
|
}
|
|
else
|
|
{
|
|
/* dm > 0 and m > 0: shift and zero */
|
|
mpn_rshift(cp, MPFR_MANT(c)+m, n-m, dm);
|
|
MPN_ZERO(cp+n-m, m);
|
|
}
|
|
|
|
DEBUG( mpfr_print_mant_binary("Before", MPFR_MANT(c), p) );
|
|
DEBUG( mpfr_print_mant_binary("B= ", MPFR_MANT(b), p) );
|
|
DEBUG( mpfr_print_mant_binary("After ", cp, p) );
|
|
|
|
/* Compute bcp=Cp and bcp1=C'p+1 */
|
|
if (MPFR_LIKELY(sh))
|
|
{
|
|
/* Try to compute them from C' rather than C (FIXME: Faster?) */
|
|
bcp = (cp[0] & (MPFR_LIMB_ONE<<(sh-1))) ;
|
|
if (MPFR_LIKELY( cp[0] & MPFR_LIMB_MASK(sh-1) ))
|
|
bcp1 = 1;
|
|
else
|
|
{
|
|
/* We can't compute C'p+1 from C'. Compute it from C */
|
|
/* Start from bit x=p-d+sh in mantissa C
|
|
(+sh since we have already looked sh bits in C'!) */
|
|
mpfr_prec_t x = p-d+sh-1;
|
|
if (MPFR_LIKELY(x>p))
|
|
/* We are already looked at all the bits of c, so C'p+1 = 0*/
|
|
bcp1 = 0;
|
|
else
|
|
{
|
|
mp_limb_t *tp = MPFR_MANT(c);
|
|
mp_size_t kx = n-1 - (x / GMP_NUMB_BITS);
|
|
mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
|
|
DEBUG (printf ("(First) x=%lu Kx=%ld Sx=%lu\n",
|
|
(unsigned long) x, (long) kx,
|
|
(unsigned long) sx));
|
|
/* Looks at the last bits of limb kx (if sx=0 does nothing)*/
|
|
if (tp[kx] & MPFR_LIMB_MASK(sx))
|
|
bcp1 = 1;
|
|
else
|
|
{
|
|
/*kx += (sx==0);*/
|
|
/*If sx==0, tp[kx] hasn't been checked*/
|
|
do {
|
|
kx--;
|
|
} while (kx>=0 && tp[kx]==0);
|
|
bcp1 = (kx >= 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Compute Cp and C'p+1 from C with sh=0 */
|
|
mp_limb_t *tp = MPFR_MANT(c);
|
|
/* Start from bit x=p-d in mantissa C */
|
|
mpfr_prec_t x = p-d;
|
|
mp_size_t kx = n-1 - (x / GMP_NUMB_BITS);
|
|
mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
|
|
MPFR_ASSERTD(p >= d);
|
|
bcp = (tp[kx] & (MPFR_LIMB_ONE<<sx));
|
|
/* Looks at the last bits of limb kx (If sx=0, does nothing)*/
|
|
if (tp[kx] & MPFR_LIMB_MASK(sx))
|
|
bcp1 = 1;
|
|
else
|
|
{
|
|
/*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/
|
|
do {
|
|
kx--;
|
|
} while (kx>=0 && tp[kx]==0);
|
|
bcp1 = (kx>=0);
|
|
}
|
|
}
|
|
DEBUG( printf("sh=%lu Cp=%d C'p+1=%d\n", sh, bcp!=0, bcp1!=0) );
|
|
|
|
/* Check if we can lose a bit, and if so compute Cp+1 and C'p+2 */
|
|
bp = MPFR_MANT(b);
|
|
if (MPFR_UNLIKELY((bp[n-1]-cp[n-1]) <= MPFR_LIMB_HIGHBIT))
|
|
{
|
|
/* We can lose a bit so we precompute Cp+1 and C'p+2 */
|
|
/* Test for trivial case: since C'p+1=0, Cp+1=0 and C'p+2 =0 */
|
|
if (MPFR_LIKELY(bcp1 == 0))
|
|
{
|
|
bbcp = 0;
|
|
bbcp1 = 0;
|
|
}
|
|
else /* bcp1 != 0 */
|
|
{
|
|
/* We can lose a bit:
|
|
compute Cp+1 and C'p+2 from mantissa C */
|
|
mp_limb_t *tp = MPFR_MANT(c);
|
|
/* Start from bit x=(p+1)-d in mantissa C */
|
|
mpfr_prec_t x = p+1-d;
|
|
mp_size_t kx = n-1 - (x/GMP_NUMB_BITS);
|
|
mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
|
|
MPFR_ASSERTD(p > d);
|
|
DEBUG (printf ("(pre) x=%lu Kx=%ld Sx=%lu\n",
|
|
(unsigned long) x, (long) kx,
|
|
(unsigned long) sx));
|
|
bbcp = (tp[kx] & (MPFR_LIMB_ONE<<sx)) ;
|
|
/* Looks at the last bits of limb kx (If sx=0, does nothing)*/
|
|
/* If Cp+1=0, since C'p+1!=0, C'p+2=1 ! */
|
|
if (MPFR_LIKELY(bbcp==0 || (tp[kx]&MPFR_LIMB_MASK(sx))))
|
|
bbcp1 = 1;
|
|
else
|
|
{
|
|
/*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/
|
|
do {
|
|
kx--;
|
|
} while (kx>=0 && tp[kx]==0);
|
|
bbcp1 = (kx>=0);
|
|
DEBUG (printf ("(Pre) Scan done for %ld\n", (long) kx));
|
|
}
|
|
} /*End of Bcp1 != 0*/
|
|
DEBUG( printf("(Pre) Cp+1=%d C'p+2=%d\n", bbcp!=0, bbcp1!=0) );
|
|
} /* End of "can lose a bit" */
|
|
|
|
/* Clean shifted C' */
|
|
mask = ~MPFR_LIMB_MASK (sh);
|
|
cp[0] &= mask;
|
|
|
|
/* Substract the mantissa c from b in a */
|
|
ap = MPFR_MANT(a);
|
|
mpn_sub_n (ap, bp, cp, n);
|
|
DEBUG( mpfr_print_mant_binary("Sub= ", ap, p) );
|
|
|
|
/* Normalize: we lose at max one bit*/
|
|
if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
|
|
{
|
|
/* High bit is not set and we have to fix it! */
|
|
/* Ap >= 010000xxx001 */
|
|
mpn_lshift(ap, ap, n, 1);
|
|
/* Ap >= 100000xxx010 */
|
|
if (MPFR_UNLIKELY(bcp!=0)) /* Check if Cp = -1 */
|
|
/* Since Cp == -1, we have to substract one more */
|
|
{
|
|
mpn_sub_1(ap, ap, n, MPFR_LIMB_ONE<<sh);
|
|
MPFR_ASSERTD(MPFR_LIMB_MSB(ap[n-1]) != 0);
|
|
}
|
|
/* Ap >= 10000xxx001 */
|
|
/* Final exponent -1 since we have shifted the mantissa */
|
|
bx--;
|
|
/* Update bcp and bcp1 */
|
|
MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
|
|
MPFR_ASSERTN(bbcp1 != (mp_limb_t) -1);
|
|
bcp = bbcp;
|
|
bcp1 = bbcp1;
|
|
/* We dont't have anymore a valid Cp+1!
|
|
But since Ap >= 100000xxx001, the final sub can't unnormalize!*/
|
|
}
|
|
MPFR_ASSERTD( !(ap[0] & ~mask) );
|
|
|
|
/* Rounding */
|
|
if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
|
|
{
|
|
if (MPFR_LIKELY(bcp==0))
|
|
goto truncate;
|
|
else if ((bcp1) || ((ap[0] & (MPFR_LIMB_ONE<<sh)) != 0))
|
|
goto sub_one_ulp;
|
|
else
|
|
goto truncate;
|
|
}
|
|
|
|
/* Update rounding mode */
|
|
MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
|
|
if (rnd_mode == MPFR_RNDZ && (MPFR_LIKELY(bcp || bcp1)))
|
|
goto sub_one_ulp;
|
|
goto truncate;
|
|
}
|
|
MPFR_RET_NEVER_GO_HERE ();
|
|
|
|
/* Sub one ulp to the result */
|
|
sub_one_ulp:
|
|
mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh);
|
|
/* Result should be smaller than exact value: inexact=-1 */
|
|
inexact = -1;
|
|
/* Check normalisation */
|
|
if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
|
|
{
|
|
/* ap was a power of 2, and we lose a bit */
|
|
/* Now it is 0111111111111111111[00000 */
|
|
mpn_lshift(ap, ap, n, 1);
|
|
bx--;
|
|
/* And the lost bit x depends on Cp+1, and Cp */
|
|
/* Compute Cp+1 if it isn't already compute (ie d==1) */
|
|
/* FIXME: Is this case possible? */
|
|
if (MPFR_UNLIKELY(d == 1))
|
|
bbcp = 0;
|
|
DEBUG( printf("(SubOneUlp)Cp=%d, Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0));
|
|
/* Compute the last bit (Since we have shifted the mantissa)
|
|
we need one more bit!*/
|
|
MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
|
|
if ( (rnd_mode == MPFR_RNDZ && bcp==0)
|
|
|| (rnd_mode==MPFR_RNDN && bbcp==0)
|
|
|| (bcp && bcp1==0) ) /*Exact result*/
|
|
{
|
|
ap[0] |= MPFR_LIMB_ONE<<sh;
|
|
if (rnd_mode == MPFR_RNDN)
|
|
inexact = 1;
|
|
DEBUG( printf("(SubOneUlp) Last bit set\n") );
|
|
}
|
|
/* Result could be exact if C'p+1 = 0 and rnd == Zero
|
|
since we have had one more bit to the result */
|
|
/* Fixme: rnd_mode == MPFR_RNDZ needed ? */
|
|
if (bcp1==0 && rnd_mode==MPFR_RNDZ)
|
|
{
|
|
DEBUG( printf("(SubOneUlp) Exact result\n") );
|
|
inexact = 0;
|
|
}
|
|
}
|
|
|
|
goto end_of_sub;
|
|
|
|
truncate:
|
|
/* Check if the result is an exact power of 2: 100000000000
|
|
in which cases, we could have to do sub_one_ulp due to some nasty reasons:
|
|
If Result is a Power of 2:
|
|
+ If rnd = AWAY,
|
|
| If Cp=-1 and C'p+1 = 0, SubOneUlp and the result is EXACT.
|
|
If Cp=-1 and C'p+1 =-1, SubOneUlp and the result is above.
|
|
Otherwise truncate
|
|
+ If rnd = NEAREST,
|
|
If Cp= 0 and Cp+1 =-1 and C'p+2=-1, SubOneUlp and the result is above
|
|
If cp=-1 and C'p+1 = 0, SubOneUlp and the result is exact.
|
|
Otherwise truncate.
|
|
X bit should always be set if SubOneUlp*/
|
|
if (MPFR_UNLIKELY(ap[n-1] == MPFR_LIMB_HIGHBIT))
|
|
{
|
|
mp_size_t k = n-1;
|
|
do {
|
|
k--;
|
|
} while (k>=0 && ap[k]==0);
|
|
if (MPFR_UNLIKELY(k<0))
|
|
{
|
|
/* It is a power of 2! */
|
|
/* Compute Cp+1 if it isn't already compute (ie d==1) */
|
|
/* FIXME: Is this case possible? */
|
|
if (d == 1)
|
|
bbcp=0;
|
|
DEBUG( printf("(Truncate) Cp=%d, Cp+1=%d C'p+1=%d C'p+2=%d\n", \
|
|
bcp!=0, bbcp!=0, bcp1!=0, bbcp1!=0) );
|
|
MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
|
|
MPFR_ASSERTN((rnd_mode != MPFR_RNDN) || (bcp != 0) || (bbcp == 0) || (bbcp1 != (mp_limb_t) -1));
|
|
if (((rnd_mode != MPFR_RNDZ) && bcp)
|
|
||
|
|
((rnd_mode == MPFR_RNDN) && (bcp == 0) && (bbcp) && (bbcp1)))
|
|
{
|
|
DEBUG( printf("(Truncate) Do sub\n") );
|
|
mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh);
|
|
mpn_lshift(ap, ap, n, 1);
|
|
ap[0] |= MPFR_LIMB_ONE<<sh;
|
|
bx--;
|
|
/* FIXME: Explain why it works (or why not)... */
|
|
inexact = (bcp1 == 0) ? 0 : (rnd_mode==MPFR_RNDN) ? -1 : 1;
|
|
goto end_of_sub;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Calcul of Inexact flag.*/
|
|
inexact = MPFR_LIKELY(bcp || bcp1) ? 1 : 0;
|
|
|
|
end_of_sub:
|
|
/* Update Expo */
|
|
/* FIXME: Is this test really useful?
|
|
If d==0 : Exact case. This is never called.
|
|
if 1 < d < p : bx=MPFR_EXP(b) or MPFR_EXP(b)-1 > MPFR_EXP(c) > emin
|
|
if d == 1 : bx=MPFR_EXP(b). If we could lose any bits, the exact
|
|
normalisation is called.
|
|
if d >= p : bx=MPFR_EXP(b) >= MPFR_EXP(c) + p > emin
|
|
After SubOneUlp, we could have one bit less.
|
|
if 1 < d < p : bx >= MPFR_EXP(b)-2 >= MPFR_EXP(c) > emin
|
|
if d == 1 : bx >= MPFR_EXP(b)-1 = MPFR_EXP(c) > emin.
|
|
if d >= p : bx >= MPFR_EXP(b)-1 > emin since p>=2.
|
|
*/
|
|
MPFR_ASSERTD( bx >= __gmpfr_emin);
|
|
/*
|
|
if (MPFR_UNLIKELY(bx < __gmpfr_emin))
|
|
{
|
|
DEBUG( printf("(Final Underflow)\n") );
|
|
if (rnd_mode == MPFR_RNDN &&
|
|
(bx < __gmpfr_emin - 1 ||
|
|
(inexact >= 0 && mpfr_powerof2_raw (a))))
|
|
rnd_mode = MPFR_RNDZ;
|
|
MPFR_TMP_FREE(marker);
|
|
return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
|
|
}
|
|
*/
|
|
MPFR_SET_EXP (a, bx);
|
|
|
|
MPFR_TMP_FREE(marker);
|
|
MPFR_RET (inexact * MPFR_INT_SIGN (a));
|
|
}
|