Line data Source code
1 : #line 2 "../src/kernel/none/divll_pre.h"
2 : /* Copyright (C) 2014 The PARI group.
3 :
4 : This file is part of the PARI/GP package.
5 :
6 : PARI/GP is free software; you can redistribute it and/or modify it under the
7 : terms of the GNU General Public License as published by the Free Software
8 : Foundation; either version 2 of the License, or (at your option) any later
9 : version. It is distributed in the hope that it will be useful, but WITHOUT
10 : ANY WARRANTY WHATSOEVER.
11 :
12 : Check the License for details. You should have received a copy of it, along
13 : with the package; see the file 'COPYING'. If not, write to the Free Software
14 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
15 :
16 : #undef LOCAL_HIREMAINDER
17 : extern ulong hiremainder;
18 : #if defined(INLINE) && defined(__GNUC__) && !defined(DISABLE_INLINE)
19 : #define LOCAL_HIREMAINDER ulong hiremainder
20 : #else
21 : #define LOCAL_HIREMAINDER
22 : #endif
23 :
24 : #if defined(INLINE) && defined(__GNUC__) && !defined(DISABLE_INLINE)
25 : INLINE ulong /* precompute inverse of n */
26 1386702052 : get_Fl_red(ulong n)
27 : {
28 : LOCAL_HIREMAINDER;
29 1386702052 : n <<= bfffo(n);
30 1386702052 : hiremainder = ~n;
31 1386702052 : return divll(~0UL, n);
32 : }
33 : #else
34 : INLINE ulong /* precompute inverse of n */
35 414384232 : get_Fl_red(ulong n)
36 : {
37 414384232 : ulong q, oldhi = hiremainder;
38 414384232 : n <<= bfffo(n);
39 414384232 : hiremainder = ~n;
40 414384232 : q = divll(~0UL, n);
41 414384232 : hiremainder = oldhi;
42 414384232 : return q;
43 : }
44 : #endif
45 :
46 : INLINE ulong /* requires u1 <= n, n normalised */
47 10647458361 : divll_pre_normalized(ulong u1, ulong u0, ulong n, ulong ninv, ulong *pt_r)
48 : {
49 : ulong q0, q1, r;
50 : LOCAL_HIREMAINDER;
51 : LOCAL_OVERFLOW;
52 10647458361 : q0 = mulll(ninv, u1); q1 = hiremainder;
53 10647458361 : q0 = addll(q0, u0);
54 10647458361 : q1 = addllx(q1+1, u1);
55 10647458361 : r = u0 - q1 * n;
56 10647458361 : if (r > q0)
57 : {
58 7263507440 : r += n; q1--;
59 : }
60 10647458361 : if (r >= n)
61 : {
62 22079004 : r -= n; q1++;
63 : }
64 10647458361 : *pt_r = r; return q1;
65 : }
66 :
67 : INLINE ulong /* requires u1 <= n, n normalised */
68 14311880102 : remll_pre_normalized(ulong u1, ulong u0, ulong n, ulong ninv)
69 : {
70 : ulong q0, q1, r;
71 : LOCAL_HIREMAINDER;
72 : LOCAL_OVERFLOW;
73 14311880102 : q0 = mulll(ninv, u1); q1 = hiremainder;
74 14311880102 : q0 = addll(q0, u0);
75 14311880102 : q1 = addllx(q1, u1);
76 14311880102 : r = u0 - (q1 + 1) * n;
77 14311880102 : if (r >= q0)
78 10121873615 : r += n;
79 14311880102 : return r < n ? r : r - n;
80 : }
81 :
82 : INLINE ulong /* reduce <a_hi, a_lo> mod n */
83 14238295751 : remll_pre(ulong a_hi, ulong a_lo, ulong n, ulong ninv)
84 : {
85 14238295751 : int norm = bfffo(n);
86 14238295751 : int bits = BITS_IN_LONG - norm;
87 14238295751 : ulong sn = n << norm;
88 14238295751 : if (a_hi >= n) /* reduce a_hi first */
89 : {
90 71063375 : const ulong u1 = norm ? a_hi >> bits : 0;
91 71063375 : const ulong u0 = a_hi << norm;
92 71063375 : a_hi = remll_pre_normalized(u1, u0, sn, ninv) >> norm;
93 : }
94 : /* now reduce <a_hi, a_lo> */
95 : {
96 14238313898 : const ulong u1 = ((a_hi << norm) | (norm ? a_lo >> bits: 0));
97 14238313898 : const ulong u0 = a_lo << norm;
98 14238313898 : return remll_pre_normalized(u1, u0, sn, ninv) >> norm;
99 : }
100 : }
101 :
102 : #if !defined(INLINE)
103 : extern ulong divll_pre(ulong a_lo, ulong n, ulong ninv);
104 : #else
105 :
106 : #if defined(__GNUC__) && !defined(DISABLE_INLINE)
107 : #define divll_pre(a, n, ninv) \
108 : __extension__ ({ \
109 : ulong __a = (a); \
110 : ulong __n = (n); \
111 : int norm = bfffo(__n); \
112 : int bits = BITS_IN_LONG - norm; \
113 : ulong r, sn = __n << norm; \
114 : const ulong u1 = ((hiremainder << norm) | (norm ? __a >> bits: 0)); \
115 : const ulong u0 = __a << norm; \
116 : const ulong q = divll_pre_normalized(u1, u0, sn, ninv, &r); \
117 : hiremainder = r>>norm; q; \
118 : })
119 :
120 : #else /* __GNUC__ */
121 : INLINE ulong
122 2084260809 : divll_pre(ulong a_lo, ulong n, ulong ninv)
123 : {
124 2084260809 : int norm = bfffo(n);
125 2084260809 : int bits = BITS_IN_LONG - norm;
126 2084260809 : ulong r, sn = n << norm;
127 2084260809 : const ulong u1 = ((hiremainder << norm) | (norm ? a_lo >> bits: 0));
128 2084260809 : const ulong u0 = a_lo << norm;
129 2084260809 : const ulong q = divll_pre_normalized(u1, u0, sn, ninv, &r);
130 2084260809 : hiremainder = r>>norm; return q;
131 : }
132 : #endif /* __GNUC__ */
133 :
134 : #endif
|