blob: e3412df605be10e62de1d207579307486626a78b [file] [log] [blame]
/* 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 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 2.1 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.LIB. If not, 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, mp_rnd_t rnd_mode);
int mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_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, GMP_RNDN);
MPFR_ASSERTN (inexb == 0);
inexc = mpfr_set (tmpc, c, GMP_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 = GMP_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 = GMP_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 = GMP_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, mp_rnd_t rnd_mode)
{
mp_exp_t bx,cx;
mp_exp_unsigned_t d;
mp_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)/BITS_PER_MP_LIMB+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 == GMP_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;
mp_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 = (mp_exp_unsigned_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((-p)%BITS_PER_MP_LIMB)));
}
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*BITS_PER_MP_LIMB; /* Update Expo */
/* Last limb should be ok */
MPFR_ASSERTD(!(ap[len]&MPFR_LIMB_MASK((-p)%BITS_PER_MP_LIMB)));
}
/* Check expo underflow */
if (MPFR_UNLIKELY(bx < __gmpfr_emin))
{
MPFR_TMP_FREE(marker);
/* inexact=0 */
DEBUG( printf("(D==0 Underflow)\n") );
if (rnd_mode == GMP_RNDN &&
(bx < __gmpfr_emin - 1 ||
(/*inexact >= 0 &&*/ mpfr_powerof2_raw (a))))
rnd_mode = GMP_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 == GMP_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 == GMP_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<<(BITS_PER_MP_LIMB-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)<<(BITS_PER_MP_LIMB-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<<(BITS_PER_MP_LIMB-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 == GMP_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 == GMP_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==GMP_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 == GMP_RNDN))
goto truncate;
MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
if (rnd_mode == GMP_RNDZ)
goto sub_one_ulp;
else /* rnd_mode = AWAY */
goto truncate;
}
}
else
{
mp_exp_unsigned_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 % BITS_PER_MP_LIMB;
m = d / BITS_PER_MP_LIMB;
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 / BITS_PER_MP_LIMB);
mpfr_prec_t sx = BITS_PER_MP_LIMB-1-(x%BITS_PER_MP_LIMB);
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 / BITS_PER_MP_LIMB);
mpfr_prec_t sx = BITS_PER_MP_LIMB-1-(x%BITS_PER_MP_LIMB);
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 */
mp_prec_t x = p+1-d;
mp_size_t kx = n-1 - (x/BITS_PER_MP_LIMB);
mp_prec_t sx = BITS_PER_MP_LIMB-1-(x%BITS_PER_MP_LIMB);
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 == GMP_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 == GMP_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 == GMP_RNDZ && bcp==0)
|| (rnd_mode==GMP_RNDN && bbcp==0)
|| (bcp && bcp1==0) ) /*Exact result*/
{
ap[0] |= MPFR_LIMB_ONE<<sh;
if (rnd_mode == GMP_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 == GMP_RNDZ needed ? */
if (bcp1==0 && rnd_mode==GMP_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 != GMP_RNDN) || (bcp != 0) || (bbcp == 0) || (bbcp1 != (mp_limb_t) -1));
if (((rnd_mode != GMP_RNDZ) && bcp)
||
((rnd_mode == GMP_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==GMP_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 == GMP_RNDN &&
(bx < __gmpfr_emin - 1 ||
(inexact >= 0 && mpfr_powerof2_raw (a))))
rnd_mode = GMP_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));
}