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

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

1.1     ! maekawa     1: /* mpfr_round_raw2, mpfr_round_raw, mpfr_round, mpfr_can_round,
        !             2:    mpfr_can_round_raw -- various rounding functions
        !             3:
        !             4: Copyright (C) 1999 PolKA project, Inria Lorraine and Loria
        !             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 Library General Public License as published by
        !            10: the Free Software Foundation; either version 2 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 Library General Public
        !            16: License for more details.
        !            17:
        !            18: You should have received a copy of the GNU Library 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 <stdio.h>
        !            24: #include "gmp.h"
        !            25: #include "gmp-impl.h"
        !            26: #include "mpfr.h"
        !            27:
        !            28: #ifdef Exp
        !            29: #include "longlong.h"
        !            30: #endif
        !            31:
        !            32: /* returns 0 if round(sign*xp[0..xn-1], prec, rnd) =
        !            33:    round(sign*xp[0..xn-1], prec, GMP_RNDZ), 1 otherwise,
        !            34:    where sign=1 if neg=0, sign=-1 otherwise.
        !            35:
        !            36:    Does *not* modify anything.
        !            37: */
        !            38: int
        !            39: #if __STDC__
        !            40: mpfr_round_raw2(mp_limb_t *xp, unsigned long xn,
        !            41:                char neg, char rnd, unsigned long prec)
        !            42: #else
        !            43: mpfr_round_raw2(xp, xn, neg, rnd, prec)
        !            44:      mp_limb_t *xp;
        !            45:      unsigned long xn;
        !            46:      char neg;
        !            47:      char rnd;
        !            48:      unsigned long prec;
        !            49: #endif
        !            50: {
        !            51:   unsigned long nw; long wd; char rw; short l; mp_limb_t mask;
        !            52:
        !            53:   nw = prec / BITS_PER_MP_LIMB; rw = prec & (BITS_PER_MP_LIMB - 1);
        !            54:   if (rw) nw++;
        !            55:   if (rnd==GMP_RNDZ || xn<nw || (rnd==GMP_RNDU && neg)
        !            56:       || (rnd==GMP_RNDD && neg==0)) return 0;
        !            57:
        !            58:   mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - 1);
        !            59:   switch (rnd)
        !            60:     {
        !            61:     case GMP_RNDU:
        !            62:     case GMP_RNDD:
        !            63:       if (xp[xn - nw] & ~mask) return 1;
        !            64:       for (l = nw + 1;l <= xn; l++)
        !            65:        if (xp[xn - l]) break;
        !            66:       return (l <= xn);
        !            67:
        !            68:     case GMP_RNDN:
        !            69:     /* First check if we are just halfway between two representable numbers */
        !            70:       wd = xn - nw;
        !            71:       if (!rw)
        !            72:        {
        !            73:          if (!wd) /* all bits are significative */ return 0;
        !            74:          wd--;
        !            75:          if (xp[wd] == ((mp_limb_t)1 << (BITS_PER_MP_LIMB - 1)))
        !            76:            {
        !            77:              do wd--; while (wd > 0 && !xp[wd]);
        !            78:              if (!wd) { return 1; } else return xp[xn - nw] & 1;
        !            79:            }
        !            80:
        !            81:          return xp[wd]>>(BITS_PER_MP_LIMB - 1);
        !            82:        }
        !            83:       else
        !            84:       if (rw + 1 < BITS_PER_MP_LIMB)
        !            85:        {
        !            86:          if ((xp[wd] & (~mask)) == (((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw - 1)))
        !            87:              do { wd--; } while (wd >= 0 && !xp[wd]);
        !            88:          else return ((xp[wd]>>(BITS_PER_MP_LIMB - rw - 1)) & 1);
        !            89:
        !            90:          /* first limb was in the middle, and others down to wd+1 were 0 */
        !            91:          if (wd>=0) return 1;
        !            92:          else
        !            93:              return ((xp[xn - nw] & mask) >> (BITS_PER_MP_LIMB - rw)) & 1;
        !            94:        }
        !            95:       else
        !            96:        /* Modified PZ, 27 May 1999:
        !            97:           rw, i.e. the number of bits stored in xp[xn-nw], is
        !            98:           BITS_PER_MP_LIMB-1, i.e. there is exactly one non significant bit.
        !            99:           We are just halfway iff xp[wd] has its low significant bit
        !           100:           set and all limbs xp[0]...xp[wd-1] are zero */
        !           101:        {
        !           102:          if (xp[wd] & 1)
        !           103:              do wd--; while (wd >= 0 && !xp[wd]);
        !           104:          return ((wd<0) ? xp[xn-nw]>>1 : xp[xn-nw]) & 1;
        !           105:        }
        !           106:     default: return 0;
        !           107:     }
        !           108: }
        !           109:
        !           110: /* puts in y the value of xp (with precision xprec and sign 1 if negative=0,
        !           111:    -1 otherwise) rounded to precision yprec and direction RND_MODE
        !           112:    Supposes x is not zero nor NaN nor +/- Infinity (i.e. *xp != 0).
        !           113: */
        !           114: int
        !           115: #if __STDC__
        !           116: mpfr_round_raw(mp_limb_t *y, mp_limb_t *xp, unsigned long xprec, char negative,
        !           117:               unsigned long yprec, char RND_MODE)
        !           118: #else
        !           119: mpfr_round_raw(y, xp, xprec, negative, yprec, RND_MODE)
        !           120:      mp_limb_t *y;
        !           121:      mp_limb_t *xp;
        !           122:      unsigned long xprec;
        !           123:      char negative;
        !           124:      unsigned long yprec;
        !           125:      char RND_MODE;
        !           126: #endif
        !           127: {
        !           128:   unsigned long nw, xsize; mp_limb_t mask;
        !           129:   char rw, xrw, carry = 0;
        !           130:
        !           131:   xsize = (xprec-1)/BITS_PER_MP_LIMB + 1;
        !           132:   xrw = xprec % BITS_PER_MP_LIMB; if (xrw == 0) { xrw = BITS_PER_MP_LIMB; }
        !           133:
        !           134: #ifdef Exp
        !           135:   count_leading_zeros(flag, xp[xsize-1]);
        !           136:   yprec += flag;
        !           137: #endif
        !           138:
        !           139:   nw = yprec / BITS_PER_MP_LIMB; rw = yprec & (BITS_PER_MP_LIMB - 1);
        !           140:   if (rw) nw++;
        !           141:   /* number of words needed to represent x */
        !           142:
        !           143:   mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - (mp_limb_t)1);
        !           144:
        !           145:   /* precision is larger than the size of x. No rounding is necessary.
        !           146:      Just add zeroes at the end */
        !           147:   if (xsize < nw) {
        !           148:     MPN_COPY(y + nw - xsize, xp, xsize);
        !           149:     MPN_ZERO(y, nw - xsize); /* PZ 27 May 99 */
        !           150:     y[0] &= mask;
        !           151:     return 0;
        !           152:   }
        !           153:
        !           154:   if (mpfr_round_raw2(xp, xsize, negative, RND_MODE, yprec))
        !           155:     carry = mpn_add_1(y, xp + xsize - nw, nw,
        !           156:                           ((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw));
        !           157:   else MPN_COPY(y, xp + xsize - nw, nw);
        !           158:
        !           159:   y[0] &= mask;
        !           160:   return carry;
        !           161: }
        !           162:
        !           163: void
        !           164: #if __STDC__
        !           165: mpfr_round(mpfr_t x, char RND_MODE, unsigned long prec)
        !           166: #else
        !           167: mpfr_round(x, RND_MODE, prec)
        !           168:      mpfr_t x;
        !           169:      char RND_MODE;
        !           170:      unsigned long prec;
        !           171: #endif
        !           172: {
        !           173:   mp_limb_t *tmp; int carry; unsigned long nw;
        !           174:   TMP_DECL(marker);
        !           175:
        !           176:   nw = prec / BITS_PER_MP_LIMB;
        !           177:   if (prec & (BITS_PER_MP_LIMB - 1)) nw++;
        !           178:   TMP_MARK(marker);
        !           179:   tmp = TMP_ALLOC (nw * BYTES_PER_MP_LIMB);
        !           180:   carry = mpfr_round_raw(tmp, MANT(x), PREC(x), (SIGN(x)<0), prec, RND_MODE);
        !           181:
        !           182:   if (carry)
        !           183:     {
        !           184:       mpn_rshift(tmp, tmp, nw, 1);
        !           185:       tmp [nw-1] |= (((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1));
        !           186:       EXP(x)++;
        !           187:     }
        !           188:
        !           189:   if (SIGN(x)<0) { SIZE(x)=nw; CHANGE_SIGN(x); } else SIZE(x)=nw;
        !           190:   PREC(x) = prec;
        !           191:   MPN_COPY(MANT(x), tmp, nw);
        !           192:   TMP_FREE(marker);
        !           193: }
        !           194:
        !           195: /* hypotheses : BITS_PER_MP_LIMB est une puissance de 2
        !           196:                 dans un test, la premiere partie du && est evaluee d'abord */
        !           197:
        !           198:
        !           199: /* assuming b is an approximation of x in direction rnd1
        !           200:    with error at most 2^(EXP(b)-err), returns 1 if one is
        !           201:    able to round exactly x to precision prec with direction rnd2,
        !           202:    and 0 otherwise.
        !           203:
        !           204:    Side effects: none.
        !           205: */
        !           206:
        !           207: int
        !           208: #if __STDC__
        !           209: mpfr_can_round(mpfr_t b, unsigned long err, unsigned char rnd1,
        !           210:               unsigned char rnd2, unsigned long prec)
        !           211: #else
        !           212: mpfr_can_round(b, err, rnd1, rnd2, prec)
        !           213:      mpfr_t b;
        !           214:      unsigned long err;
        !           215:      unsigned char rnd1;
        !           216:      unsigned char rnd2;
        !           217:      unsigned long prec;
        !           218: #endif
        !           219: {
        !           220:   return mpfr_can_round_raw(MANT(b), (PREC(b) - 1)/BITS_PER_MP_LIMB + 1,
        !           221:                            SIGN(b), err, rnd1, rnd2, prec);
        !           222: }
        !           223:
        !           224: int
        !           225: #if __STDC__
        !           226: mpfr_can_round_raw(mp_limb_t *bp, unsigned long bn, int neg,
        !           227:                   unsigned long err, unsigned char rnd1, unsigned char rnd2,
        !           228:                   unsigned long prec)
        !           229: #else
        !           230: mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec)
        !           231:      mp_limb_t *bp;
        !           232:      unsigned long bn;
        !           233:      int neg;
        !           234:      unsigned long err;
        !           235:      unsigned char rnd1;
        !           236:      unsigned char rnd2;
        !           237:      unsigned long prec;
        !           238: #endif
        !           239: {
        !           240:   int k, k1, l, l1, tn; mp_limb_t cc, cc2, *tmp;
        !           241:   TMP_DECL(marker);
        !           242:
        !           243:   if (err<=prec) return 0;
        !           244:   neg = (neg > 0 ? 0 : 1);
        !           245:
        !           246:   /* warning: if k = m*BITS_PER_MP_LIMB, consider limb m-1 and not m */
        !           247:   k = (err-1)/BITS_PER_MP_LIMB;
        !           248:   l = err % BITS_PER_MP_LIMB; if (l) l = BITS_PER_MP_LIMB-l;
        !           249:   /* the error corresponds to bit l in limb k */
        !           250:   k1 = (prec-1)/BITS_PER_MP_LIMB;
        !           251:   l1 = prec%BITS_PER_MP_LIMB; if (l1) l1 = BITS_PER_MP_LIMB-l1;
        !           252:
        !           253:   /* the last significant bit is bit l1 in limb k1 */
        !           254:
        !           255:   /* don't need to consider the k1 most significant limbs */
        !           256:   k -= k1; bn -= k1; prec -= k1*BITS_PER_MP_LIMB; k1=0;
        !           257:
        !           258:   if (rnd1==GMP_RNDU) { if (neg) rnd1=GMP_RNDZ; }
        !           259:   if (rnd1==GMP_RNDD) { if (neg) rnd1=GMP_RNDU; else rnd1=GMP_RNDZ; }
        !           260:
        !           261:   /* in the sequel, RNDU = towards infinity, RNDZ = towards zero */
        !           262:
        !           263:   TMP_MARK(marker);
        !           264:   tn = bn;
        !           265:   k++; /* since we work with k+1 everywhere */
        !           266:
        !           267:   switch (rnd1) {
        !           268:
        !           269:   case GMP_RNDZ: /* b <= x <= b+2^(EXP(b)-err) */
        !           270:     tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB);
        !           271:     cc = (bp[bn-1]>>l1) & 1;
        !           272:     cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec);
        !           273:
        !           274:     /* now round b+2^(EXP(b)-err) */
        !           275:     cc2 = mpn_add_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l);
        !           276:     /* if carry, then all bits up to err were to 1, and we can round only
        !           277:        if cc==0 and mpfr_round_raw2 returns 0 below */
        !           278:     if (cc2 && cc) { TMP_FREE(marker); return 0; }
        !           279:     cc2 = (tmp[bn-1]>>l1) & 1; /* gives 0 when carry */
        !           280:     cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec);
        !           281:
        !           282:     TMP_FREE(marker);
        !           283:     return (cc == cc2);
        !           284:
        !           285:   case GMP_RNDU: /* b-2^(EXP(b)-err) <= x <= b */
        !           286:     tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB);
        !           287:     /* first round b */
        !           288:     cc = (bp[bn-1]>>l1) & 1;
        !           289:     cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec);
        !           290:
        !           291:     /* now round b-2^(EXP(b)-err) */
        !           292:     cc2 = mpn_sub_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l);
        !           293:     /* if borrow, then all bits up to err were to 0, and we can round only
        !           294:        if cc==0 and mpfr_round_raw2 returns 1 below */
        !           295:     if (cc2 && cc) { TMP_FREE(marker); return 0; }
        !           296:     cc2 = (tmp[bn-1]>>l1) & 1; /* gives 1 when carry */
        !           297:     cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec);
        !           298:
        !           299:     TMP_FREE(marker);
        !           300:     return (cc == cc2);
        !           301:
        !           302:   case GMP_RNDN: /* b-2^(EXP(b)-err-1) <= x <= b+2^(EXP(b)-err-1) */
        !           303:     if (l==0) tn++;
        !           304:     tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB);
        !           305:
        !           306:     /* this case is the same than GMP_RNDZ, except we first have to
        !           307:        subtract 2^(EXP(b)-err-1) from b */
        !           308:
        !           309:     if (l) {
        !           310:       l--; /* tn=bn */
        !           311:       mpn_sub_1(tmp+tn-k, bp+bn-k, k, (mp_limb_t)1<<l);
        !           312:     }
        !           313:     else {
        !           314:       MPN_COPY(tmp+1, bp, bn); *tmp=0; /* extra limb to add or subtract 1 */
        !           315:       k++; l=BITS_PER_MP_LIMB-1;
        !           316:       mpn_sub_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l);
        !           317:     }
        !           318:
        !           319:     /* round b-2^(EXP(b)-err-1) */
        !           320:     /* we can disregard borrow, since we start from tmp in 2nd case too */
        !           321:     cc = (tmp[tn-1]>>l1) & 1;
        !           322:     cc ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec);
        !           323:
        !           324:     if (l==BITS_PER_MP_LIMB-1) { l=0; k--; } else l++;
        !           325:
        !           326:     /* round b+2^(EXP(b)-err-1) = b-2^(EXP(b)-err-1) + 2^(EXP(b)-err) */
        !           327:     cc2 = mpn_add_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l);
        !           328:     /* if carry, then all bits up to err were to 1, and we can round only
        !           329:        if cc==0 and mpfr_round_raw2 returns 0 below */
        !           330:     if (cc2 && cc) { TMP_FREE(marker); return 0; }
        !           331:     cc2 = (tmp[tn-1]>>l1) & 1; /* gives 0 when carry */
        !           332:     cc2 ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec);
        !           333:
        !           334:     TMP_FREE(marker);
        !           335:     return (cc == cc2);
        !           336:   }
        !           337:   return 0;
        !           338: }

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