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

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

1.1     ! maekawa     1: /* mpfr_div -- divide two floating-point numbers
        !             2:
        !             3: Copyright (C) 1999 PolKA project, Inria Lorraine and Loria
        !             4:
        !             5: This file is part of the MPFR Library.
        !             6:
        !             7: The MPFR Library is free software; you can redistribute it and/or modify
        !             8: it under the terms of the GNU Library General Public License as published by
        !             9: the Free Software Foundation; either version 2 of the License, or (at your
        !            10: option) any later version.
        !            11:
        !            12: The MPFR Library is distributed in the hope that it will be useful, but
        !            13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
        !            15: License for more details.
        !            16:
        !            17: You should have received a copy of the GNU Library General Public License
        !            18: along with the MPFR Library; see the file COPYING.LIB.  If not, write to
        !            19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            20: MA 02111-1307, USA. */
        !            21:
        !            22: #include <math.h>
        !            23: #include <stdio.h>
        !            24: #include <stdlib.h>
        !            25: #include "gmp.h"
        !            26: #include "gmp-impl.h"
        !            27: #include "mpfr.h"
        !            28: #include "longlong.h"
        !            29:
        !            30: /* #define DEBUG */
        !            31:
        !            32: void
        !            33: mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode)
        !            34: {
        !            35:   mp_srcptr up, vp;
        !            36:   mp_ptr rp, tp, tp0, tmp;
        !            37:   mp_size_t usize, vsize, rrsize;
        !            38:   mp_size_t rsize;
        !            39:   mp_size_t sign_quotient;
        !            40:   mp_size_t prec, err;
        !            41:   mp_limb_t q_limb;
        !            42:   mp_exp_t rexp;
        !            43:   long k, mult, vn;
        !            44:   unsigned long cc = 0, rw, nw;
        !            45:   char can_round = 0;
        !            46:   TMP_DECL (marker);
        !            47:
        !            48:   if (FLAG_NAN(u) || FLAG_NAN(v)) { SET_NAN(r); return; }
        !            49:
        !            50:   usize = (PREC(u) - 1)/BITS_PER_MP_LIMB + 1;
        !            51:   vsize = (PREC(v) - 1)/BITS_PER_MP_LIMB + 1;
        !            52:   sign_quotient = (SIGN(u) == SIGN(v) ? 1 : -1);
        !            53:   prec = PREC(r);
        !            54:
        !            55:   if (!NOTZERO(u)) { SET_ZERO(r); return; }
        !            56:
        !            57:   if (!NOTZERO(v))
        !            58:     vsize = 1 / v->_mp_d[vsize - 1];    /* Gestion des infinis ? */
        !            59:
        !            60:   if (!NOTZERO(v))
        !            61:     {
        !            62:       r->_mp_exp = 0;
        !            63:       MPN_ZERO(r->_mp_d, r->_mp_size);
        !            64:       return;
        !            65:     }
        !            66:
        !            67:   up = u->_mp_d;
        !            68:   vp = v->_mp_d;
        !            69:
        !            70: #ifdef DEBUG
        !            71:       printf("Entering division : ");
        !            72:       for(k = usize - 1; k >= 0; k--) { printf("%lu ", up[k]); }
        !            73:       printf(" by ");
        !            74:       for(k = vsize - 1; k >= 0; k--) { printf("%lu ", vp[k]); }
        !            75:       printf(".\n");
        !            76: #endif
        !            77:
        !            78:   /* Compare the mantissas */
        !            79:   mult = mpn_cmp(up, vp, (usize > vsize ? vsize : usize));
        !            80:   if (mult == 0 && vsize > usize)
        !            81:     {
        !            82:       vn = vsize - usize;
        !            83:       while (vn >= 0) if (vp[vn--]) { mult = 1; break; }
        !            84:       /* On peut diagnostiquer ici pour pas cher le cas u = v */
        !            85:     }
        !            86:   else { mult = (mult < 0 ? 1 : 0); }
        !            87:
        !            88:   rsize = (PREC(r) + 3)/BITS_PER_MP_LIMB + 1;
        !            89:   rrsize = PREC(r)/BITS_PER_MP_LIMB + 1;
        !            90:   /* Three extra bits are needed in order to get the quotient with enough
        !            91:      precision ; take one extra bit for rrsize in order to solve more
        !            92:      easily the problem of rounding to nearest. */
        !            93:
        !            94:   /* ATTENTION, USIZE DOIT RESTER > A VSIZE !!!!!!!! */
        !            95:
        !            96:   do
        !            97:     {
        !            98:       TMP_MARK (marker);
        !            99:
        !           100:       rexp = u->_mp_exp - v->_mp_exp;
        !           101:
        !           102:       err = rsize*BITS_PER_MP_LIMB;
        !           103:       if (rsize < vsize) { err-=2; }
        !           104:       if (rsize < usize) { err--; }
        !           105:       if (err > rrsize * BITS_PER_MP_LIMB)
        !           106:        { err = rrsize * BITS_PER_MP_LIMB; }
        !           107:
        !           108:       tp0 = (mp_ptr) TMP_ALLOC ((rsize+rrsize) * BYTES_PER_MP_LIMB);
        !           109:       /* fill by zero rrsize low limbs of t */
        !           110:       MPN_ZERO(tp0, rrsize); tp = tp0 + rrsize;
        !           111:       tmp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB);
        !           112:       rp = (mp_ptr) TMP_ALLOC (rrsize * BYTES_PER_MP_LIMB);
        !           113:
        !           114:       if (vsize >= rsize) {
        !           115:        MPN_COPY (tmp, vp + vsize - rsize, rsize);
        !           116:       }
        !           117:       else {
        !           118:        MPN_COPY (tmp + rsize - vsize, vp, vsize);
        !           119:        MPN_ZERO (tmp, rsize - vsize);
        !           120:       }
        !           121:
        !           122:       if (usize >= rsize) {
        !           123:        MPN_COPY (tp, up + usize - rsize, rsize);
        !           124:       }
        !           125:       else {
        !           126:        MPN_COPY (tp + rsize - usize, up, usize);
        !           127:        MPN_ZERO (tp, rsize - usize);
        !           128:       }
        !           129:
        !           130:       /* Do the real job */
        !           131:
        !           132: #ifdef DEBUG
        !           133:       printf("Dividing : ");
        !           134:       for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); }
        !           135:       printf(" by ");
        !           136:       for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tmp[k]); }
        !           137:       printf(".\n");
        !           138: #endif
        !           139:
        !           140:       q_limb = (rsize==rrsize) /* use Burnikel-Ziegler algorithm */
        !           141:        ? mpn_divrem_n (rp, tp0, tmp, rsize)
        !           142:        : mpn_divrem (rp, 0, tp0, rsize+rrsize, tmp, rsize);
        !           143:       tp = tp0; /* location of remainder */
        !           144:
        !           145: #ifdef DEBUG
        !           146:       printf("The result is : \n");
        !           147:       printf("Quotient : ");
        !           148:       for(k = rrsize - 1; k >= 0; k--) { printf("%lu ", rp[k]); }
        !           149:       printf("Remainder : ");
        !           150:       for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); }
        !           151:       printf("(q_limb = %lu)\n", q_limb);
        !           152: #endif
        !           153:
        !           154:       /* msb-normalize the result */
        !           155:
        !           156:       if (q_limb)
        !           157:        {
        !           158:          count_leading_zeros(k, q_limb);
        !           159:          mpn_rshift(rp, rp, rrsize, BITS_PER_MP_LIMB - k);
        !           160:          rp[rrsize - 1] |= (q_limb << k);
        !           161:          rexp += BITS_PER_MP_LIMB - k;
        !           162:        }
        !           163:       else
        !           164:        {
        !           165:          count_leading_zeros(k, rp[rrsize - 1]);
        !           166:          if (k) { mpn_lshift(rp, rp, rrsize, k); }
        !           167:          rexp -= k;
        !           168:        }
        !           169:
        !           170:       can_round = (mpfr_can_round_raw(rp, rrsize, sign_quotient, err,
        !           171:                                     GMP_RNDN, rnd_mode, PREC(r))
        !           172:        || (usize == rsize && vsize == rsize &&
        !           173:            mpfr_can_round_raw(rp, rrsize, sign_quotient, err,
        !           174:                               GMP_RNDZ, rnd_mode, PREC(r))));
        !           175:
        !           176:       /* If we used all the limbs of both the dividend and the divisor,
        !           177:         then we have the correct RNDZ rounding */
        !           178:
        !           179:       if (!can_round && (rsize < usize || rsize < vsize))
        !           180:        {
        !           181: #ifdef DEBUG
        !           182:          printf("Increasing the precision.\n");
        !           183: #endif
        !           184:          printf("#");
        !           185:          TMP_FREE(marker);
        !           186:        }
        !           187:     }
        !           188:   while (!can_round && (rsize < usize || rsize < vsize)
        !           189:         && (rsize++) && (rrsize++));
        !           190:
        !           191:   /* ON PEUT PROBABLEMENT SE DEBROUILLER DES QUE rsize >= vsize */
        !           192:   /* MAIS IL FAUT AJOUTER LE BOUT QUI MANQUE DE usize A rsize */
        !           193:
        !           194:   if (can_round)
        !           195:     {
        !           196:       cc = mpfr_round_raw(rp, rp, err, (sign_quotient == -1 ? 1 : 0),
        !           197:                          PREC(r), rnd_mode);
        !           198:       rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1;
        !           199:     }
        !           200:   else
        !           201:     /* Use the remainder to find out the correct rounding */
        !           202:     /* Note that at this point the division has been done */
        !           203:     /* EXACTLY. */
        !           204:     if ((rnd_mode == GMP_RNDD && sign_quotient == -1)
        !           205:        || (rnd_mode == GMP_RNDU && sign_quotient == 1)
        !           206:        || (rnd_mode == GMP_RNDN))
        !           207:       {
        !           208:        /* We cannot round, so that the last bits of the quotient
        !           209:           have to be zero; just look if the remainder is nonzero */
        !           210:        k = rsize - 1;
        !           211:        while (k >= 0) { if (tp[k]) break; k--; }
        !           212:        if (k >= 0)
        !           213:          cc = mpn_add_1(rp, rp, rrsize, (mp_limb_t)1 << (BITS_PER_MP_LIMB -
        !           214:                                               (PREC(r) &
        !           215:                                                (BITS_PER_MP_LIMB - 1))));
        !           216:        else
        !           217:          if (rnd_mode == GMP_RNDN) /* even rounding */
        !           218:            {
        !           219:              rw = (PREC(r) + 1) & (BITS_PER_MP_LIMB - 1);
        !           220:              if (rw) { rw = BITS_PER_MP_LIMB - rw; nw = 0; } else nw = 1;
        !           221:              if ((rw ? (rp[nw] >> (rw + 1)) & 1 :
        !           222:                   (rp[nw] >> (BITS_PER_MP_LIMB - 1)) & 1))
        !           223:                {
        !           224:                  cc = mpn_add_1(rp + nw, rp + nw, rrsize,
        !           225:                                 ((mp_limb_t)1) << rw);
        !           226:                }
        !           227:            }
        !           228:        /* cas 0111111 */
        !           229:       }
        !           230:
        !           231:   if (sign_quotient != SIGN(r)) { CHANGE_SIGN(r); }
        !           232:   r->_mp_exp = rexp;
        !           233:
        !           234:   if (cc) {
        !           235:     mpn_rshift(rp, rp, rrsize, 1);
        !           236:     rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1);
        !           237:     r->_mp_exp++;
        !           238:   }
        !           239:
        !           240:   rsize = rrsize;
        !           241:   rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1;
        !           242:   MPN_COPY(r->_mp_d, rp + rsize - rrsize, rrsize);
        !           243:   MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB -
        !           244:                    (PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ;
        !           245:
        !           246:   TMP_FREE (marker);
        !           247: }

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