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

Annotation of OpenXM_contrib/gmp/mpfr/round_prec.c, Revision 1.1.1.1

1.1       ohara       1: /* mpfr_round_raw_generic, mpfr_round_raw2, mpfr_round_raw, mpfr_round_prec,
                      2:    mpfr_can_round, mpfr_can_round_raw -- various rounding functions
                      3:
                      4: Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
                      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: #if (BITS_PER_MP_LIMB & (BITS_PER_MP_LIMB - 1))
                     29: #error "BITS_PER_MP_LIMB must be a power of 2"
                     30: #endif
                     31:
                     32: /*
                     33:  * If flag = 0, puts in y the value of xp (with precision xprec and
                     34:  * sign 1 if negative=0, -1 otherwise) rounded to precision yprec and
                     35:  * direction rnd_mode. Supposes x is not zero nor NaN nor +/- Infinity
                     36:  * (i.e. *xp != 0). If inexp != NULL, computes the inexact flag of the
                     37:  * rounding.
                     38:  *
                     39:  * In case of even rounding when rnd = GMP_RNDN, returns 2 or -2.
                     40:  *
                     41:  * If flag = 1, just returns whether one should add 1 or not for rounding.
                     42:  *
                     43:  * Note: yprec may be < MPFR_PREC_MIN; in particular, it may be equal
                     44:  * to 1. In this case, the even rounding is done away from 0, which is
                     45:  * a natural generalization. Indeed, a number with 1-bit precision can
                     46:  * be seen as a denormalized number with more precision.
                     47:  */
                     48:
                     49: int
                     50: mpfr_round_raw_generic(mp_limb_t *yp, mp_limb_t *xp, mp_prec_t xprec,
                     51:                        int neg, mp_prec_t yprec, mp_rnd_t rnd_mode,
                     52:                        int *inexp, int flag)
                     53: {
                     54:   mp_size_t xsize, nw;
                     55:   mp_limb_t himask, lomask;
                     56:   int rw, carry = 0;
                     57:
                     58:   xsize = (xprec-1)/BITS_PER_MP_LIMB + 1;
                     59:
                     60:   nw = yprec / BITS_PER_MP_LIMB;
                     61:   rw = yprec & (BITS_PER_MP_LIMB - 1);
                     62:
                     63:   if (flag && !inexp && (rnd_mode==GMP_RNDZ || xprec <= yprec
                     64:                         || (rnd_mode==GMP_RNDU && neg)
                     65:                         || (rnd_mode==GMP_RNDD && neg==0)))
                     66:     return 0;
                     67:
                     68:   if (rw)
                     69:     {
                     70:       nw++;
                     71:       lomask = ((MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw)) - MP_LIMB_T_ONE);
                     72:       himask = ~lomask;
                     73:     }
                     74:   else
                     75:     {
                     76:       lomask = -1;
                     77:       himask = -1;
                     78:     }
                     79:   MPFR_ASSERTN(nw >= 1);
                     80:
                     81:   if (xprec <= yprec)
                     82:     { /* No rounding is necessary. */
                     83:       /* if yp=xp, maybe an overlap: MPN_COPY_DECR is ok when src <= dst */
                     84:       MPFR_ASSERTN(nw >= xsize);
                     85:       if (inexp)
                     86:         *inexp = 0;
                     87:       if (flag)
                     88:         return 0;
                     89:       MPN_COPY_DECR(yp + (nw - xsize), xp, xsize);
                     90:       MPN_ZERO(yp, nw - xsize);
                     91:     }
                     92:   else
                     93:     {
                     94:       mp_limb_t sb;
                     95:
                     96:       if ((rnd_mode == GMP_RNDU && neg) ||
                     97:           (rnd_mode == GMP_RNDD && !neg))
                     98:         rnd_mode = GMP_RNDZ;
                     99:
                    100:       if (inexp || rnd_mode != GMP_RNDZ)
                    101:         {
                    102:           mp_size_t k;
                    103:
                    104:           k = xsize - nw;
                    105:           if (!rw)
                    106:             k--;
                    107:           MPFR_ASSERTN(k >= 0);
                    108:           sb = xp[k] & lomask;  /* First non-significant bits */
                    109:           if (rnd_mode == GMP_RNDN)
                    110:             {
                    111:               mp_limb_t rbmask = MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw - 1);
                    112:               if (sb & rbmask) /* rounding bit */
                    113:                 sb &= ~rbmask; /* it is 1, clear it */
                    114:               else
                    115:                 rnd_mode = GMP_RNDZ; /* it is 0, behave like rounding to 0 */
                    116:             }
                    117:           while (sb == 0 && k > 0)
                    118:             sb = xp[--k];
                    119:           if (rnd_mode == GMP_RNDN)
                    120:             { /* rounding to nearest, with rounding bit = 1 */
                    121:               if (sb == 0) /* Even rounding. */
                    122:                 {
                    123:                   sb = xp[xsize - nw] & (himask ^ (himask << 1));
                    124:                   if (inexp)
                    125:                     *inexp = ((neg != 0) ^ (sb != 0))
                    126:                       ? MPFR_EVEN_INEX  : -MPFR_EVEN_INEX;
                    127:                 }
                    128:               else /* sb != 0 */
                    129:                 {
                    130:                   if (inexp)
                    131:                     *inexp = (neg == 0) ? 1 : -1;
                    132:                 }
                    133:             }
                    134:           else if (inexp)
                    135:             *inexp = sb == 0 ? 0
                    136:               : (((neg != 0) ^ (rnd_mode != GMP_RNDZ)) ? 1 : -1);
                    137:         }
                    138:       else
                    139:         sb = 0;
                    140:
                    141:     if (flag)
                    142:       return sb != 0 && rnd_mode != GMP_RNDZ;
                    143:
                    144:     if (sb != 0 && rnd_mode != GMP_RNDZ)
                    145:       carry = mpn_add_1(yp, xp + xsize - nw, nw,
                    146:                         rw ? MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw) : 1);
                    147:     else
                    148:       MPN_COPY_INCR(yp, xp + xsize - nw, nw);
                    149:
                    150:     yp[0] &= himask;
                    151:   }
                    152:
                    153:   return carry;
                    154: }
                    155:
                    156: int
                    157: mpfr_round_prec (mpfr_ptr x, mp_rnd_t rnd_mode, mp_prec_t prec)
                    158: {
                    159:   mp_limb_t *tmp, *xp;
                    160:   int carry, inexact;
                    161:   mp_prec_t nw;
                    162:   TMP_DECL(marker);
                    163:
                    164:   MPFR_ASSERTN(prec >= MPFR_PREC_MIN && prec <= MPFR_PREC_MAX);
                    165:
                    166:   nw = 1 + (prec - 1) / BITS_PER_MP_LIMB; /* needed allocated limbs */
                    167:
                    168:   /* check if x has enough allocated space for the mantissa */
                    169:   if (nw > MPFR_ABSSIZE(x))
                    170:     {
                    171:       MPFR_MANT(x) = (mp_ptr) (*__gmp_reallocate_func)
                    172:         (MPFR_MANT(x), (size_t) MPFR_ABSSIZE(x) * BYTES_PER_MP_LIMB,
                    173:          (size_t) nw * BYTES_PER_MP_LIMB);
                    174:       MPFR_SET_ABSSIZE(x, nw); /* new number of allocated limbs */
                    175:     }
                    176:
                    177:   if (MPFR_IS_NAN(x))
                    178:     MPFR_RET_NAN;
                    179:
                    180:   if (MPFR_IS_INF(x))
                    181:     return 0; /* infinity is exact */
                    182:
                    183:   /* x is a real number */
                    184:
                    185:   TMP_MARK(marker);
                    186:   tmp = TMP_ALLOC (nw * BYTES_PER_MP_LIMB);
                    187:   xp = MPFR_MANT(x);
                    188:   carry = mpfr_round_raw (tmp, xp, MPFR_PREC(x), MPFR_SIGN(x) < 0,
                    189:                           prec, rnd_mode, &inexact);
                    190:   MPFR_PREC(x) = prec;
                    191:
                    192:   if (carry)
                    193:     {
                    194:       mp_exp_t exp = MPFR_EXP(x);
                    195:
                    196:       if (exp == __mpfr_emax)
                    197:         (void) mpfr_set_overflow(x, rnd_mode, MPFR_SIGN(x));
                    198:       else
                    199:         {
                    200:           MPFR_EXP(x)++;
                    201:           xp[nw - 1] = GMP_LIMB_HIGHBIT;
                    202:           if (nw - 1 > 0)
                    203:             MPN_ZERO(xp, nw - 1);
                    204:         }
                    205:     }
                    206:   else
                    207:     MPN_COPY(xp, tmp, nw);
                    208:
                    209:   TMP_FREE(marker);
                    210:   return inexact;
                    211: }
                    212:
                    213: /* assumption: BITS_PER_MP_LIMB is a power of 2 */
                    214:
                    215: /* assuming b is an approximation of x in direction rnd1
                    216:    with error at most 2^(MPFR_EXP(b)-err), returns 1 if one is
                    217:    able to round exactly x to precision prec with direction rnd2,
                    218:    and 0 otherwise.
                    219:
                    220:    Side effects: none.
                    221: */
                    222:
                    223: int
                    224: mpfr_can_round (mpfr_ptr b, mp_exp_t err, mp_rnd_t rnd1,
                    225:                mp_rnd_t rnd2, mp_prec_t prec)
                    226: {
                    227:   return MPFR_IS_ZERO(b) ? 0 : /* we cannot round if b=0 */
                    228:     mpfr_can_round_raw (MPFR_MANT(b),
                    229:                        (MPFR_PREC(b) - 1)/BITS_PER_MP_LIMB + 1,
                    230:                        MPFR_SIGN(b), err, rnd1, rnd2, prec);
                    231: }
                    232:
                    233: int
                    234: mpfr_can_round_raw (mp_limb_t *bp, mp_size_t bn, int neg, mp_exp_t err0,
                    235:                     mp_rnd_t rnd1, mp_rnd_t rnd2, mp_prec_t prec)
                    236: {
                    237:   mp_prec_t err;
                    238:   mp_size_t k, k1, tn;
                    239:   int s, s1;
                    240:   mp_limb_t cc, cc2;
                    241:   mp_limb_t *tmp;
                    242:   TMP_DECL(marker);
                    243:
                    244:   if (err0 < 0 || (mp_exp_unsigned_t) err0 <= prec)
                    245:     return 0;  /* can't round */
                    246:
                    247:   neg = neg <= 0;
                    248:
                    249:   /* if the error is smaller than ulp(b), then anyway it will propagate
                    250:      up to ulp(b) */
                    251:   err = ((mp_exp_unsigned_t) err0 > (mp_prec_t) bn * BITS_PER_MP_LIMB) ?
                    252:     (mp_prec_t) bn * BITS_PER_MP_LIMB : err0;
                    253:
                    254:   /* warning: if k = m*BITS_PER_MP_LIMB, consider limb m-1 and not m */
                    255:   k = (err - 1) / BITS_PER_MP_LIMB;
                    256:   s = err % BITS_PER_MP_LIMB;
                    257:   if (s)
                    258:     s = BITS_PER_MP_LIMB - s;
                    259:   /* the error corresponds to bit s in limb k, the most significant limb
                    260:      being limb 0 */
                    261:   k1 = (prec - 1) / BITS_PER_MP_LIMB;
                    262:   s1 = prec % BITS_PER_MP_LIMB;
                    263:   if (s1)
                    264:     s1 = BITS_PER_MP_LIMB - s1;
                    265:
                    266:   /* the last significant bit is bit s1 in limb k1 */
                    267:
                    268:   /* don't need to consider the k1 most significant limbs */
                    269:   k -= k1;
                    270:   bn -= k1;
                    271:   prec -= (mp_prec_t) k1 * BITS_PER_MP_LIMB;
                    272:   /* if when adding or subtracting (1 << s) in bp[bn-1-k], it does not
                    273:      change bp[bn-1] >> s1, then we can round */
                    274:
                    275:   if (rnd1 == GMP_RNDU)
                    276:     if (neg)
                    277:       rnd1 = GMP_RNDZ;
                    278:
                    279:   if (rnd1 == GMP_RNDD)
                    280:     rnd1 = neg ? GMP_RNDU : GMP_RNDZ;
                    281:
                    282:   /* in the sequel, RNDU = towards infinity, RNDZ = towards zero */
                    283:
                    284:   TMP_MARK(marker);
                    285:   tn = bn;
                    286:   k++; /* since we work with k+1 everywhere */
                    287:   tmp = TMP_ALLOC(tn * BYTES_PER_MP_LIMB);
                    288:   if (bn > k)
                    289:     MPN_COPY (tmp, bp, bn - k);
                    290:
                    291:   if (rnd1 != GMP_RNDN)
                    292:     { /* GMP_RNDZ or GMP_RNDU */
                    293:       cc = (bp[bn - 1] >> s1) & 1;
                    294:       cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec);
                    295:
                    296:       /* now round b +/- 2^(MPFR_EXP(b)-err) */
                    297:       cc2 = rnd1 == GMP_RNDZ ?
                    298:         mpn_add_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << s) :
                    299:         mpn_sub_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << s);
                    300:     }
                    301:   else
                    302:     { /* GMP_RNDN */
                    303:       /* first round b+2^(MPFR_EXP(b)-err) */
                    304:       cc = mpn_add_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << s);
                    305:       cc = (tmp[bn - 1] >> s1) & 1; /* gives 0 when cc=1 */
                    306:       cc ^= mpfr_round_raw2 (tmp, bn, neg, rnd2, prec);
                    307:
                    308:       /* now round b-2^(MPFR_EXP(b)-err) */
                    309:       cc2 = mpn_sub_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << s);
                    310:     }
                    311:
                    312:   if (cc2 && cc)
                    313:     {
                    314:       TMP_FREE(marker);
                    315:       return 0;
                    316:     }
                    317:
                    318:   cc2 = (tmp[bn - 1] >> s1) & 1;
                    319:   cc2 ^= mpfr_round_raw2 (tmp, bn, neg, rnd2, prec);
                    320:
                    321:   TMP_FREE(marker);
                    322:   return cc == cc2;
                    323: }

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