OLD | NEW |
| (Empty) |
1 /* mpn_preinv_divrem_1 -- mpn by limb division with pre-inverted divisor. | |
2 | |
3 THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST | |
4 CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN | |
5 FUTURE GNU MP RELEASES. | |
6 | |
7 Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. | |
8 | |
9 This file is part of the GNU MP Library. | |
10 | |
11 The GNU MP Library is free software; you can redistribute it and/or modify | |
12 it under the terms of the GNU Lesser General Public License as published by | |
13 the Free Software Foundation; either version 3 of the License, or (at your | |
14 option) any later version. | |
15 | |
16 The GNU MP Library is distributed in the hope that it will be useful, but | |
17 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
18 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |
19 License for more details. | |
20 | |
21 You should have received a copy of the GNU Lesser General Public License | |
22 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ | |
23 | |
24 #include "gmp.h" | |
25 #include "gmp-impl.h" | |
26 #include "longlong.h" | |
27 | |
28 | |
29 /* Don't bloat a shared library with unused code. */ | |
30 #if USE_PREINV_DIVREM_1 | |
31 | |
32 /* Same test here for skipping one divide step as in mpn_divrem_1. | |
33 | |
34 The main reason for a separate shift==0 case is that not all CPUs give | |
35 zero for "n0 >> BITS_PER_MP_LIMB" which would arise in the general case | |
36 code used on shift==0. shift==0 is also reasonably common in __mp_bases | |
37 big_base, for instance base==10 on a 64-bit limb. | |
38 | |
39 Under shift!=0 it would be possible to call mpn_lshift to adjust the | |
40 dividend all in one go (into the quotient space say), rather than | |
41 limb-by-limb in the loop. This might help if mpn_lshift is a lot faster | |
42 than what the compiler can generate for EXTRACT. But this is left to CPU | |
43 specific implementations to consider, especially since EXTRACT isn't on | |
44 the dependent chain. | |
45 | |
46 If size==0 then the result is simply xsize limbs of zeros, but nothing | |
47 special is done for that, since it wouldn't be a usual call, and | |
48 certainly never arises from mpn_get_str which is our main caller. */ | |
49 | |
50 mp_limb_t | |
51 mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t xsize, | |
52 mp_srcptr ap, mp_size_t size, mp_limb_t d_unnorm, | |
53 mp_limb_t dinv, int shift) | |
54 { | |
55 mp_limb_t ahigh, qhigh, r; | |
56 mp_size_t i; | |
57 mp_limb_t n1, n0; | |
58 mp_limb_t d; | |
59 | |
60 ASSERT (xsize >= 0); | |
61 ASSERT (size >= 1); | |
62 ASSERT (d_unnorm != 0); | |
63 #if WANT_ASSERT | |
64 { | |
65 int want_shift; | |
66 mp_limb_t want_dinv; | |
67 count_leading_zeros (want_shift, d_unnorm); | |
68 ASSERT (shift == want_shift); | |
69 invert_limb (want_dinv, d_unnorm << shift); | |
70 ASSERT (dinv == want_dinv); | |
71 } | |
72 #endif | |
73 /* FIXME: What's the correct overlap rule when xsize!=0? */ | |
74 ASSERT (MPN_SAME_OR_SEPARATE_P (qp+xsize, ap, size)); | |
75 | |
76 ahigh = ap[size-1]; | |
77 d = d_unnorm << shift; | |
78 qp += (size + xsize - 1); /* dest high limb */ | |
79 | |
80 if (shift == 0) | |
81 { | |
82 /* High quotient limb is 0 or 1, and skip a divide step. */ | |
83 r = ahigh; | |
84 qhigh = (r >= d); | |
85 r = (qhigh ? r-d : r); | |
86 *qp-- = qhigh; | |
87 size--; | |
88 | |
89 for (i = size-1; i >= 0; i--) | |
90 { | |
91 n0 = ap[i]; | |
92 udiv_qrnnd_preinv (*qp, r, r, n0, d, dinv); | |
93 qp--; | |
94 } | |
95 } | |
96 else | |
97 { | |
98 r = 0; | |
99 if (ahigh < d_unnorm) | |
100 { | |
101 r = ahigh << shift; | |
102 *qp-- = 0; | |
103 size--; | |
104 if (size == 0) | |
105 goto done_integer; | |
106 } | |
107 | |
108 n1 = ap[size-1]; | |
109 r |= n1 >> (BITS_PER_MP_LIMB - shift); | |
110 | |
111 for (i = size-2; i >= 0; i--) | |
112 { | |
113 ASSERT (r < d); | |
114 n0 = ap[i]; | |
115 udiv_qrnnd_preinv (*qp, r, r, | |
116 ((n1 << shift) | (n0 >> (BITS_PER_MP_LIMB - shift))
), | |
117 d, dinv); | |
118 qp--; | |
119 n1 = n0; | |
120 } | |
121 udiv_qrnnd_preinv (*qp, r, r, n1 << shift, d, dinv); | |
122 qp--; | |
123 } | |
124 | |
125 done_integer: | |
126 for (i = 0; i < xsize; i++) | |
127 { | |
128 udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv); | |
129 qp--; | |
130 } | |
131 | |
132 return r >> shift; | |
133 } | |
134 | |
135 #endif /* USE_PREINV_DIVREM_1 */ | |
OLD | NEW |