Annotation of OpenXM_contrib/gmp/mpfr/karadiv.c, Revision 1.1.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>