[BACK]Return to sub1.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpfr

Annotation of OpenXM_contrib/gmp/mpfr/sub1.c, Revision 1.1

1.1     ! ohara       1: /* mpfr_sub1 -- internal function to perform a "real" subtraction
        !             2:
        !             3: Copyright 2001 Free Software Foundation.
        !             4: Contributed by the Spaces project, INRIA Lorraine.
        !             5:
        !             6: This file is part of the MPFR Library.
        !             7:
        !             8: The MPFR Library is free software; you can redistribute it and/or modify
        !             9: it under the terms of the GNU Lesser General Public License as published by
        !            10: the Free Software Foundation; either version 2.1 of the License, or (at your
        !            11: option) any later version.
        !            12:
        !            13: The MPFR Library is distributed in the hope that it will be useful, but
        !            14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            16: License for more details.
        !            17:
        !            18: You should have received a copy of the GNU Lesser General Public License
        !            19: along with the MPFR Library; see the file COPYING.LIB.  If not, write to
        !            20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            21: MA 02111-1307, USA. */
        !            22:
        !            23: #include "gmp.h"
        !            24: #include "gmp-impl.h"
        !            25: #include "mpfr.h"
        !            26: #include "mpfr-impl.h"
        !            27:
        !            28: /* compute sign(b) * (|b| - |c|), with |b| > |c|, diff_exp = EXP(b) - EXP(c)
        !            29:    Returns 0 iff result is exact,
        !            30:    a negative value when the result is less than the exact value,
        !            31:    a positive value otherwise.
        !            32: */
        !            33:
        !            34: int
        !            35: mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode,
        !            36:            int sub)
        !            37: {
        !            38:   int sign;
        !            39:   mp_exp_unsigned_t diff_exp;
        !            40:   mp_prec_t cancel, cancel1;
        !            41:   mp_size_t cancel2, an, bn, cn, cn0;
        !            42:   mp_limb_t *ap, *bp, *cp;
        !            43:   mp_limb_t carry, bb, cc, borrow = 0;
        !            44:   int inexact = 0, shift_b, shift_c, is_exact = 1, down = 0, add_exp = 0;
        !            45:   int sh, k;
        !            46:   TMP_DECL(marker);
        !            47:
        !            48:   TMP_MARK(marker);
        !            49:   ap = MPFR_MANT(a);
        !            50:   an = 1 + (MPFR_PREC(a) - 1) / BITS_PER_MP_LIMB;
        !            51:
        !            52:   sign = mpfr_cmp2 (b, c, &cancel);
        !            53:   if (sign == 0)
        !            54:     {
        !            55:       if (rnd_mode == GMP_RNDD)
        !            56:         MPFR_SET_NEG(a);
        !            57:       else
        !            58:         MPFR_SET_POS(a);
        !            59:       MPFR_SET_ZERO(a);
        !            60:       MPFR_RET(0);
        !            61:     }
        !            62:
        !            63:   /* If subtraction: sign(a) = sign * sign(b) */
        !            64:   if (sub && MPFR_SIGN(a) != sign * MPFR_SIGN(b))
        !            65:     MPFR_CHANGE_SIGN(a);
        !            66:
        !            67:   if (sign < 0) /* swap b and c so that |b| > |c| */
        !            68:     {
        !            69:       mpfr_srcptr t;
        !            70:       t = b; b = c; c = t;
        !            71:     }
        !            72:
        !            73:   /* If addition: sign(a) = sign of the larger argument in absolute value */
        !            74:   if (!sub)
        !            75:     MPFR_SET_SAME_SIGN(a, b);
        !            76:
        !            77:   diff_exp = (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c);
        !            78:
        !            79:   /* reserve a space to store b aligned with the result, i.e. shifted by
        !            80:      (-cancel) % BITS_PER_MP_LIMB to the right */
        !            81:   bn = 1 + (MPFR_PREC(b) - 1) / BITS_PER_MP_LIMB;
        !            82:   shift_b = cancel % BITS_PER_MP_LIMB;
        !            83:   if (shift_b)
        !            84:     shift_b = BITS_PER_MP_LIMB - shift_b;
        !            85:   cancel1 = (cancel + shift_b) / BITS_PER_MP_LIMB;
        !            86:   /* the high cancel1 limbs from b should not be taken into account */
        !            87:   if (shift_b == 0)
        !            88:     bp = MPFR_MANT(b); /* no need of an extra space */
        !            89:   else
        !            90:     {
        !            91:       bp = TMP_ALLOC ((bn + 1) * BYTES_PER_MP_LIMB);
        !            92:       bp[0] = mpn_rshift (bp + 1, MPFR_MANT(b), bn++, shift_b);
        !            93:     }
        !            94:
        !            95:   /* reserve a space to store c aligned with the result, i.e. shifted by
        !            96:      (diff_exp-cancel) % BITS_PER_MP_LIMB to the right */
        !            97:   cn = 1 + (MPFR_PREC(c) - 1) / BITS_PER_MP_LIMB;
        !            98:   shift_c = diff_exp - (cancel % BITS_PER_MP_LIMB);
        !            99:   shift_c = (shift_c + BITS_PER_MP_LIMB) % BITS_PER_MP_LIMB;
        !           100:   if (shift_c == 0)
        !           101:     cp = MPFR_MANT(c);
        !           102:   else
        !           103:     {
        !           104:       cp = TMP_ALLOC ((cn + 1) * BYTES_PER_MP_LIMB);
        !           105:       cp[0] = mpn_rshift (cp + 1, MPFR_MANT(c), cn++, shift_c);
        !           106:     }
        !           107:
        !           108: #ifdef DEBUG
        !           109:   printf("shift_b=%u shift_c=%u\n", shift_b, shift_c);
        !           110: #endif
        !           111:
        !           112:   /* ensure ap != bp and ap != cp */
        !           113:   if (ap == bp)
        !           114:     {
        !           115:       bp = (mp_ptr) TMP_ALLOC(bn * BYTES_PER_MP_LIMB);
        !           116:       MPN_COPY (bp, ap, bn);
        !           117:       /* ap == cp cannot occur since we would have b=c, which is detected
        !           118:         in mpfr_add or mpfr_sub */
        !           119:     }
        !           120:   else if (ap == cp)
        !           121:     {
        !           122:       cp = (mp_ptr) TMP_ALLOC (cn * BYTES_PER_MP_LIMB);
        !           123:       MPN_COPY(cp, ap, cn);
        !           124:     }
        !           125:
        !           126:   /* here we have shift_c = (diff_exp - cancel) % BITS_PER_MP_LIMB,
        !           127:      thus we want cancel2 = ceil((cancel - diff_exp) / BITS_PER_MP_LIMB) */
        !           128:
        !           129:   cancel2 = (long int) (cancel - (diff_exp - shift_c)) / BITS_PER_MP_LIMB;
        !           130:   /* the high cancel2 limbs from b should not be taken into account */
        !           131: #ifdef DEBUG
        !           132:   printf("cancel=%u cancel1=%u cancel2=%d\n", cancel, cancel1, cancel2);
        !           133: #endif
        !           134:
        !           135:   /*               ap[an-1]        ap[0]
        !           136:              <----------------+-----------|---->
        !           137:              <----------PREC(a)----------><-sh->
        !           138:  cancel1
        !           139:  limbs        bp[bn-cancel1-1]
        !           140:  <--...-----><----------------+-----------+----------->
        !           141:   cancel2
        !           142:   limbs       cp[cn-cancel2-1]                                    cancel2 >= 0
        !           143:     <--...--><----------------+----------------+---------------->
        !           144:                 (-cancel2)                                        cancel2 < 0
        !           145:                    limbs      <----------------+---------------->
        !           146:   */
        !           147:
        !           148:   /* first part: put in ap[0..an-1] the value of high(b) - high(c),
        !           149:      where high(b) consists of the high an+cancel1 limbs of b,
        !           150:      and high(c) consists of the high an+cancel2 limbs of c.
        !           151:    */
        !           152:
        !           153:   /* copy high(b) into a */
        !           154:   if (an + cancel1 <= bn) /* a: <----------------+-----------|---->
        !           155:                         b: <-----------------------------------------> */
        !           156:       MPN_COPY (ap, bp + bn - (an + cancel1), an);
        !           157:   else  /* a: <----------------+-----------|---->
        !           158:        b: <-------------------------> */
        !           159:     if (cancel1 < bn) /* otherwise b does not overlap with a */
        !           160:       {
        !           161:        MPN_ZERO (ap, an + cancel1 - bn);
        !           162:        MPN_COPY (ap + an + cancel1 - bn, bp, bn - cancel1);
        !           163:       }
        !           164:     else
        !           165:       MPN_ZERO (ap, an);
        !           166:
        !           167: #ifdef DEBUG
        !           168:   printf("after copying high(b), a="); mpfr_print_binary(a); putchar('\n');
        !           169: #endif
        !           170:
        !           171:   /* subtract high(c) */
        !           172:   if (an + cancel2 > 0) /* otherwise c does not overlap with a */
        !           173:     {
        !           174:       mp_limb_t *ap2;
        !           175:
        !           176:       if (cancel2 >= 0)
        !           177:        {
        !           178:          if (an + cancel2 <= cn) /* a: <----------------------------->
        !           179:                              c: <-----------------------------------------> */
        !           180:            mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an);
        !           181:          else /* a: <---------------------------->
        !           182:              c: <-------------------------> */
        !           183:            {
        !           184:              ap2 = ap + an + cancel2 - cn;
        !           185:              if (cn > cancel2)
        !           186:                mpn_sub_n (ap2, ap2, cp, cn - cancel2);
        !           187:            }
        !           188:        }
        !           189:       else /* cancel2 < 0 */
        !           190:        {
        !           191:          if (an + cancel2 <= cn) /* a: <----------------------------->
        !           192:                                          c: <-----------------------------> */
        !           193:              borrow = mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an + cancel2);
        !           194:          else /* a: <---------------------------->
        !           195:                        c: <----------------> */
        !           196:            {
        !           197:              ap2 = ap + an + cancel2 - cn;
        !           198:              borrow = mpn_sub_n (ap2, ap2, cp, cn);
        !           199:            }
        !           200:          ap2 = ap + an + cancel2;
        !           201:          mpn_sub_1 (ap2, ap2, -cancel2, borrow);
        !           202:        }
        !           203:     }
        !           204:
        !           205: #ifdef DEBUG
        !           206:   printf("after subtracting high(c), a="); mpfr_print_binary(a); putchar('\n');
        !           207: #endif
        !           208:
        !           209:   /* now perform rounding */
        !           210:   sh = an * BITS_PER_MP_LIMB - MPFR_PREC(a); /* last unused bits from a */
        !           211:   carry = ap[0] & ((MP_LIMB_T_ONE << sh) - MP_LIMB_T_ONE);
        !           212:   ap[0] -= carry;
        !           213:
        !           214:   if (rnd_mode == GMP_RNDN)
        !           215:     {
        !           216:       if (sh)
        !           217:        {
        !           218:          is_exact = (carry == 0);
        !           219:          /* can decide except when carry = 2^(sh-1) [middle]
        !           220:             or carry = 0 [truncate, but cannot decide inexact flag] */
        !           221:          down = (carry < (MP_LIMB_T_ONE << (sh - 1)));
        !           222:          if (carry > (MP_LIMB_T_ONE << (sh - 1)))
        !           223:            goto add_one_ulp;
        !           224:          else if ((0 < carry) && down)
        !           225:            {
        !           226:              inexact = -1; /* result if smaller than exact value */
        !           227:              goto truncate;
        !           228:            }
        !           229:        }
        !           230:     }
        !           231:   else /* directed rounding: set rnd_mode to RNDZ iff towards zero */
        !           232:     {
        !           233:       if (((rnd_mode == GMP_RNDD) && (MPFR_SIGN(a) > 0)) ||
        !           234:          ((rnd_mode == GMP_RNDU) && (MPFR_SIGN(a) < 0)))
        !           235:        rnd_mode = GMP_RNDZ;
        !           236:
        !           237:       if (carry)
        !           238:        {
        !           239:          if (rnd_mode == GMP_RNDZ)
        !           240:            {
        !           241:              inexact = -1;
        !           242:              goto truncate;
        !           243:            }
        !           244:          else /* round away */
        !           245:            goto add_one_ulp;
        !           246:        }
        !           247:     }
        !           248:
        !           249:   /* we have to consider the low (bn - (an+cancel1)) limbs from b,
        !           250:      and the (cn - (an+cancel2)) limbs from c. */
        !           251:   bn -= an + cancel1;
        !           252:   cn0 = cn;
        !           253:   cn -= (long int) an + cancel2;
        !           254: #ifdef DEBUG
        !           255:   printf("last %d bits from a are %lu, bn=%ld, cn=%ld\n", sh, carry, bn, cn);
        !           256: #endif
        !           257:
        !           258:   for (k = 0; (bn > 0) || (cn > 0); k = 1)
        !           259:     {
        !           260:       bb = (bn > 0) ? bp[--bn] : 0;
        !           261:       if ((cn > 0) && (cn-- <= cn0))
        !           262:        cc = cp[cn];
        !           263:       else
        !           264:        cc = 0;
        !           265:
        !           266:       if (down == 0)
        !           267:        down = (bb < cc);
        !           268:
        !           269:       if ((rnd_mode == GMP_RNDN) && !k && sh == 0)
        !           270:        {
        !           271:          mp_limb_t half = GMP_LIMB_HIGHBIT;
        !           272:
        !           273:          is_exact = (bb == cc);
        !           274:
        !           275:          /* add one ulp if bb > cc + half
        !           276:             truncate if cc - half < bb < cc + half
        !           277:             sub one ulp if bb < cc - half
        !           278:          */
        !           279:
        !           280:          if (down)
        !           281:            {
        !           282:              if (cc >= half)
        !           283:                cc -= half;
        !           284:              else
        !           285:                bb += half;
        !           286:            }
        !           287:          else /* bb >= cc */
        !           288:            {
        !           289:              if (cc < half)
        !           290:                cc += half;
        !           291:              else
        !           292:                bb -= half;
        !           293:            }
        !           294:        }
        !           295:
        !           296: #ifdef DEBUG
        !           297:       printf("    bb=%lu cc=%lu down=%d is_exact=%d\n", bb, cc, down, is_exact);
        !           298: #endif
        !           299:       if (bb < cc)
        !           300:        {
        !           301:          if (rnd_mode == GMP_RNDZ)
        !           302:            goto sub_one_ulp;
        !           303:          else if (rnd_mode != GMP_RNDN) /* round away */
        !           304:            {
        !           305:              inexact = 1;
        !           306:              goto truncate;
        !           307:            }
        !           308:          else /* round to nearest */
        !           309:            {
        !           310:              if (is_exact && sh == 0)
        !           311:                {
        !           312:                  inexact = 0;
        !           313:                  goto truncate;
        !           314:                }
        !           315:              else if (down && sh == 0)
        !           316:                goto sub_one_ulp;
        !           317:              else
        !           318:                {
        !           319:                  inexact = (is_exact) ? 1 : -1;
        !           320:                  goto truncate;
        !           321:                }
        !           322:            }
        !           323:        }
        !           324:       else if (bb > cc)
        !           325:        {
        !           326:          if (rnd_mode == GMP_RNDZ)
        !           327:            {
        !           328:              inexact = -1;
        !           329:              goto truncate;
        !           330:            }
        !           331:          else if (rnd_mode != GMP_RNDN) /* round away */
        !           332:              goto add_one_ulp;
        !           333:          else /* round to nearest */
        !           334:            {
        !           335:              if (is_exact)
        !           336:                {
        !           337:                  inexact = -1;
        !           338:                  goto truncate;
        !           339:                }
        !           340:              else if (down)
        !           341:                {
        !           342:                  inexact = 1;
        !           343:                  goto truncate;
        !           344:                }
        !           345:              else
        !           346:                goto add_one_ulp;
        !           347:            }
        !           348:        }
        !           349:     }
        !           350:
        !           351:   if ((rnd_mode == GMP_RNDN) && !is_exact)
        !           352:     {
        !           353:       /* even rounding rule */
        !           354:       if ((ap[0] >> sh) & 1)
        !           355:        {
        !           356:          if (down) goto sub_one_ulp;
        !           357:          else goto add_one_ulp;
        !           358:        }
        !           359:       else
        !           360:        inexact = (down) ? 1 : -1;
        !           361:     }
        !           362:   else
        !           363:     inexact = 0;
        !           364:   goto truncate;
        !           365:
        !           366:  sub_one_ulp: /* add one unit in last place to a */
        !           367:   mpn_sub_1 (ap, ap, an, MP_LIMB_T_ONE << sh);
        !           368:   inexact = -1;
        !           369:   goto end_of_sub;
        !           370:
        !           371:  add_one_ulp: /* add one unit in last place to a */
        !           372:   if (mpn_add_1 (ap, ap, an, MP_LIMB_T_ONE << sh)) /* result is a power of 2 */
        !           373:     {
        !           374:       ap[an-1] = GMP_LIMB_HIGHBIT;
        !           375:       add_exp = 1;
        !           376:     }
        !           377:   inexact = 1; /* result larger than exact value */
        !           378:
        !           379:  truncate:
        !           380:   if ((ap[an-1] >> (BITS_PER_MP_LIMB - 1)) == 0) /* case 1 - epsilon */
        !           381:     {
        !           382:       ap[an-1] = GMP_LIMB_HIGHBIT;
        !           383:       add_exp = 1;
        !           384:     }
        !           385:
        !           386:  end_of_sub:
        !           387:   /* we have to set MPFR_EXP(a) to MPFR_EXP(b) - cancel + add_exp, taking
        !           388:      care of underflows/overflows in that computation, and of the allowed
        !           389:      exponent range */
        !           390:   if (cancel)
        !           391:     {
        !           392:       mp_exp_t exp_b;
        !           393:
        !           394:       cancel -= add_exp; /* still valid as unsigned long */
        !           395:       exp_b = MPFR_EXP(b); /* save it in case a equals b */
        !           396:       MPFR_EXP(a) = MPFR_EXP(b) - cancel;
        !           397:       if ((MPFR_EXP(a) > exp_b) /* underflow in type mp_exp_t */
        !           398:          || (MPFR_EXP(a) < __mpfr_emin))
        !           399:        {
        !           400:          TMP_FREE(marker);
        !           401:          return mpfr_set_underflow (a, rnd_mode, MPFR_SIGN(a));
        !           402:        }
        !           403:     }
        !           404:   else /* cancel = 0: MPFR_EXP(a) <- MPFR_EXP(b) + add_exp */
        !           405:     {
        !           406:       /* in case cancel = 0, add_exp can still be 1, in case b is just
        !           407:         below a power of two, c is very small, prec(a) < prec(b),
        !           408:         and rnd=away or nearest */
        !           409:       if (add_exp && MPFR_EXP(b) == __mpfr_emax)
        !           410:        {
        !           411:          TMP_FREE(marker);
        !           412:          return mpfr_set_overflow (a, rnd_mode, MPFR_SIGN(a));
        !           413:        }
        !           414:       MPFR_EXP(a) = MPFR_EXP(b) + add_exp;
        !           415:     }
        !           416:   TMP_FREE(marker);
        !           417: #ifdef DEBUG
        !           418:   printf ("result is a="); mpfr_print_binary(a); putchar('\n');
        !           419: #endif
        !           420:   /* check that result is msb-normalized */
        !           421:   MPFR_ASSERTN(ap[an-1] > ~ap[an-1]);
        !           422:   return inexact * MPFR_SIGN(a);
        !           423: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>