All the op must have the same precision
Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by the Arenaire and Cacao projects, INRIA.
This file is part of the MPFR Library.
The 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 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 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"
#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),
MPFR_PREC (a), MPFR_PREC (b), 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, (void *) 0);
return inexact;
}
# define mpfr_sub1sp mpfr_sub1sp2
# endif
#endif
#ifdef DEBUG
# undef DEBUG
# define DEBUG(x) (x)
#else
# define DEBUG(x)
#endif
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.
*/
* 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*/
* + 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;
mp_limb_t bbcp, bbcp1;
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));
p = MPFR_PREC(b);
n = (p-1)/BITS_PER_MP_LIMB+1;
bx = MPFR_GET_EXP (b);
cx = MPFR_GET_EXP (c);
if (MPFR_UNLIKELY(bx == cx))
{
mp_size_t k = n - 1;
bp = MPFR_MANT(b);
cp = MPFR_MANT(c);
while (k>=0 && MPFR_UNLIKELY(bp[k] == cp[k]))
k--;
if (MPFR_UNLIKELY(k < 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))
{
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
{
BGreater:
MPFR_SET_SAME_SIGN(a,b);
}
MPFR_ASSERTD(bx >= cx);
d = (mp_exp_unsigned_t) bx - cx;
DEBUG( printf("New with diff=%lu\n", d) );
if (MPFR_UNLIKELY(d <= 1))
{
if (MPFR_LIKELY(d < 1))
{
<-- c --> : exact sub */
ap = MPFR_MANT(a);
mpn_sub_n (ap, MPFR_MANT(b), MPFR_MANT(c), n);
ExactNormalize:
limb = ap[n-1];
if (MPFR_LIKELY(limb))
{
count_leading_zeros(cnt, limb);
if (MPFR_LIKELY(cnt))
{
mpn_lshift(ap, ap, n, cnt);
bx -= cnt;
}
MPFR_ASSERTD(!(ap[0] & MPFR_LIMB_MASK((-p)%BITS_PER_MP_LIMB)));
}
else
{
mp_size_t k = n-1, len;
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;
MPFR_ASSERTD(k >= 0);
if (MPFR_LIKELY(cnt))
mpn_lshift(ap+len, ap, k, cnt);
else
{
MPN_COPY_DECR(ap+len, ap, k);
}
MPN_ZERO(ap, len);
bx -= cnt + len*BITS_PER_MP_LIMB;
MPFR_ASSERTD(!(ap[len]&MPFR_LIMB_MASK((-p)%BITS_PER_MP_LIMB)));
}
if (MPFR_UNLIKELY(bx < __gmpfr_emin))
{
MPFR_TMP_FREE(marker);
DEBUG( printf("(D==0 Underflow)\n") );
if (rnd_mode == GMP_RNDN &&
(bx < __gmpfr_emin - 1 ||
( mpfr_powerof2_raw (a))))
rnd_mode = GMP_RNDZ;
return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
}
MPFR_SET_EXP (a, bx);
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
MPFR_TMP_FREE(marker);
return 0;
}
else
{
| <-- c --> */
mp_limb_t c0, mask;
mp_size_t k;
MPFR_UNSIGNED_MINUS_MODULO(sh, p);
* 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)
{
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))
{
ap = MPFR_MANT(a);
mpn_sub_n (ap, bp, cp, n);
MPFR_SET_EXP(a, bx);
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
MPFR_TMP_FREE(marker);
return 0;
}
ap = MPFR_MANT(a);
mask = ~MPFR_LIMB_MASK(sh);
cp[0] &= mask;
mpn_sub_n (ap, bp, cp, n);
MPFR_SET_EXP(a, bx);
MPFR_ASSERTD( !(ap[0] & ~mask) );
MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
bcp = 1; bcp1 = 0;
if (MPFR_LIKELY(rnd_mode == GMP_RNDN))
{
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))
{
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
{
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 (MPFR_UNLIKELY(carry))
{
MPFR_ASSERTD(sh == 0);
goto SubD1Lose;
}
ap = MPFR_MANT (a);
MPN_ZERO (ap, n);
ap[n-1] = MPFR_LIMB_HIGHBIT;
MPFR_SET_EXP (a, bx);
MPFR_TMP_FREE (marker);
return 0;
}
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);
if (MPFR_UNLIKELY(d == p))
{
bcp = 1;
bbcp = (MPFR_MANT(c)[n-1] & (MPFR_LIMB_ONE<<(BITS_PER_MP_LIMB-2)));
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);
if (MPFR_LIKELY(rnd_mode == GMP_RNDN))
{
if (MPFR_UNLIKELY( bcp && bcp1==0 ))
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
{
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) );
(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) );
}
MPN_COPY(ap, MPFR_MANT(b), n);
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
goto truncate;
}
}
else
{
mp_exp_unsigned_t dm;
mp_size_t m;
mp_limb_t mask;
MPFR_UNSIGNED_MINUS_MODULO(sh, p);
cp = (mp_limb_t*) MPFR_TMP_ALLOC(n * BYTES_PER_MP_LIMB);
dm = d % BITS_PER_MP_LIMB;
m = d / BITS_PER_MP_LIMB;
if (MPFR_UNLIKELY(dm == 0))
{
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))
{
MPFR_ASSERTD(dm >= 2);
mpn_rshift(cp, MPFR_MANT(c), n, dm);
}
else
{
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) );
if (MPFR_LIKELY(sh))
{
bcp = (cp[0] & (MPFR_LIMB_ONE<<(sh-1))) ;
if (MPFR_LIKELY( cp[0] & MPFR_LIMB_MASK(sh-1) ))
bcp1 = 1;
else
{
(+sh since we have already looked sh bits in C'!) */
mpfr_prec_t x = p-d+sh-1;
if (MPFR_LIKELY(x>p))
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", x, kx, sx));
if (tp[kx] & MPFR_LIMB_MASK(sx))
bcp1 = 1;
else
{
do {
kx--;
} while (kx>=0 && tp[kx]==0);
bcp1 = (kx >= 0);
}
}
}
}
else
{
mp_limb_t *tp = MPFR_MANT(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));
if (tp[kx] & MPFR_LIMB_MASK(sx))
bcp1 = 1;
else
{
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) );
bp = MPFR_MANT(b);
if (MPFR_UNLIKELY((bp[n-1]-cp[n-1]) <= MPFR_LIMB_HIGHBIT))
{
if (MPFR_LIKELY(bcp1 == 0))
{
bbcp = 0;
bbcp1 = 0;
}
else
{
compute Cp+1 and C'p+2 from mantissa C */
mp_limb_t *tp = MPFR_MANT(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", x, kx, sx));
bbcp = (tp[kx] & (MPFR_LIMB_ONE<<sx)) ;
if (MPFR_LIKELY(bbcp==0 || (tp[kx]&MPFR_LIMB_MASK(sx))))
bbcp1 = 1;
else
{
do {
kx--;
} while (kx>=0 && tp[kx]==0);
bbcp1 = (kx>=0);
DEBUG( printf("(Pre) Scan done for %ld\n", kx));
}
}
DEBUG( printf("(Pre) Cp+1=%d C'p+2=%d\n", bbcp!=0, bbcp1!=0) );
}
mask = ~MPFR_LIMB_MASK (sh);
cp[0] &= mask;
ap = MPFR_MANT(a);
mpn_sub_n (ap, bp, cp, n);
DEBUG( mpfr_print_mant_binary("Sub= ", ap, p) );
if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
{
mpn_lshift(ap, ap, n, 1);
if (MPFR_UNLIKELY(bcp!=0))
{
mpn_sub_1(ap, ap, n, MPFR_LIMB_ONE<<sh);
MPFR_ASSERTD(MPFR_LIMB_MSB(ap[n-1]) != 0);
}
bx--;
bcp = bbcp;
bcp1 = bbcp1;
But since Ap >= 100000xxx001, the final sub can't unnormalize!*/
}
MPFR_ASSERTD( !(ap[0] & ~mask) );
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;
}
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:
mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh);
inexact = -1;
if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
{
mpn_lshift(ap, ap, n, 1);
bx--;
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));
we need one more bit!*/
if ( (rnd_mode == GMP_RNDZ && bcp==0)
|| (rnd_mode==GMP_RNDN && bbcp==0)
|| (bcp && bcp1==0) )
{
ap[0] |= MPFR_LIMB_ONE<<sh;
if (rnd_mode == GMP_RNDN)
inexact = 1;
DEBUG( printf("(SubOneUlp) Last bit set\n") );
}
since we have had one more bit to the result */
if (bcp1==0 && rnd_mode==GMP_RNDZ)
{
DEBUG( printf("(SubOneUlp) Exact result\n") );
inexact = 0;
}
}
goto end_of_sub;
truncate:
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))
{
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) );
if (( ((rnd_mode == GMP_RNDN) || (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--;
inexact = (bcp1 == 0) ? 0 : (rnd_mode==GMP_RNDN) ? -1 : 1;
goto end_of_sub;
}
}
}
inexact = MPFR_LIKELY(bcp || bcp1) ? 1 : 0;
end_of_sub:
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));
}