Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

28495 views
License: GPL3
ubuntu2004
1
#line 2 "../src/kernel/none/ratlift.c"
2
/* Copyright (C) 2003 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
/*==========================================================
17
* Fp_ratlift(GEN x, GEN m, GEN *a, GEN *b, GEN amax, GEN bmax)
18
*==========================================================
19
* Reconstruct rational number from its residue x mod m
20
* Given t_INT x, m, amax>=0, bmax>0 such that
21
* 0 <= x < m; 2*amax*bmax < m
22
* attempts to find t_INT a, b such that
23
* (1) a = b*x (mod m)
24
* (2) |a| <= amax, 0 < b <= bmax
25
* (3) gcd(m, b) = gcd(a, b)
26
* If unsuccessful, it will return 0 and leave a,b unchanged (and
27
* caller may deduce no such a,b exist). If successful, sets a,b
28
* and returns 1. If there exist a,b satisfying (1), (2), and
29
* (3') gcd(m, b) = 1
30
* then they are uniquely determined subject to (1),(2) and
31
* (3'') gcd(a, b) = 1,
32
* and will be returned by the routine. (The caller may wish to
33
* check gcd(a,b)==1, either directly or based on known prime
34
* divisors of m, depending on the application.)
35
* Reference:
36
@article {MR97c:11116,
37
AUTHOR = {Collins, George E. and Encarnaci{\'o}n, Mark J.},
38
TITLE = {Efficient rational number reconstruction},
39
JOURNAL = {J. Symbolic Comput.},
40
VOLUME = {20},
41
YEAR = {1995},
42
NUMBER = {3},
43
PAGES = {287--297},
44
}
45
* Preprint available from:
46
* ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1994/94-64.ps.gz */
47
static ulong
48
get_vmax(GEN r, long lb, long lbb)
49
{
50
long lr = lb - lgefint(r);
51
ulong vmax;
52
if (lr > 1) /* still more than a word's worth to go */
53
vmax = ULONG_MAX; /* (cannot in fact happen) */
54
else
55
{ /* take difference of bit lengths */
56
long lbr = bfffo(*int_MSW(r));
57
lr = lr*BITS_IN_LONG - lbb + lbr;
58
if ((ulong)lr > BITS_IN_LONG)
59
vmax = ULONG_MAX;
60
else if (lr == 0)
61
vmax = 1UL;
62
else
63
vmax = 1UL << (lr-1); /* pessimistic but faster than a division */
64
}
65
return vmax;
66
}
67
68
/* Assume x,m,amax >= 0,bmax > 0 are t_INTs, 0 <= x < m, 2 amax * bmax < m */
69
int
70
Fp_ratlift(GEN x, GEN m, GEN amax, GEN bmax, GEN *a, GEN *b)
71
{
72
GEN d, d1, v, v1, q, r;
73
pari_sp av = avma, av1;
74
long lb, lbb, s, s0;
75
ulong vmax;
76
ulong xu, xu1, xv, xv1; /* Lehmer stage recurrence matrix */
77
int lhmres; /* Lehmer stage return value */
78
79
/* special cases x=0 and/or amax=0 */
80
if (!signe(x)) { *a = gen_0; *b = gen_1; return 1; }
81
if (!signe(amax)) return 0;
82
/* assert: m > x > 0, amax > 0 */
83
84
/* check whether a=x, b=1 is a solution */
85
if (cmpii(x,amax) <= 0) { *a = icopy(x); *b = gen_1; return 1; }
86
87
/* There is no special case for single-word numbers since this is
88
* mainly meant to be used with large moduli. */
89
(void)new_chunk(lgefint(bmax) + lgefint(amax)); /* room for a,b */
90
d = m; d1 = x;
91
v = gen_0; v1 = gen_1;
92
/* assert d1 > amax, v1 <= bmax here */
93
lb = lgefint(bmax);
94
lbb = bfffo(*int_MSW(bmax));
95
s = 1;
96
av1 = avma;
97
98
/* General case: Euclidean division chain starting with m div x, and
99
* with bounds on the sequence of convergents' denoms v_j.
100
* Just to be different from what invmod and bezout are doing, we work
101
* here with the all-nonnegative matrices [u,u1;v,v1]=prod_j([0,1;1,q_j]).
102
* Loop invariants:
103
* (a) (sign)*[-v,v1]*x = [d,d1] (mod m) (componentwise)
104
* (sign initially +1, changes with each Euclidean step)
105
* so [a,b] will be obtained in the form [-+d,v] or [+-d1,v1];
106
* this congruence is a consequence of
107
*
108
* (b) [x,m]~ = [u,u1;v,v1]*[d1,d]~,
109
* where u,u1 is the usual numerator sequence starting with 1,0
110
* instead of 0,1 (just multiply the eqn on the left by the inverse
111
* matrix, which is det*[v1,-u1;-v,u], where "det" is the same as the
112
* "(sign)" in (a)). From m = v*d1 + v1*d and
113
*
114
* (c) d > d1 >= 0, 0 <= v < v1,
115
* we have d >= m/(2*v1), so while v1 remains smaller than m/(2*amax),
116
* the pair [-(sign)*d,v] satisfies (1) but violates (2) (d > amax).
117
* Conversely, v1 > bmax indicates that no further solutions will be
118
* forthcoming; [-(sign)*d,v] will be the last, and first, candidate.
119
* Thus there's at most one point in the chain division where a solution
120
* can live: v < bmax, v1 >= m/(2*amax) > bmax, and this is acceptable
121
* iff in fact d <= amax (e.g. m=221, x=34 or 35, amax=bmax=10 fail on
122
* this count while x=32,33,36,37 succeed). However, a division may leave
123
* a zero residue before we ever reach this point (consider m=210, x=35,
124
* amax=bmax=10), and our caller may find that gcd(d,v) > 1 (Examples:
125
* keep m=210 and consider any of x=29,31,32,33,34,36,37,38,39,40,41).
126
* Furthermore, at the start of the loop body we have in fact
127
*
128
* (c') 0 <= v < v1 <= bmax, d > d1 > amax >= 0,
129
* (and are never done already).
130
*
131
* Main loop is similar to those of invmod() and bezout(), except for
132
* having to determine appropriate vmax bounds, and checking termination
133
* conditions. The signe(d1) condition is only for paranoia */
134
while (lgefint(d) > 3 && signe(d1))
135
{
136
/* determine vmax for lgcdii so as to ensure v won't overshoot.
137
* If v+v1 > bmax, the next step would take v1 beyond the limit, so
138
* since [+-d1,v1] is not a solution, we give up. Otherwise if v+v1
139
* is way shorter than bmax, use vmax=MAXULUNG. Otherwise, set vmax
140
* to a crude lower approximation of bmax/(v+v1), or to 1, which will
141
* allow the inner loop to do one step */
142
r = addii(v,v1);
143
if (cmpii(r,bmax) > 0) return gc_long(av, 0); /* done, not found */
144
vmax = get_vmax(r, lb, lbb);
145
/* do a Lehmer-Jebelean round */
146
lhmres = lgcdii((ulong *)d, (ulong *)d1, &xu, &xu1, &xv, &xv1, vmax);
147
if (lhmres) /* check progress */
148
{ /* apply matrix */
149
if (lhmres == 1 || lhmres == -1)
150
{
151
s = -s;
152
if (xv1 == 1)
153
{ /* re-use v+v1 computed above */
154
v = v1; v1 = r;
155
r = subii(d,d1); d = d1; d1 = r;
156
}
157
else
158
{
159
r = subii(d, mului(xv1,d1)); d = d1; d1 = r;
160
r = addii(v, mului(xv1,v1)); v = v1; v1 = r;
161
}
162
}
163
else
164
{
165
r = subii(muliu(d,xu), muliu(d1,xv));
166
d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r;
167
r = addii(muliu(v,xu), muliu(v1,xv));
168
v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r;
169
if (lhmres&1) { togglesign(d); s = -s; } else togglesign(d1);
170
}
171
/* check whether we're done. Assert v <= bmax here. Examine v1:
172
* if v1 > bmax, check d and return 0 or 1 depending on the outcome;
173
* if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise proceed*/
174
if (cmpii(v1,bmax) > 0)
175
{
176
set_avma(av);
177
if (cmpii(d,amax) > 0) return 0; /* done, not found */
178
/* done, found */
179
*a = icopy(d); setsigne(*a,-s);
180
*b = icopy(v); return 1;
181
}
182
if (cmpii(d1,amax) <= 0)
183
{ /* done, found */
184
set_avma(av);
185
if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0;
186
*b = icopy(v1); return 1;
187
}
188
} /* lhmres != 0 */
189
190
if (lhmres <= 0 && signe(d1))
191
{
192
q = dvmdii(d,d1,&r);
193
d = d1; d1 = r;
194
r = addii(v, mulii(q,v1));
195
v = v1; v1 = r;
196
s = -s;
197
/* check whether we are done now. Since we weren't before the div, it
198
* suffices to examine v1 and d1 -- the new d (former d1) cannot cut it */
199
if (cmpii(v1,bmax) > 0) return gc_long(av, 0); /* done, not found */
200
if (cmpii(d1,amax) <= 0) /* done, found */
201
{
202
set_avma(av);
203
if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0;
204
*b = icopy(v1); return 1;
205
}
206
}
207
208
if (gc_needed(av,1))
209
{
210
if(DEBUGMEM>1) pari_warn(warnmem,"ratlift");
211
gerepileall(av1, 4, &d, &d1, &v, &v1);
212
}
213
} /* end while */
214
215
/* Postprocessing - final sprint. Since we usually underestimate vmax,
216
* this function needs a loop here instead of a simple conditional.
217
* Note we can only get here when amax fits into one word (which will
218
* typically not be the case!). The condition is bogus -- d1 is never
219
* zero at the start of the loop. There will be at most a few iterations,
220
* so we don't bother collecting garbage */
221
while (signe(d1))
222
{
223
/* Assertions: lgefint(d)==lgefint(d1)==3.
224
* Moreover, we aren't done already, or we would have returned by now.
225
* Recompute vmax */
226
r = addii(v,v1);
227
if (cmpii(r,bmax) > 0) return gc_long(av, 0); /* done, not found */
228
vmax = get_vmax(r, lb, lbb);
229
/* single-word "Lehmer", discarding the gcd or whatever it returns */
230
(void)rgcduu((ulong)*int_MSW(d), (ulong)*int_MSW(d1), vmax, &xu, &xu1, &xv, &xv1, &s0);
231
if (xv1 == 1) /* avoid multiplications */
232
{ /* re-use r = v+v1 computed above */
233
v = v1; v1 = r;
234
r = subii(d,d1); d = d1; d1 = r;
235
s = -s;
236
}
237
else if (xu == 0) /* and xv==1, xu1==1, xv1 > 1 */
238
{
239
r = subii(d, mului(xv1,d1)); d = d1; d1 = r;
240
r = addii(v, mului(xv1,v1)); v = v1; v1 = r;
241
s = -s;
242
}
243
else
244
{
245
r = subii(muliu(d,xu), muliu(d1,xv));
246
d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r;
247
r = addii(muliu(v,xu), muliu(v1,xv));
248
v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r;
249
if (s0 < 0) { togglesign(d); s = -s; } else togglesign(d1);
250
}
251
/* check whether we're done, as above. Assert v <= bmax.
252
* if v1 > bmax, check d and return 0 or 1 depending on the outcome;
253
* if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise proceed.
254
*/
255
if (cmpii(v1,bmax) > 0)
256
{
257
set_avma(av);
258
if (cmpii(d,amax) > 0) return 0; /* done, not found */
259
/* done, found */
260
*a = icopy(d); setsigne(*a,-s);
261
*b = icopy(v); return 1;
262
}
263
if (cmpii(d1,amax) <= 0)
264
{ /* done, found */
265
set_avma(av);
266
if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0;
267
*b = icopy(v1); return 1;
268
}
269
} /* while */
270
271
/* We have run into d1 == 0 before returning. This cannot happen */
272
pari_err_BUG("ratlift failed to catch d1 == 0");
273
return 0; /* LCOV_EXCL_LINE */
274
}
275
276