xref: /dragonfly/contrib/mpfr/src/sub1sp.c (revision ab6d115f)
14a238c70SJohn Marino /* mpfr_sub1sp -- internal function to perform a "real" substraction
24a238c70SJohn Marino    All the op must have the same precision
34a238c70SJohn Marino 
4*ab6d115fSJohn Marino Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
64a238c70SJohn Marino 
74a238c70SJohn Marino This file is part of the GNU MPFR Library.
84a238c70SJohn Marino 
94a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
104a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
114a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
124a238c70SJohn Marino option) any later version.
134a238c70SJohn Marino 
144a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
154a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
164a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
174a238c70SJohn Marino License for more details.
184a238c70SJohn Marino 
194a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
204a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
214a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
224a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
234a238c70SJohn Marino 
244a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
254a238c70SJohn Marino #include "mpfr-impl.h"
264a238c70SJohn Marino 
274a238c70SJohn Marino /* Check if we have to check the result of mpfr_sub1sp with mpfr_sub1 */
284a238c70SJohn Marino #ifdef WANT_ASSERT
294a238c70SJohn Marino # if WANT_ASSERT >= 2
304a238c70SJohn Marino 
314a238c70SJohn Marino int mpfr_sub1sp2 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode);
mpfr_sub1sp(mpfr_ptr a,mpfr_srcptr b,mpfr_srcptr c,mpfr_rnd_t rnd_mode)324a238c70SJohn Marino int mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
334a238c70SJohn Marino {
344a238c70SJohn Marino   mpfr_t tmpa, tmpb, tmpc;
354a238c70SJohn Marino   int inexb, inexc, inexact, inexact2;
364a238c70SJohn Marino 
374a238c70SJohn Marino   mpfr_init2 (tmpa, MPFR_PREC (a));
384a238c70SJohn Marino   mpfr_init2 (tmpb, MPFR_PREC (b));
394a238c70SJohn Marino   mpfr_init2 (tmpc, MPFR_PREC (c));
404a238c70SJohn Marino 
414a238c70SJohn Marino   inexb = mpfr_set (tmpb, b, MPFR_RNDN);
424a238c70SJohn Marino   MPFR_ASSERTN (inexb == 0);
434a238c70SJohn Marino 
444a238c70SJohn Marino   inexc = mpfr_set (tmpc, c, MPFR_RNDN);
454a238c70SJohn Marino   MPFR_ASSERTN (inexc == 0);
464a238c70SJohn Marino 
474a238c70SJohn Marino   inexact2 = mpfr_sub1 (tmpa, tmpb, tmpc, rnd_mode);
484a238c70SJohn Marino   inexact  = mpfr_sub1sp2(a, b, c, rnd_mode);
494a238c70SJohn Marino 
504a238c70SJohn Marino   if (mpfr_cmp (tmpa, a) || inexact != inexact2)
514a238c70SJohn Marino     {
524a238c70SJohn Marino       fprintf (stderr, "sub1 & sub1sp return different values for %s\n"
534a238c70SJohn Marino                "Prec_a = %lu, Prec_b = %lu, Prec_c = %lu\nB = ",
544a238c70SJohn Marino                mpfr_print_rnd_mode (rnd_mode), (unsigned long) MPFR_PREC (a),
554a238c70SJohn Marino                (unsigned long) MPFR_PREC (b), (unsigned long) MPFR_PREC (c));
564a238c70SJohn Marino       mpfr_fprint_binary (stderr, tmpb);
574a238c70SJohn Marino       fprintf (stderr, "\nC = ");
584a238c70SJohn Marino       mpfr_fprint_binary (stderr, tmpc);
594a238c70SJohn Marino       fprintf (stderr, "\nSub1  : ");
604a238c70SJohn Marino       mpfr_fprint_binary (stderr, tmpa);
614a238c70SJohn Marino       fprintf (stderr, "\nSub1sp: ");
624a238c70SJohn Marino       mpfr_fprint_binary (stderr, a);
634a238c70SJohn Marino       fprintf (stderr, "\nInexact sp = %d | Inexact = %d\n",
644a238c70SJohn Marino                inexact, inexact2);
654a238c70SJohn Marino       MPFR_ASSERTN (0);
664a238c70SJohn Marino     }
674a238c70SJohn Marino   mpfr_clears (tmpa, tmpb, tmpc, (mpfr_ptr) 0);
684a238c70SJohn Marino   return inexact;
694a238c70SJohn Marino }
704a238c70SJohn Marino #  define mpfr_sub1sp mpfr_sub1sp2
714a238c70SJohn Marino # endif
724a238c70SJohn Marino #endif
734a238c70SJohn Marino 
744a238c70SJohn Marino /* Debugging support */
754a238c70SJohn Marino #ifdef DEBUG
764a238c70SJohn Marino # undef DEBUG
774a238c70SJohn Marino # define DEBUG(x) (x)
784a238c70SJohn Marino #else
794a238c70SJohn Marino # define DEBUG(x) /**/
804a238c70SJohn Marino #endif
814a238c70SJohn Marino 
824a238c70SJohn Marino /* Rounding Sub */
834a238c70SJohn Marino 
844a238c70SJohn Marino /*
854a238c70SJohn Marino    compute sgn(b)*(|b| - |c|) if |b|>|c| else -sgn(b)*(|c| -|b|)
864a238c70SJohn Marino    Returns 0 iff result is exact,
874a238c70SJohn Marino    a negative value when the result is less than the exact value,
884a238c70SJohn Marino    a positive value otherwise.
894a238c70SJohn Marino */
904a238c70SJohn Marino 
914a238c70SJohn Marino /* A0...Ap-1
924a238c70SJohn Marino  *          Cp Cp+1 ....
934a238c70SJohn Marino  *             <- C'p+1 ->
944a238c70SJohn Marino  * Cp = -1 if calculated from c mantissa
954a238c70SJohn Marino  * Cp = 0  if 0 from a or c
964a238c70SJohn Marino  * Cp = 1  if calculated from a.
974a238c70SJohn Marino  * C'p+1 = First bit not null or 0 if there isn't one
984a238c70SJohn Marino  *
994a238c70SJohn Marino  * Can't have Cp=-1 and C'p+1=1*/
1004a238c70SJohn Marino 
1014a238c70SJohn Marino /* RND = MPFR_RNDZ:
1024a238c70SJohn Marino  *  + if Cp=0 and C'p+1=0,1,  Truncate.
1034a238c70SJohn Marino  *  + if Cp=0 and C'p+1=-1,   SubOneUlp
1044a238c70SJohn Marino  *  + if Cp=-1,               SubOneUlp
1054a238c70SJohn Marino  *  + if Cp=1,                AddOneUlp
1064a238c70SJohn Marino  * RND = MPFR_RNDA (Away)
1074a238c70SJohn Marino  *  + if Cp=0 and C'p+1=0,-1, Truncate
1084a238c70SJohn Marino  *  + if Cp=0 and C'p+1=1,    AddOneUlp
1094a238c70SJohn Marino  *  + if Cp=1,                AddOneUlp
1104a238c70SJohn Marino  *  + if Cp=-1,               Truncate
1114a238c70SJohn Marino  * RND = MPFR_RNDN
1124a238c70SJohn Marino  *  + if Cp=0,                Truncate
1134a238c70SJohn Marino  *  + if Cp=1 and C'p+1=1,    AddOneUlp
1144a238c70SJohn Marino  *  + if Cp=1 and C'p+1=-1,   Truncate
1154a238c70SJohn Marino  *  + if Cp=1 and C'p+1=0,    Truncate if Ap-1=0, AddOneUlp else
1164a238c70SJohn Marino  *  + if Cp=-1 and C'p+1=-1,  SubOneUlp
1174a238c70SJohn Marino  *  + if Cp=-1 and C'p+1=0,   Truncate if Ap-1=0, SubOneUlp else
1184a238c70SJohn Marino  *
1194a238c70SJohn Marino  * If AddOneUlp:
1204a238c70SJohn Marino  *   If carry, then it is 11111111111 + 1 = 10000000000000
1214a238c70SJohn Marino  *      ap[n-1]=MPFR_HIGHT_BIT
1224a238c70SJohn Marino  * If SubOneUlp:
1234a238c70SJohn Marino  *   If we lose one bit, it is 1000000000 - 1 = 0111111111111
1244a238c70SJohn Marino  *      Then shift, and put as last bit x which is calculated
1254a238c70SJohn Marino  *              according Cp, Cp-1 and rnd_mode.
1264a238c70SJohn Marino  * If Truncate,
1274a238c70SJohn Marino  *    If it is a power of 2,
1284a238c70SJohn Marino  *       we may have to suboneulp in some special cases.
1294a238c70SJohn Marino  *
1304a238c70SJohn Marino  * To simplify, we don't use Cp = 1.
1314a238c70SJohn Marino  *
1324a238c70SJohn Marino  */
1334a238c70SJohn Marino 
1344a238c70SJohn Marino int
mpfr_sub1sp(mpfr_ptr a,mpfr_srcptr b,mpfr_srcptr c,mpfr_rnd_t rnd_mode)1354a238c70SJohn Marino mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
1364a238c70SJohn Marino {
1374a238c70SJohn Marino   mpfr_exp_t bx,cx;
1384a238c70SJohn Marino   mpfr_uexp_t d;
1394a238c70SJohn Marino   mpfr_prec_t p, sh, cnt;
1404a238c70SJohn Marino   mp_size_t n;
1414a238c70SJohn Marino   mp_limb_t *ap, *bp, *cp;
1424a238c70SJohn Marino   mp_limb_t limb;
1434a238c70SJohn Marino   int inexact;
1444a238c70SJohn Marino   mp_limb_t bcp,bcp1; /* Cp and C'p+1 */
1454a238c70SJohn Marino   mp_limb_t bbcp = (mp_limb_t) -1, bbcp1 = (mp_limb_t) -1; /* Cp+1 and C'p+2,
1464a238c70SJohn Marino     gcc claims that they might be used uninitialized. We fill them with invalid
1474a238c70SJohn Marino     values, which should produce a failure if so. See README.dev file. */
1484a238c70SJohn Marino 
1494a238c70SJohn Marino   MPFR_TMP_DECL(marker);
1504a238c70SJohn Marino 
1514a238c70SJohn Marino   MPFR_TMP_MARK(marker);
1524a238c70SJohn Marino 
1534a238c70SJohn Marino   MPFR_ASSERTD(MPFR_PREC(a) == MPFR_PREC(b) && MPFR_PREC(b) == MPFR_PREC(c));
1544a238c70SJohn Marino   MPFR_ASSERTD(MPFR_IS_PURE_FP(b));
1554a238c70SJohn Marino   MPFR_ASSERTD(MPFR_IS_PURE_FP(c));
1564a238c70SJohn Marino 
1574a238c70SJohn Marino   /* Read prec and num of limbs */
1584a238c70SJohn Marino   p = MPFR_PREC (b);
159*ab6d115fSJohn Marino   n = MPFR_PREC2LIMBS (p);
1604a238c70SJohn Marino 
1614a238c70SJohn Marino   /* Fast cmp of |b| and |c|*/
1624a238c70SJohn Marino   bx = MPFR_GET_EXP (b);
1634a238c70SJohn Marino   cx = MPFR_GET_EXP (c);
1644a238c70SJohn Marino   if (MPFR_UNLIKELY(bx == cx))
1654a238c70SJohn Marino     {
1664a238c70SJohn Marino       mp_size_t k = n - 1;
1674a238c70SJohn Marino       /* Check mantissa since exponent are equals */
1684a238c70SJohn Marino       bp = MPFR_MANT(b);
1694a238c70SJohn Marino       cp = MPFR_MANT(c);
1704a238c70SJohn Marino       while (k>=0 && MPFR_UNLIKELY(bp[k] == cp[k]))
1714a238c70SJohn Marino         k--;
1724a238c70SJohn Marino       if (MPFR_UNLIKELY(k < 0))
1734a238c70SJohn Marino         /* b == c ! */
1744a238c70SJohn Marino         {
1754a238c70SJohn Marino           /* Return exact number 0 */
1764a238c70SJohn Marino           if (rnd_mode == MPFR_RNDD)
1774a238c70SJohn Marino             MPFR_SET_NEG(a);
1784a238c70SJohn Marino           else
1794a238c70SJohn Marino             MPFR_SET_POS(a);
1804a238c70SJohn Marino           MPFR_SET_ZERO(a);
1814a238c70SJohn Marino           MPFR_RET(0);
1824a238c70SJohn Marino         }
1834a238c70SJohn Marino       else if (bp[k] > cp[k])
1844a238c70SJohn Marino         goto BGreater;
1854a238c70SJohn Marino       else
1864a238c70SJohn Marino         {
1874a238c70SJohn Marino           MPFR_ASSERTD(bp[k]<cp[k]);
1884a238c70SJohn Marino           goto CGreater;
1894a238c70SJohn Marino         }
1904a238c70SJohn Marino     }
1914a238c70SJohn Marino   else if (MPFR_UNLIKELY(bx < cx))
1924a238c70SJohn Marino     {
1934a238c70SJohn Marino       /* Swap b and c and set sign */
1944a238c70SJohn Marino       mpfr_srcptr t;
1954a238c70SJohn Marino       mpfr_exp_t tx;
1964a238c70SJohn Marino     CGreater:
1974a238c70SJohn Marino       MPFR_SET_OPPOSITE_SIGN(a,b);
1984a238c70SJohn Marino       t  = b;  b  = c;  c  = t;
1994a238c70SJohn Marino       tx = bx; bx = cx; cx = tx;
2004a238c70SJohn Marino     }
2014a238c70SJohn Marino   else
2024a238c70SJohn Marino     {
2034a238c70SJohn Marino       /* b > c */
2044a238c70SJohn Marino     BGreater:
2054a238c70SJohn Marino       MPFR_SET_SAME_SIGN(a,b);
2064a238c70SJohn Marino     }
2074a238c70SJohn Marino 
2084a238c70SJohn Marino   /* Now b > c */
2094a238c70SJohn Marino   MPFR_ASSERTD(bx >= cx);
2104a238c70SJohn Marino   d = (mpfr_uexp_t) bx - cx;
2114a238c70SJohn Marino   DEBUG (printf ("New with diff=%lu\n", (unsigned long) d));
2124a238c70SJohn Marino 
2134a238c70SJohn Marino   if (MPFR_UNLIKELY(d <= 1))
2144a238c70SJohn Marino     {
2154a238c70SJohn Marino       if (MPFR_LIKELY(d < 1))
2164a238c70SJohn Marino         {
2174a238c70SJohn Marino           /* <-- b -->
2184a238c70SJohn Marino              <-- c --> : exact sub */
2194a238c70SJohn Marino           ap = MPFR_MANT(a);
2204a238c70SJohn Marino           mpn_sub_n (ap, MPFR_MANT(b), MPFR_MANT(c), n);
2214a238c70SJohn Marino           /* Normalize */
2224a238c70SJohn Marino         ExactNormalize:
2234a238c70SJohn Marino           limb = ap[n-1];
2244a238c70SJohn Marino           if (MPFR_LIKELY(limb))
2254a238c70SJohn Marino             {
2264a238c70SJohn Marino               /* First limb is not zero. */
2274a238c70SJohn Marino               count_leading_zeros(cnt, limb);
2284a238c70SJohn Marino               /* cnt could be == 0 <= SubD1Lose */
2294a238c70SJohn Marino               if (MPFR_LIKELY(cnt))
2304a238c70SJohn Marino                 {
2314a238c70SJohn Marino                   mpn_lshift(ap, ap, n, cnt); /* Normalize number */
2324a238c70SJohn Marino                   bx -= cnt; /* Update final expo */
2334a238c70SJohn Marino                 }
2344a238c70SJohn Marino               /* Last limb should be ok */
2354a238c70SJohn Marino               MPFR_ASSERTD(!(ap[0] & MPFR_LIMB_MASK((unsigned int) (-p)
2364a238c70SJohn Marino                                                     % GMP_NUMB_BITS)));
2374a238c70SJohn Marino             }
2384a238c70SJohn Marino           else
2394a238c70SJohn Marino             {
2404a238c70SJohn Marino               /* First limb is zero */
2414a238c70SJohn Marino               mp_size_t k = n-1, len;
2424a238c70SJohn Marino               /* Find the first limb not equal to zero.
2434a238c70SJohn Marino                  FIXME:It is assume it exists (since |b| > |c| and same prec)*/
2444a238c70SJohn Marino               do
2454a238c70SJohn Marino                 {
2464a238c70SJohn Marino                   MPFR_ASSERTD( k > 0 );
2474a238c70SJohn Marino                   limb = ap[--k];
2484a238c70SJohn Marino                 }
2494a238c70SJohn Marino               while (limb == 0);
2504a238c70SJohn Marino               MPFR_ASSERTD(limb != 0);
2514a238c70SJohn Marino               count_leading_zeros(cnt, limb);
2524a238c70SJohn Marino               k++;
2534a238c70SJohn Marino               len = n - k; /* Number of last limb */
2544a238c70SJohn Marino               MPFR_ASSERTD(k >= 0);
2554a238c70SJohn Marino               if (MPFR_LIKELY(cnt))
2564a238c70SJohn Marino                 mpn_lshift(ap+len, ap, k, cnt); /* Normalize the High Limb*/
2574a238c70SJohn Marino               else
2584a238c70SJohn Marino                 {
2594a238c70SJohn Marino                   /* Must use DECR since src and dest may overlap & dest>=src*/
2604a238c70SJohn Marino                   MPN_COPY_DECR(ap+len, ap, k);
2614a238c70SJohn Marino                 }
2624a238c70SJohn Marino               MPN_ZERO(ap, len); /* Zeroing the last limbs */
2634a238c70SJohn Marino               bx -= cnt + len*GMP_NUMB_BITS; /* Update Expo */
2644a238c70SJohn Marino               /* Last limb should be ok */
2654a238c70SJohn Marino               MPFR_ASSERTD(!(ap[len]&MPFR_LIMB_MASK((unsigned int) (-p)
2664a238c70SJohn Marino                                                     % GMP_NUMB_BITS)));
2674a238c70SJohn Marino             }
2684a238c70SJohn Marino           /* Check expo underflow */
2694a238c70SJohn Marino           if (MPFR_UNLIKELY(bx < __gmpfr_emin))
2704a238c70SJohn Marino             {
2714a238c70SJohn Marino               MPFR_TMP_FREE(marker);
2724a238c70SJohn Marino               /* inexact=0 */
2734a238c70SJohn Marino               DEBUG( printf("(D==0 Underflow)\n") );
2744a238c70SJohn Marino               if (rnd_mode == MPFR_RNDN &&
2754a238c70SJohn Marino                   (bx < __gmpfr_emin - 1 ||
2764a238c70SJohn Marino                    (/*inexact >= 0 &&*/ mpfr_powerof2_raw (a))))
2774a238c70SJohn Marino                 rnd_mode = MPFR_RNDZ;
2784a238c70SJohn Marino               return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
2794a238c70SJohn Marino             }
2804a238c70SJohn Marino           MPFR_SET_EXP (a, bx);
2814a238c70SJohn Marino           /* No rounding is necessary since the result is exact */
2824a238c70SJohn Marino           MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
2834a238c70SJohn Marino           MPFR_TMP_FREE(marker);
2844a238c70SJohn Marino           return 0;
2854a238c70SJohn Marino         }
2864a238c70SJohn Marino       else /* if (d == 1) */
2874a238c70SJohn Marino         {
2884a238c70SJohn Marino           /* | <-- b -->
2894a238c70SJohn Marino              |  <-- c --> */
2904a238c70SJohn Marino           mp_limb_t c0, mask;
2914a238c70SJohn Marino           mp_size_t k;
2924a238c70SJohn Marino           MPFR_UNSIGNED_MINUS_MODULO(sh, p);
2934a238c70SJohn Marino           /* If we lose at least one bit, compute 2*b-c (Exact)
2944a238c70SJohn Marino            * else compute b-c/2 */
2954a238c70SJohn Marino           bp = MPFR_MANT(b);
2964a238c70SJohn Marino           cp = MPFR_MANT(c);
2974a238c70SJohn Marino           k = n-1;
2984a238c70SJohn Marino           limb = bp[k] - cp[k]/2;
2994a238c70SJohn Marino           if (limb > MPFR_LIMB_HIGHBIT)
3004a238c70SJohn Marino             {
3014a238c70SJohn Marino               /* We can't lose precision: compute b-c/2 */
3024a238c70SJohn Marino               /* Shift c in the allocated temporary block */
3034a238c70SJohn Marino             SubD1NoLose:
3044a238c70SJohn Marino               c0 = cp[0] & (MPFR_LIMB_ONE<<sh);
3054a238c70SJohn Marino               cp = MPFR_TMP_LIMBS_ALLOC (n);
3064a238c70SJohn Marino               mpn_rshift(cp, MPFR_MANT(c), n, 1);
3074a238c70SJohn Marino               if (MPFR_LIKELY(c0 == 0))
3084a238c70SJohn Marino                 {
3094a238c70SJohn Marino                   /* Result is exact: no need of rounding! */
3104a238c70SJohn Marino                   ap = MPFR_MANT(a);
3114a238c70SJohn Marino                   mpn_sub_n (ap, bp, cp, n);
3124a238c70SJohn Marino                   MPFR_SET_EXP(a, bx); /* No expo overflow! */
3134a238c70SJohn Marino                   /* No truncate or normalize is needed */
3144a238c70SJohn Marino                   MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
3154a238c70SJohn Marino                   /* No rounding is necessary since the result is exact */
3164a238c70SJohn Marino                   MPFR_TMP_FREE(marker);
3174a238c70SJohn Marino                   return 0;
3184a238c70SJohn Marino                 }
3194a238c70SJohn Marino               ap = MPFR_MANT(a);
3204a238c70SJohn Marino               mask = ~MPFR_LIMB_MASK(sh);
3214a238c70SJohn Marino               cp[0] &= mask; /* Delete last bit of c */
3224a238c70SJohn Marino               mpn_sub_n (ap, bp, cp, n);
3234a238c70SJohn Marino               MPFR_SET_EXP(a, bx);                 /* No expo overflow! */
3244a238c70SJohn Marino               MPFR_ASSERTD( !(ap[0] & ~mask) );    /* Check last bits */
3254a238c70SJohn Marino               /* No normalize is needed */
3264a238c70SJohn Marino               MPFR_ASSERTD(ap[n-1] > ~ap[n-1]);
3274a238c70SJohn Marino               /* Rounding is necessary since c0 = 1*/
3284a238c70SJohn Marino               /* Cp =-1 and C'p+1=0 */
3294a238c70SJohn Marino               bcp = 1; bcp1 = 0;
3304a238c70SJohn Marino               if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
3314a238c70SJohn Marino                 {
3324a238c70SJohn Marino                   /* Even Rule apply: Check Ap-1 */
3334a238c70SJohn Marino                   if (MPFR_LIKELY( (ap[0] & (MPFR_LIMB_ONE<<sh)) == 0) )
3344a238c70SJohn Marino                     goto truncate;
3354a238c70SJohn Marino                   else
3364a238c70SJohn Marino                     goto sub_one_ulp;
3374a238c70SJohn Marino                 }
3384a238c70SJohn Marino               MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
3394a238c70SJohn Marino               if (rnd_mode == MPFR_RNDZ)
3404a238c70SJohn Marino                 goto sub_one_ulp;
3414a238c70SJohn Marino               else
3424a238c70SJohn Marino                 goto truncate;
3434a238c70SJohn Marino             }
3444a238c70SJohn Marino           else if (MPFR_LIKELY(limb < MPFR_LIMB_HIGHBIT))
3454a238c70SJohn Marino             {
3464a238c70SJohn Marino               /* We lose at least one bit of prec */
3474a238c70SJohn Marino               /* Calcul of 2*b-c (Exact) */
3484a238c70SJohn Marino               /* Shift b in the allocated temporary block */
3494a238c70SJohn Marino             SubD1Lose:
3504a238c70SJohn Marino               bp = MPFR_TMP_LIMBS_ALLOC (n);
3514a238c70SJohn Marino               mpn_lshift (bp, MPFR_MANT(b), n, 1);
3524a238c70SJohn Marino               ap = MPFR_MANT(a);
3534a238c70SJohn Marino               mpn_sub_n (ap, bp, cp, n);
3544a238c70SJohn Marino               bx--;
3554a238c70SJohn Marino               goto ExactNormalize;
3564a238c70SJohn Marino             }
3574a238c70SJohn Marino           else
3584a238c70SJohn Marino             {
3594a238c70SJohn Marino               /* Case: limb = 100000000000 */
3604a238c70SJohn Marino               /* Check while b[k] == c'[k] (C' is C shifted by 1) */
3614a238c70SJohn Marino               /* If b[k]<c'[k] => We lose at least one bit*/
3624a238c70SJohn Marino               /* If b[k]>c'[k] => We don't lose any bit */
3634a238c70SJohn Marino               /* If k==-1 => We don't lose any bit
3644a238c70SJohn Marino                  AND the result is 100000000000 0000000000 00000000000 */
3654a238c70SJohn Marino               mp_limb_t carry;
3664a238c70SJohn Marino               do {
3674a238c70SJohn Marino                 carry = cp[k]&MPFR_LIMB_ONE;
3684a238c70SJohn Marino                 k--;
3694a238c70SJohn Marino               } while (k>=0 &&
3704a238c70SJohn Marino                        bp[k]==(carry=cp[k]/2+(carry<<(GMP_NUMB_BITS-1))));
3714a238c70SJohn Marino               if (MPFR_UNLIKELY(k<0))
3724a238c70SJohn Marino                 {
3734a238c70SJohn Marino                   /*If carry then (sh==0 and Virtual c'[-1] > Virtual b[-1]) */
3744a238c70SJohn Marino                   if (MPFR_UNLIKELY(carry)) /* carry = cp[0]&MPFR_LIMB_ONE */
3754a238c70SJohn Marino                     {
3764a238c70SJohn Marino                       /* FIXME: Can be faster? */
3774a238c70SJohn Marino                       MPFR_ASSERTD(sh == 0);
3784a238c70SJohn Marino                       goto SubD1Lose;
3794a238c70SJohn Marino                     }
3804a238c70SJohn Marino                   /* Result is a power of 2 */
3814a238c70SJohn Marino                   ap = MPFR_MANT (a);
3824a238c70SJohn Marino                   MPN_ZERO (ap, n);
3834a238c70SJohn Marino                   ap[n-1] = MPFR_LIMB_HIGHBIT;
3844a238c70SJohn Marino                   MPFR_SET_EXP (a, bx); /* No expo overflow! */
3854a238c70SJohn Marino                   /* No Normalize is needed*/
3864a238c70SJohn Marino                   /* No Rounding is needed */
3874a238c70SJohn Marino                   MPFR_TMP_FREE (marker);
3884a238c70SJohn Marino                   return 0;
3894a238c70SJohn Marino                 }
3904a238c70SJohn Marino               /* carry = cp[k]/2+(cp[k-1]&1)<<(GMP_NUMB_BITS-1) = c'[k]*/
3914a238c70SJohn Marino               else if (bp[k] > carry)
3924a238c70SJohn Marino                 goto SubD1NoLose;
3934a238c70SJohn Marino               else
3944a238c70SJohn Marino                 {
3954a238c70SJohn Marino                   MPFR_ASSERTD(bp[k]<carry);
3964a238c70SJohn Marino                   goto SubD1Lose;
3974a238c70SJohn Marino                 }
3984a238c70SJohn Marino             }
3994a238c70SJohn Marino         }
4004a238c70SJohn Marino     }
4014a238c70SJohn Marino   else if (MPFR_UNLIKELY(d >= p))
4024a238c70SJohn Marino     {
4034a238c70SJohn Marino       ap = MPFR_MANT(a);
4044a238c70SJohn Marino       MPFR_UNSIGNED_MINUS_MODULO(sh, p);
4054a238c70SJohn Marino       /* We can't set A before since we use cp for rounding... */
4064a238c70SJohn Marino       /* Perform rounding: check if a=b or a=b-ulp(b) */
4074a238c70SJohn Marino       if (MPFR_UNLIKELY(d == p))
4084a238c70SJohn Marino         {
4094a238c70SJohn Marino           /* cp == -1 and c'p+1 = ? */
4104a238c70SJohn Marino           bcp  = 1;
4114a238c70SJohn Marino           /* We need Cp+1 later for a very improbable case. */
4124a238c70SJohn Marino           bbcp = (MPFR_MANT(c)[n-1] & (MPFR_LIMB_ONE<<(GMP_NUMB_BITS-2)));
4134a238c70SJohn Marino           /* We need also C'p+1 for an even more unprobable case... */
4144a238c70SJohn Marino           if (MPFR_LIKELY( bbcp ))
4154a238c70SJohn Marino             bcp1 = 1;
4164a238c70SJohn Marino           else
4174a238c70SJohn Marino             {
4184a238c70SJohn Marino               cp = MPFR_MANT(c);
4194a238c70SJohn Marino               if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT))
4204a238c70SJohn Marino                 {
4214a238c70SJohn Marino                   mp_size_t k = n-1;
4224a238c70SJohn Marino                   do {
4234a238c70SJohn Marino                     k--;
4244a238c70SJohn Marino                   } while (k>=0 && cp[k]==0);
4254a238c70SJohn Marino                   bcp1 = (k>=0);
4264a238c70SJohn Marino                 }
4274a238c70SJohn Marino               else
4284a238c70SJohn Marino                 bcp1 = 1;
4294a238c70SJohn Marino             }
4304a238c70SJohn Marino           DEBUG( printf("(D=P) Cp=-1 Cp+1=%d C'p+1=%d \n", bbcp!=0, bcp1!=0) );
4314a238c70SJohn Marino           bp = MPFR_MANT (b);
4324a238c70SJohn Marino 
4334a238c70SJohn Marino           /* Even if src and dest overlap, it is ok using MPN_COPY */
4344a238c70SJohn Marino           if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
4354a238c70SJohn Marino             {
4364a238c70SJohn Marino               if (MPFR_UNLIKELY( bcp && bcp1==0 ))
4374a238c70SJohn Marino                 /* Cp=-1 and C'p+1=0: Even rule Apply! */
4384a238c70SJohn Marino                 /* Check Ap-1 = Bp-1 */
4394a238c70SJohn Marino                 if ((bp[0] & (MPFR_LIMB_ONE<<sh)) == 0)
4404a238c70SJohn Marino                   {
4414a238c70SJohn Marino                     MPN_COPY(ap, bp, n);
4424a238c70SJohn Marino                     goto truncate;
4434a238c70SJohn Marino                   }
4444a238c70SJohn Marino               MPN_COPY(ap, bp, n);
4454a238c70SJohn Marino               goto sub_one_ulp;
4464a238c70SJohn Marino             }
4474a238c70SJohn Marino           MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
4484a238c70SJohn Marino           if (rnd_mode == MPFR_RNDZ)
4494a238c70SJohn Marino             {
4504a238c70SJohn Marino               MPN_COPY(ap, bp, n);
4514a238c70SJohn Marino               goto sub_one_ulp;
4524a238c70SJohn Marino             }
4534a238c70SJohn Marino           else
4544a238c70SJohn Marino             {
4554a238c70SJohn Marino               MPN_COPY(ap, bp, n);
4564a238c70SJohn Marino               goto truncate;
4574a238c70SJohn Marino             }
4584a238c70SJohn Marino         }
4594a238c70SJohn Marino       else
4604a238c70SJohn Marino         {
4614a238c70SJohn Marino           /* Cp=0, Cp+1=-1 if d==p+1, C'p+1=-1 */
4624a238c70SJohn Marino           bcp = 0; bbcp = (d==p+1); bcp1 = 1;
4634a238c70SJohn Marino           DEBUG( printf("(D>P) Cp=%d Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0) );
4644a238c70SJohn Marino           /* Need to compute C'p+2 if d==p+1 and if rnd_mode=NEAREST
4654a238c70SJohn Marino              (Because of a very improbable case) */
4664a238c70SJohn Marino           if (MPFR_UNLIKELY(d==p+1 && rnd_mode==MPFR_RNDN))
4674a238c70SJohn Marino             {
4684a238c70SJohn Marino               cp = MPFR_MANT(c);
4694a238c70SJohn Marino               if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT))
4704a238c70SJohn Marino                 {
4714a238c70SJohn Marino                   mp_size_t k = n-1;
4724a238c70SJohn Marino                   do {
4734a238c70SJohn Marino                     k--;
4744a238c70SJohn Marino                   } while (k>=0 && cp[k]==0);
4754a238c70SJohn Marino                   bbcp1 = (k>=0);
4764a238c70SJohn Marino                 }
4774a238c70SJohn Marino               else
4784a238c70SJohn Marino                 bbcp1 = 1;
4794a238c70SJohn Marino               DEBUG( printf("(D>P) C'p+2=%d\n", bbcp1!=0) );
4804a238c70SJohn Marino             }
4814a238c70SJohn Marino           /* Copy mantissa B in A */
4824a238c70SJohn Marino           MPN_COPY(ap, MPFR_MANT(b), n);
4834a238c70SJohn Marino           /* Round */
4844a238c70SJohn Marino           if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
4854a238c70SJohn Marino             goto truncate;
4864a238c70SJohn Marino           MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
4874a238c70SJohn Marino           if (rnd_mode == MPFR_RNDZ)
4884a238c70SJohn Marino             goto sub_one_ulp;
4894a238c70SJohn Marino           else /* rnd_mode = AWAY */
4904a238c70SJohn Marino             goto truncate;
4914a238c70SJohn Marino         }
4924a238c70SJohn Marino     }
4934a238c70SJohn Marino   else
4944a238c70SJohn Marino     {
4954a238c70SJohn Marino       mpfr_uexp_t dm;
4964a238c70SJohn Marino       mp_size_t m;
4974a238c70SJohn Marino       mp_limb_t mask;
4984a238c70SJohn Marino 
4994a238c70SJohn Marino       /* General case: 2 <= d < p */
5004a238c70SJohn Marino       MPFR_UNSIGNED_MINUS_MODULO(sh, p);
5014a238c70SJohn Marino       cp = MPFR_TMP_LIMBS_ALLOC (n);
5024a238c70SJohn Marino 
5034a238c70SJohn Marino       /* Shift c in temporary allocated place */
5044a238c70SJohn Marino       dm = d % GMP_NUMB_BITS;
5054a238c70SJohn Marino       m = d / GMP_NUMB_BITS;
5064a238c70SJohn Marino       if (MPFR_UNLIKELY(dm == 0))
5074a238c70SJohn Marino         {
5084a238c70SJohn Marino           /* dm = 0 and m > 0: Just copy */
5094a238c70SJohn Marino           MPFR_ASSERTD(m!=0);
5104a238c70SJohn Marino           MPN_COPY(cp, MPFR_MANT(c)+m, n-m);
5114a238c70SJohn Marino           MPN_ZERO(cp+n-m, m);
5124a238c70SJohn Marino         }
5134a238c70SJohn Marino       else if (MPFR_LIKELY(m == 0))
5144a238c70SJohn Marino         {
5154a238c70SJohn Marino           /* dm >=2 and m == 0: just shift */
5164a238c70SJohn Marino           MPFR_ASSERTD(dm >= 2);
5174a238c70SJohn Marino           mpn_rshift(cp, MPFR_MANT(c), n, dm);
5184a238c70SJohn Marino         }
5194a238c70SJohn Marino       else
5204a238c70SJohn Marino         {
5214a238c70SJohn Marino           /* dm > 0 and m > 0: shift and zero  */
5224a238c70SJohn Marino           mpn_rshift(cp, MPFR_MANT(c)+m, n-m, dm);
5234a238c70SJohn Marino           MPN_ZERO(cp+n-m, m);
5244a238c70SJohn Marino         }
5254a238c70SJohn Marino 
5264a238c70SJohn Marino       DEBUG( mpfr_print_mant_binary("Before", MPFR_MANT(c), p) );
5274a238c70SJohn Marino       DEBUG( mpfr_print_mant_binary("B=    ", MPFR_MANT(b), p) );
5284a238c70SJohn Marino       DEBUG( mpfr_print_mant_binary("After ", cp, p) );
5294a238c70SJohn Marino 
5304a238c70SJohn Marino       /* Compute bcp=Cp and bcp1=C'p+1 */
5314a238c70SJohn Marino       if (MPFR_LIKELY(sh))
5324a238c70SJohn Marino         {
5334a238c70SJohn Marino           /* Try to compute them from C' rather than C (FIXME: Faster?) */
5344a238c70SJohn Marino           bcp = (cp[0] & (MPFR_LIMB_ONE<<(sh-1))) ;
5354a238c70SJohn Marino           if (MPFR_LIKELY( cp[0] & MPFR_LIMB_MASK(sh-1) ))
5364a238c70SJohn Marino             bcp1 = 1;
5374a238c70SJohn Marino           else
5384a238c70SJohn Marino             {
5394a238c70SJohn Marino               /* We can't compute C'p+1 from C'. Compute it from C */
5404a238c70SJohn Marino               /* Start from bit x=p-d+sh in mantissa C
5414a238c70SJohn Marino                  (+sh since we have already looked sh bits in C'!) */
5424a238c70SJohn Marino               mpfr_prec_t x = p-d+sh-1;
5434a238c70SJohn Marino               if (MPFR_LIKELY(x>p))
5444a238c70SJohn Marino                 /* We are already looked at all the bits of c, so C'p+1 = 0*/
5454a238c70SJohn Marino                 bcp1 = 0;
5464a238c70SJohn Marino               else
5474a238c70SJohn Marino                 {
5484a238c70SJohn Marino                   mp_limb_t *tp = MPFR_MANT(c);
5494a238c70SJohn Marino                   mp_size_t kx = n-1 - (x / GMP_NUMB_BITS);
5504a238c70SJohn Marino                   mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
5514a238c70SJohn Marino                   DEBUG (printf ("(First) x=%lu Kx=%ld Sx=%lu\n",
5524a238c70SJohn Marino                                  (unsigned long) x, (long) kx,
5534a238c70SJohn Marino                                  (unsigned long) sx));
5544a238c70SJohn Marino                   /* Looks at the last bits of limb kx (if sx=0 does nothing)*/
5554a238c70SJohn Marino                   if (tp[kx] & MPFR_LIMB_MASK(sx))
5564a238c70SJohn Marino                     bcp1 = 1;
5574a238c70SJohn Marino                   else
5584a238c70SJohn Marino                     {
5594a238c70SJohn Marino                       /*kx += (sx==0);*/
5604a238c70SJohn Marino                       /*If sx==0, tp[kx] hasn't been checked*/
5614a238c70SJohn Marino                       do {
5624a238c70SJohn Marino                         kx--;
5634a238c70SJohn Marino                       } while (kx>=0 && tp[kx]==0);
5644a238c70SJohn Marino                       bcp1 = (kx >= 0);
5654a238c70SJohn Marino                     }
5664a238c70SJohn Marino                 }
5674a238c70SJohn Marino             }
5684a238c70SJohn Marino         }
5694a238c70SJohn Marino       else
5704a238c70SJohn Marino         {
5714a238c70SJohn Marino           /* Compute Cp and C'p+1 from C with sh=0 */
5724a238c70SJohn Marino           mp_limb_t *tp = MPFR_MANT(c);
5734a238c70SJohn Marino           /* Start from bit x=p-d in mantissa C */
5744a238c70SJohn Marino           mpfr_prec_t  x = p-d;
5754a238c70SJohn Marino           mp_size_t   kx = n-1 - (x / GMP_NUMB_BITS);
5764a238c70SJohn Marino           mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
5774a238c70SJohn Marino           MPFR_ASSERTD(p >= d);
5784a238c70SJohn Marino           bcp = (tp[kx] & (MPFR_LIMB_ONE<<sx));
5794a238c70SJohn Marino           /* Looks at the last bits of limb kx (If sx=0, does nothing)*/
5804a238c70SJohn Marino           if (tp[kx] & MPFR_LIMB_MASK(sx))
5814a238c70SJohn Marino             bcp1 = 1;
5824a238c70SJohn Marino           else
5834a238c70SJohn Marino             {
5844a238c70SJohn Marino               /*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/
5854a238c70SJohn Marino               do {
5864a238c70SJohn Marino                 kx--;
5874a238c70SJohn Marino               } while (kx>=0 && tp[kx]==0);
5884a238c70SJohn Marino               bcp1 = (kx>=0);
5894a238c70SJohn Marino             }
5904a238c70SJohn Marino         }
5914a238c70SJohn Marino       DEBUG( printf("sh=%lu Cp=%d C'p+1=%d\n", sh, bcp!=0, bcp1!=0) );
5924a238c70SJohn Marino 
5934a238c70SJohn Marino       /* Check if we can lose a bit, and if so compute Cp+1 and C'p+2 */
5944a238c70SJohn Marino       bp = MPFR_MANT(b);
5954a238c70SJohn Marino       if (MPFR_UNLIKELY((bp[n-1]-cp[n-1]) <= MPFR_LIMB_HIGHBIT))
5964a238c70SJohn Marino         {
5974a238c70SJohn Marino           /* We can lose a bit so we precompute Cp+1 and C'p+2 */
5984a238c70SJohn Marino           /* Test for trivial case: since C'p+1=0, Cp+1=0 and C'p+2 =0 */
5994a238c70SJohn Marino           if (MPFR_LIKELY(bcp1 == 0))
6004a238c70SJohn Marino             {
6014a238c70SJohn Marino               bbcp = 0;
6024a238c70SJohn Marino               bbcp1 = 0;
6034a238c70SJohn Marino             }
6044a238c70SJohn Marino           else /* bcp1 != 0 */
6054a238c70SJohn Marino             {
6064a238c70SJohn Marino               /* We can lose a bit:
6074a238c70SJohn Marino                  compute Cp+1 and C'p+2 from mantissa C */
6084a238c70SJohn Marino               mp_limb_t *tp = MPFR_MANT(c);
6094a238c70SJohn Marino               /* Start from bit x=(p+1)-d in mantissa C */
6104a238c70SJohn Marino               mpfr_prec_t x  = p+1-d;
6114a238c70SJohn Marino               mp_size_t kx = n-1 - (x/GMP_NUMB_BITS);
6124a238c70SJohn Marino               mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS);
6134a238c70SJohn Marino               MPFR_ASSERTD(p > d);
6144a238c70SJohn Marino               DEBUG (printf ("(pre) x=%lu Kx=%ld Sx=%lu\n",
6154a238c70SJohn Marino                              (unsigned long) x, (long) kx,
6164a238c70SJohn Marino                              (unsigned long) sx));
6174a238c70SJohn Marino               bbcp = (tp[kx] & (MPFR_LIMB_ONE<<sx)) ;
6184a238c70SJohn Marino               /* Looks at the last bits of limb kx (If sx=0, does nothing)*/
6194a238c70SJohn Marino               /* If Cp+1=0, since C'p+1!=0, C'p+2=1 ! */
6204a238c70SJohn Marino               if (MPFR_LIKELY(bbcp==0 || (tp[kx]&MPFR_LIMB_MASK(sx))))
6214a238c70SJohn Marino                 bbcp1 = 1;
6224a238c70SJohn Marino               else
6234a238c70SJohn Marino                 {
6244a238c70SJohn Marino                   /*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/
6254a238c70SJohn Marino                   do {
6264a238c70SJohn Marino                     kx--;
6274a238c70SJohn Marino                   } while (kx>=0 && tp[kx]==0);
6284a238c70SJohn Marino                   bbcp1 = (kx>=0);
6294a238c70SJohn Marino                   DEBUG (printf ("(Pre) Scan done for %ld\n", (long) kx));
6304a238c70SJohn Marino                 }
6314a238c70SJohn Marino             } /*End of Bcp1 != 0*/
6324a238c70SJohn Marino           DEBUG( printf("(Pre) Cp+1=%d C'p+2=%d\n", bbcp!=0, bbcp1!=0) );
6334a238c70SJohn Marino         } /* End of "can lose a bit" */
6344a238c70SJohn Marino 
6354a238c70SJohn Marino       /* Clean shifted C' */
6364a238c70SJohn Marino       mask = ~MPFR_LIMB_MASK (sh);
6374a238c70SJohn Marino       cp[0] &= mask;
6384a238c70SJohn Marino 
6394a238c70SJohn Marino       /* Substract the mantissa c from b in a */
6404a238c70SJohn Marino       ap = MPFR_MANT(a);
6414a238c70SJohn Marino       mpn_sub_n (ap, bp, cp, n);
6424a238c70SJohn Marino       DEBUG( mpfr_print_mant_binary("Sub=  ", ap, p) );
6434a238c70SJohn Marino 
6444a238c70SJohn Marino      /* Normalize: we lose at max one bit*/
6454a238c70SJohn Marino       if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
6464a238c70SJohn Marino         {
6474a238c70SJohn Marino           /* High bit is not set and we have to fix it! */
6484a238c70SJohn Marino           /* Ap >= 010000xxx001 */
6494a238c70SJohn Marino           mpn_lshift(ap, ap, n, 1);
6504a238c70SJohn Marino           /* Ap >= 100000xxx010 */
6514a238c70SJohn Marino           if (MPFR_UNLIKELY(bcp!=0)) /* Check if Cp = -1 */
6524a238c70SJohn Marino             /* Since Cp == -1, we have to substract one more */
6534a238c70SJohn Marino             {
6544a238c70SJohn Marino               mpn_sub_1(ap, ap, n, MPFR_LIMB_ONE<<sh);
6554a238c70SJohn Marino               MPFR_ASSERTD(MPFR_LIMB_MSB(ap[n-1]) != 0);
6564a238c70SJohn Marino             }
6574a238c70SJohn Marino           /* Ap >= 10000xxx001 */
6584a238c70SJohn Marino           /* Final exponent -1 since we have shifted the mantissa */
6594a238c70SJohn Marino           bx--;
6604a238c70SJohn Marino           /* Update bcp and bcp1 */
6614a238c70SJohn Marino           MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
6624a238c70SJohn Marino           MPFR_ASSERTN(bbcp1 != (mp_limb_t) -1);
6634a238c70SJohn Marino           bcp  = bbcp;
6644a238c70SJohn Marino           bcp1 = bbcp1;
6654a238c70SJohn Marino           /* We dont't have anymore a valid Cp+1!
6664a238c70SJohn Marino              But since Ap >= 100000xxx001, the final sub can't unnormalize!*/
6674a238c70SJohn Marino         }
6684a238c70SJohn Marino       MPFR_ASSERTD( !(ap[0] & ~mask) );
6694a238c70SJohn Marino 
6704a238c70SJohn Marino       /* Rounding */
6714a238c70SJohn Marino       if (MPFR_LIKELY(rnd_mode == MPFR_RNDN))
6724a238c70SJohn Marino         {
6734a238c70SJohn Marino           if (MPFR_LIKELY(bcp==0))
6744a238c70SJohn Marino             goto truncate;
6754a238c70SJohn Marino           else if ((bcp1) || ((ap[0] & (MPFR_LIMB_ONE<<sh)) != 0))
6764a238c70SJohn Marino             goto sub_one_ulp;
6774a238c70SJohn Marino           else
6784a238c70SJohn Marino             goto truncate;
6794a238c70SJohn Marino         }
6804a238c70SJohn Marino 
6814a238c70SJohn Marino       /* Update rounding mode */
6824a238c70SJohn Marino       MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a));
6834a238c70SJohn Marino       if (rnd_mode == MPFR_RNDZ && (MPFR_LIKELY(bcp || bcp1)))
6844a238c70SJohn Marino         goto sub_one_ulp;
6854a238c70SJohn Marino       goto truncate;
6864a238c70SJohn Marino     }
6874a238c70SJohn Marino   MPFR_RET_NEVER_GO_HERE ();
6884a238c70SJohn Marino 
6894a238c70SJohn Marino   /* Sub one ulp to the result */
6904a238c70SJohn Marino  sub_one_ulp:
6914a238c70SJohn Marino   mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh);
6924a238c70SJohn Marino   /* Result should be smaller than exact value: inexact=-1 */
6934a238c70SJohn Marino   inexact = -1;
6944a238c70SJohn Marino   /* Check normalisation */
6954a238c70SJohn Marino   if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0))
6964a238c70SJohn Marino     {
6974a238c70SJohn Marino       /* ap was a power of 2, and we lose a bit */
6984a238c70SJohn Marino       /* Now it is 0111111111111111111[00000 */
6994a238c70SJohn Marino       mpn_lshift(ap, ap, n, 1);
7004a238c70SJohn Marino       bx--;
7014a238c70SJohn Marino       /* And the lost bit x depends on Cp+1, and Cp */
7024a238c70SJohn Marino       /* Compute Cp+1 if it isn't already compute (ie d==1) */
7034a238c70SJohn Marino       /* FIXME: Is this case possible? */
7044a238c70SJohn Marino       if (MPFR_UNLIKELY(d == 1))
7054a238c70SJohn Marino         bbcp = 0;
7064a238c70SJohn Marino       DEBUG( printf("(SubOneUlp)Cp=%d, Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0));
7074a238c70SJohn Marino       /* Compute the last bit (Since we have shifted the mantissa)
7084a238c70SJohn Marino          we need one more bit!*/
7094a238c70SJohn Marino       MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
7104a238c70SJohn Marino       if ( (rnd_mode == MPFR_RNDZ && bcp==0)
7114a238c70SJohn Marino            || (rnd_mode==MPFR_RNDN && bbcp==0)
7124a238c70SJohn Marino            || (bcp && bcp1==0) ) /*Exact result*/
7134a238c70SJohn Marino         {
7144a238c70SJohn Marino           ap[0] |= MPFR_LIMB_ONE<<sh;
7154a238c70SJohn Marino           if (rnd_mode == MPFR_RNDN)
7164a238c70SJohn Marino             inexact = 1;
7174a238c70SJohn Marino           DEBUG( printf("(SubOneUlp) Last bit set\n") );
7184a238c70SJohn Marino         }
7194a238c70SJohn Marino       /* Result could be exact if C'p+1 = 0 and rnd == Zero
7204a238c70SJohn Marino          since we have had one more bit to the result */
7214a238c70SJohn Marino       /* Fixme: rnd_mode == MPFR_RNDZ needed ? */
7224a238c70SJohn Marino       if (bcp1==0 && rnd_mode==MPFR_RNDZ)
7234a238c70SJohn Marino         {
7244a238c70SJohn Marino           DEBUG( printf("(SubOneUlp) Exact result\n") );
7254a238c70SJohn Marino           inexact = 0;
7264a238c70SJohn Marino         }
7274a238c70SJohn Marino     }
7284a238c70SJohn Marino 
7294a238c70SJohn Marino   goto end_of_sub;
7304a238c70SJohn Marino 
7314a238c70SJohn Marino  truncate:
7324a238c70SJohn Marino   /* Check if the result is an exact power of 2: 100000000000
7334a238c70SJohn Marino      in which cases, we could have to do sub_one_ulp due to some nasty reasons:
7344a238c70SJohn Marino      If Result is a Power of 2:
7354a238c70SJohn Marino       + If rnd = AWAY,
7364a238c70SJohn Marino       |  If Cp=-1 and C'p+1 = 0, SubOneUlp and the result is EXACT.
7374a238c70SJohn Marino          If Cp=-1 and C'p+1 =-1, SubOneUlp and the result is above.
7384a238c70SJohn Marino          Otherwise truncate
7394a238c70SJohn Marino       + If rnd = NEAREST,
7404a238c70SJohn Marino          If Cp= 0 and Cp+1  =-1 and C'p+2=-1, SubOneUlp and the result is above
7414a238c70SJohn Marino          If cp=-1 and C'p+1 = 0, SubOneUlp and the result is exact.
7424a238c70SJohn Marino          Otherwise truncate.
7434a238c70SJohn Marino       X bit should always be set if SubOneUlp*/
7444a238c70SJohn Marino   if (MPFR_UNLIKELY(ap[n-1] == MPFR_LIMB_HIGHBIT))
7454a238c70SJohn Marino     {
7464a238c70SJohn Marino       mp_size_t k = n-1;
7474a238c70SJohn Marino       do {
7484a238c70SJohn Marino         k--;
7494a238c70SJohn Marino       } while (k>=0 && ap[k]==0);
7504a238c70SJohn Marino       if (MPFR_UNLIKELY(k<0))
7514a238c70SJohn Marino         {
7524a238c70SJohn Marino           /* It is a power of 2! */
7534a238c70SJohn Marino           /* Compute Cp+1 if it isn't already compute (ie d==1) */
7544a238c70SJohn Marino           /* FIXME: Is this case possible? */
7554a238c70SJohn Marino           if (d == 1)
7564a238c70SJohn Marino             bbcp=0;
7574a238c70SJohn Marino           DEBUG( printf("(Truncate) Cp=%d, Cp+1=%d C'p+1=%d C'p+2=%d\n", \
7584a238c70SJohn Marino                  bcp!=0, bbcp!=0, bcp1!=0, bbcp1!=0) );
7594a238c70SJohn Marino           MPFR_ASSERTN(bbcp != (mp_limb_t) -1);
7604a238c70SJohn Marino           MPFR_ASSERTN((rnd_mode != MPFR_RNDN) || (bcp != 0) || (bbcp == 0) || (bbcp1 != (mp_limb_t) -1));
7614a238c70SJohn Marino           if (((rnd_mode != MPFR_RNDZ) && bcp)
7624a238c70SJohn Marino               ||
7634a238c70SJohn Marino               ((rnd_mode == MPFR_RNDN) && (bcp == 0) && (bbcp) && (bbcp1)))
7644a238c70SJohn Marino             {
7654a238c70SJohn Marino               DEBUG( printf("(Truncate) Do sub\n") );
7664a238c70SJohn Marino               mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh);
7674a238c70SJohn Marino               mpn_lshift(ap, ap, n, 1);
7684a238c70SJohn Marino               ap[0] |= MPFR_LIMB_ONE<<sh;
7694a238c70SJohn Marino               bx--;
7704a238c70SJohn Marino               /* FIXME: Explain why it works (or why not)... */
7714a238c70SJohn Marino               inexact = (bcp1 == 0) ? 0 : (rnd_mode==MPFR_RNDN) ? -1 : 1;
7724a238c70SJohn Marino               goto end_of_sub;
7734a238c70SJohn Marino             }
7744a238c70SJohn Marino         }
7754a238c70SJohn Marino     }
7764a238c70SJohn Marino 
7774a238c70SJohn Marino   /* Calcul of Inexact flag.*/
7784a238c70SJohn Marino   inexact = MPFR_LIKELY(bcp || bcp1) ? 1 : 0;
7794a238c70SJohn Marino 
7804a238c70SJohn Marino  end_of_sub:
7814a238c70SJohn Marino   /* Update Expo */
7824a238c70SJohn Marino   /* FIXME: Is this test really useful?
7834a238c70SJohn Marino       If d==0      : Exact case. This is never called.
7844a238c70SJohn Marino       if 1 < d < p : bx=MPFR_EXP(b) or MPFR_EXP(b)-1 > MPFR_EXP(c) > emin
7854a238c70SJohn Marino       if d == 1    : bx=MPFR_EXP(b). If we could lose any bits, the exact
7864a238c70SJohn Marino                      normalisation is called.
7874a238c70SJohn Marino       if d >=  p   : bx=MPFR_EXP(b) >= MPFR_EXP(c) + p > emin
7884a238c70SJohn Marino      After SubOneUlp, we could have one bit less.
7894a238c70SJohn Marino       if 1 < d < p : bx >= MPFR_EXP(b)-2 >= MPFR_EXP(c) > emin
7904a238c70SJohn Marino       if d == 1    : bx >= MPFR_EXP(b)-1 = MPFR_EXP(c) > emin.
7914a238c70SJohn Marino       if d >=  p   : bx >= MPFR_EXP(b)-1 > emin since p>=2.
7924a238c70SJohn Marino   */
7934a238c70SJohn Marino   MPFR_ASSERTD( bx >= __gmpfr_emin);
7944a238c70SJohn Marino   /*
7954a238c70SJohn Marino     if (MPFR_UNLIKELY(bx < __gmpfr_emin))
7964a238c70SJohn Marino     {
7974a238c70SJohn Marino       DEBUG( printf("(Final Underflow)\n") );
7984a238c70SJohn Marino       if (rnd_mode == MPFR_RNDN &&
7994a238c70SJohn Marino           (bx < __gmpfr_emin - 1 ||
8004a238c70SJohn Marino            (inexact >= 0 && mpfr_powerof2_raw (a))))
8014a238c70SJohn Marino         rnd_mode = MPFR_RNDZ;
8024a238c70SJohn Marino       MPFR_TMP_FREE(marker);
8034a238c70SJohn Marino       return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
8044a238c70SJohn Marino     }
8054a238c70SJohn Marino   */
8064a238c70SJohn Marino   MPFR_SET_EXP (a, bx);
8074a238c70SJohn Marino 
8084a238c70SJohn Marino   MPFR_TMP_FREE(marker);
8094a238c70SJohn Marino   MPFR_RET (inexact * MPFR_INT_SIGN (a));
8104a238c70SJohn Marino }
811