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

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

1.1     ! maekawa     1: /*  mpn_divrem_n -- Karatsuba division in 2*K(n) limb operations
        !             2:
        !             3: Copyright (C) 1999-2000 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: /*
        !            23: [1] Fast Recursive Division, by Christoph Burnikel and Joachim Ziegler,
        !            24:     Technical report MPI-I-98-1-022, october 1998,
        !            25:     cf http://www.mpi-sb.mpg.de/~ziegler/TechRep.ps.gz.
        !            26:     Implemented by Paul Zimmermann, 1999.
        !            27: */
        !            28:
        !            29: #include "gmp.h"
        !            30: #include "gmp-impl.h"
        !            31: #include "mpfr.h"
        !            32:
        !            33: extern void mpn_divrem_n2 (mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t, mp_limb_t *);
        !            34: extern void mpn_divrem_3by2 (mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t, mp_limb_t *);
        !            35:
        !            36: /* mpn_divrem_n(n) calls 2*mul(n/2)+2*div(n/2), thus to be faster then
        !            37:    div(n)=4*div(n/2), we need mul(n/2) to be faster than the classic way,
        !            38:    i.e. n/2 >= KARATSUBA_MUL_THRESHOLD */
        !            39:
        !            40: #define DIV_LIMIT (7*KARATSUBA_MUL_THRESHOLD)
        !            41:
        !            42: static void mpn_decr(mp_limb_t *Q)
        !            43: {
        !            44:   while ((*Q++)-- == 0);
        !            45: }
        !            46:
        !            47: /* implements algorithm of page 8 in [1]: divides (A,2n) by (B,n) and puts the
        !            48:    quotient in (Q,n), the remainder in (A,n).
        !            49:    Returns most significant limb of the quotient, which is 0 or 1.
        !            50: */
        !            51: mp_limb_t
        !            52: mpn_divrem_n(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B, mp_size_t n)
        !            53: {
        !            54:   if (n<DIV_LIMIT) return mpn_divrem(Q, 0, A, 2*n, B, n);
        !            55:   else {
        !            56:     mp_limb_t cc=0;
        !            57:     if (mpn_cmp(A+n, B, n)>=0) {
        !            58:       cc=1;
        !            59:       mpn_sub_n(A+n, A+n, B, n);
        !            60:     }
        !            61:     if (n%2) {
        !            62:        /* divide (2n-2) most significant limbs from A by those (n-1) from B */
        !            63:        mpn_divrem_n(Q+1, A+2, B+1, n-1);
        !            64:        /* now (Q+1, n-1) contains the quotient of (A+2,2n-2) by (B+1,n-1)
        !            65:          and (A+2, n-1) contains the remainder */
        !            66:        if (mpn_sub_1(A+n, A+n, 1, mpn_submul_1(A+1, Q+1, n-1, B[0]))) {
        !            67:         /* quotient two large */
        !            68:         mpn_decr(Q+1);
        !            69:         if (mpn_add_n(A+1, A+1, B, n)==0) {
        !            70:           mpn_decr(Q+1); mpn_add_n(A+1, A+1, B, n);
        !            71:         }
        !            72:        }
        !            73:        /* now divide (A,n+1) by (B,n) */
        !            74:        mpn_divrem(Q, 0, A, n+1, B, n);
        !            75:     }
        !            76:     else {
        !            77:        mp_limb_t *tmp; int n2=n/2;
        !            78:        TMP_DECL (marker);
        !            79:
        !            80:        TMP_MARK (marker);
        !            81:        tmp = (mp_limb_t*) TMP_ALLOC(n*sizeof(mp_limb_t));
        !            82:        mpn_divrem_3by2(Q+n2, A+n2, B, n2, tmp);
        !            83:        mpn_divrem_3by2(Q, A, B, n2, tmp);
        !            84:        TMP_FREE (marker);
        !            85:     }
        !            86:     return cc;
        !            87:   }
        !            88: }
        !            89:
        !            90: /* inner procedure, with no memory allocation
        !            91:    assumes mpn_cmp(A+n, B, n) < 0
        !            92: */
        !            93: void mpn_divrem_n2(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B, mp_size_t n,
        !            94:                        mp_limb_t *tmp)
        !            95: {
        !            96:   if (n%2) {
        !            97:     /* divide (2n-2) most significant limbs from A by those (n-1) from B */
        !            98:     mpn_divrem_n2(Q+1, A+2, B+1, n-1, tmp);
        !            99:     /* now (Q+1, n-1) contains the quotient of (A+2,2n-2) by (B+1,n-1)
        !           100:        and (A+2, n-1) contains the remainder */
        !           101:     if (mpn_sub_1(A+n, A+n, 1, mpn_submul_1(A+1, Q+1, n-1, B[0]))) {
        !           102:       /* quotient two large */
        !           103:       mpn_decr(Q+1);
        !           104:       if (mpn_add_n(A+1, A+1, B, n)==0) { /* still too large */
        !           105:        mpn_decr(Q+1); mpn_add_n(A+1, A+1, B, n);
        !           106:       }
        !           107:     }
        !           108:     /* now divide (A,n+1) by (B,n) */
        !           109:     mpn_divrem(Q, 0, A, n+1, B, n);
        !           110:   }
        !           111:   else {
        !           112:     int n2=n/2;
        !           113:     mpn_divrem_3by2(Q+n2, A+n2, B, n2, tmp);
        !           114:     mpn_divrem_3by2(Q, A, B, n2, tmp);
        !           115:   }
        !           116: }
        !           117:
        !           118: /* divides (A,3n) by (B,2n) and puts the quotient in (Q,n),
        !           119:    the remainder in (A,2n) */
        !           120: void
        !           121: mpn_divrem_3by2(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B,
        !           122:                             mp_size_t n, mp_limb_t *tmp)
        !           123: {
        !           124:   int twon = n+n;
        !           125:
        !           126:   if (n<DIV_LIMIT) mpn_divrem(Q, 0, A+n, twon, B+n, n);
        !           127:   else mpn_divrem_n2(Q, A+n, B+n, n, tmp);
        !           128:   /* q=(Q,n), c=(A+n,n) with the notations of [1] */
        !           129:   mpn_mul_n(tmp, Q, B, n);
        !           130:   if (mpn_sub_n(A, A, tmp, twon)) /* R=(A,2n) */ {
        !           131:     mpn_decr(Q);
        !           132:     if (mpn_add_n(A, A, B, twon)==0) { /* Q still too large */
        !           133:       mpn_decr(Q); mpn_add_n(A, A, B, twon);
        !           134:     }
        !           135:   }
        !           136:   return;
        !           137: }

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