File Coverage

rational.c
Criterion Covered Total %
statement 180 181 99.4
branch 112 142 78.8
condition n/a
subroutine n/a
pod n/a
total 292 323 90.4


line stmt bran cond sub pod time code
1             #include
2              
3             #include "ptypes.h"
4             #include "rational.h"
5             #define FUNC_gcd_ui 1
6             #include "util.h"
7             #include "totients.h"
8              
9              
10 351           int contfrac(UV** cfrac, UV *rem, UV num, UV den)
11             {
12             UV *cf;
13 351           int steps = 0;
14 351           New(0, cf, 2 * BITS_PER_WORD, UV); /* Upper limit for gcd steps */
15 1824 100         while (den > 0) {
16 1473           UV q = num/den;
17 1473           UV r = num - q*den;
18 1473           num = den;
19 1473           den = r;
20 1473           cf[steps++] = q;
21             }
22 351           *rem = num;
23 351           *cfrac = cf;
24 351           return steps;
25             }
26              
27 99           bool next_calkin_wilf(UV* num, UV* den)
28             {
29             UV n, d;
30 99 50         if (num == 0 || den == 0) return 0;
    50          
31 99           n = *num;
32 99           d = *den;
33 99 50         if (n == 0 || d == 0 || gcd_ui(n,d) != 1) return 0;
    50          
    50          
34              
35             /* next = d / (n+d-2*(n%d)) = d / (2(n/d)+1)*d-n */
36 99 100         if (n < d) { /* n/d is 0 */
37 49           *den = d-n;
38 50 100         } else if (d == 1) {
39 6 50         if (n == UV_MAX) return 0;
40 6           *den = n + 1;
41             } else { /* n >= d and d >= 2 */
42 44           UV nd = n % d; /* nd is less than d and less than n */
43 44           UV nr = n-nd, dr = d-nd;
44 44 50         if (nr > UV_MAX-dr) return 0;
45 44           *den = nr + dr;
46             }
47 99           *num = d;
48 99           return 1;
49             }
50 99           bool next_stern_brocot(UV* num, UV* den)
51             {
52             UV n, d;
53 99 50         if (num == 0 || den == 0) return 0;
    50          
54 99           n = *num;
55 99           d = *den;
56 99 50         if (n == 0 || d == 0 || gcd_ui(n,d) != 1) return 0;
    50          
    50          
57              
58             /* Backhouse and Ferreira show how to do this *if* we had a 2x2 matrix
59             * for the node. We could also exploit that given a/b and the next c/d
60             * bc-ad=3 if they share a parent
61             * but this doesn't give us enough information to solve for both c,d.
62             */
63              
64 99 100         if (*den == 1) { /* At end of the row, go to the start of the next. */
65 6 50         if (*num == UV_MAX) return 0;
66 6           *den = *num+1;
67 6           *num = 1;
68 6           return 1;
69             }
70             /* Given the tree e.g. LLLRRLLRR, we can go up to the nearest ancestor,
71             * then back down. That is, from the right, invert all L/R from the end
72             * to and including the right L. This really isn't a huge savings over
73             * doing the full process. Doing nth(n(F)+1) is clean. */
74 93           return nth_stern_brocot(num, den, 1+stern_brocot_n(*num, *den));
75             }
76              
77              
78             #if 0 /* A recursive version */
79             UV calkin_wilf_n(UV num, UV den)
80             {
81             if (num == den) {
82             return 1;
83             } else if (num > den) {
84             UV f = calkin_wilf_n(num-den, num);
85             if (f == 0 || f == UV_MAX) return 0;
86             return 1 + f;
87             } else {
88             UV f = calkin_wilf_n(num, den-num);
89             if (f == 0 || f > (UV_MAX/2)) return 0;
90             return 2 * f;
91             }
92             }
93             #endif
94              
95 313           UV calkin_wilf_n(UV num, UV den)
96             {
97 313           UV *cf = 0, n = 0, rem;
98 313           uint32_t bit, d = 1, shift = 0;
99 313           int i, steps = contfrac(&cf, &rem, num, den);
100              
101 313 50         if (rem != 1) croak("Rational must be reduced");
102 313 50         if (steps == 0) return 0;
103              
104 313           cf[steps-1]--;
105 1494 100         for (i = 0; i < steps; i++) {
106 1187 100         if ((shift+cf[i]) >= BITS_PER_WORD)
107 6           break;
108 1181 100         if (d)
109 1606 100         for (bit = 0; bit < cf[i]; bit++)
110 944           n |= UVCONST(1) << (shift+bit);
111 1181           shift += cf[i];
112 1181           d ^= 1; /* d = 1-d; */
113             }
114 313           Safefree(cf);
115 313 100         if (i < steps) return 0;
116 307           n |= UVCONST(1) << shift;
117 307           return n;
118             }
119 203           UV stern_brocot_n(UV num, UV den)
120             {
121             /* Reverse bits in the Calkin-Wilf n */
122 203           UV n, M = calkin_wilf_n(num,den);
123 203 100         if (M == 0) return 0;
124 1294 100         for (n = 1; M > 1; M >>= 1)
125 1094           n = (n << 1) | (M & 1);
126 200           return n;
127             }
128              
129              
130 107           bool nth_calkin_wilf(UV* num, UV* den, UV n)
131             {
132 107           uint32_t b = 1;
133 107           UV p = 0, q = 1; /* p odd q even */
134 742 100         { UV v = n; while (v >>= 1) b++; }
135 849 100         while (b--) {
136 742 100         if ((n >> b) & 1) p += q;
137 292           else q += p;
138             }
139 107           *num = p;
140 107           *den = q;
141 107           return 1;
142             }
143 200           bool nth_stern_brocot(UV* num, UV* den, UV n)
144             {
145 200           UV p = 1, q = 1; /* p odd q even */
146 1294 100         while (n > 1) {
147 1094 100         if (n & 1) p += q;
148 532           else q += p;
149 1094           n >>= 1;
150             }
151 200           *num = p;
152 200           *den = q;
153 200           return 1;
154             }
155              
156 340           UV nth_stern_diatomic(UV n)
157             {
158 340           UV p = 0, q = 1;
159 2455 100         while (n) {
160 2115 100         if (n & 1) p += q;
161 983           else q += p;
162 2115           n >>= 1;
163             }
164 340           return p;
165             }
166              
167              
168              
169 34           UV farey_length(uint32_t n)
170             {
171 34           UV t = sumtotient(n);
172 34 50         return (t == 0) ? 0 : 1 + sumtotient(n);
173             }
174              
175 939           bool next_farey(uint32_t n, uint32_t* p, uint32_t* q)
176             {
177             IV ivu, ivg;
178             UV u, uvp, uvq;
179              
180 939 50         if (n == 0 || p == 0 || q == 0 || *p >= *q) return 0;
    50          
    50          
    50          
181              
182 939           ivg = gcdext( (IV)*p, (IV)*q, &ivu, 0, 0, 0);
183              
184 939           u = ivu;
185 939           uvp = *p / ivg;
186 939           uvq = *q / ivg;
187              
188 939           *q = ((n+u) / uvq) * uvq - u;
189 939           *p = (*q * uvp + 1) / uvq;
190 939           return 1;
191             }
192              
193 10           UV farey_array(uint32_t n, uint32_t **rnum, uint32_t **rden)
194             {
195             uint32_t *num, *den;
196 10           UV i, j, p0 = 0, q0 = 1, p1 = 1, q1 = n, p2, q2;
197 10           UV len = farey_length(n);
198              
199 10 50         if (n < 1 || len < 2 || len >= UVCONST(4294967295))
    50          
    50          
200 0           return 0;
201              
202 10 50         New(0, num, len, uint32_t);
203 10 50         New(0, den, len, uint32_t);
204              
205 124 100         for (i = 0; i < len; i++) {
206 114           num[i] = p0;
207 114           den[i] = q0;
208             /* Haros (1802), gives p/q using two previous terms */
209 114           j = (q0 + n) / q1;
210 114           p2 = j * p1 - p0;
211 114           q2 = j * q1 - q0;
212 114           p0 = p1; q0 = q1; p1 = p2; q1 = q2;
213             }
214 10           *rnum = num;
215 10           *rden = den;
216 10           return len;
217             }
218              
219              
220              
221             /*
222             * See:
223             * Pătraşcu and Pătraşcu (ANTS 2004)
224             * https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=d8882e782674d5cd312129823287768e123674e1
225             *
226             * Pawlewicz (2007)
227             * https://www.mimuw.edu.pl/~pan/papers/farey-esa.pdf
228             *
229             * Pawlewicz and Pătraşcu (2008)
230             * https://www.researchgate.net/publication/225715205_Order_Statistics_in_the_Farey_Sequences_in_Sublinear_Time_and_Counting_Primitive_Lattice_Points_in_Polygons
231             *
232             * For the rank, we're using a very simple but fast version.
233             * TODO: Use the method from Pawlewicz 2007 (see page 7).
234             *
235             * For the kth member, binary search on rank.
236             */
237              
238 346           UV farey_rank(uint32_t n, uint32_t p, uint32_t q)
239             {
240             uint32_t *count, i, g;
241             UV sum;
242              
243 346 50         if (n == 0 || q == 0 || p == 0) return 0;
    50          
    100          
244              
245 335           g = gcd_ui(p,q);
246 335 100         if (g != 1) { p /= g; q /= g; }
247              
248 335           New(0, count, n+1, uint32_t);
249              
250 8777 100         for (i = 2; i <= n; i++)
251 8442           count[i] = ((UV)i * p - 1) / q;
252 335           sum = 1;
253 8777 100         for (i = 2; i <= n; i++) {
254 8442           uint32_t j, icount = count[i];
255 36831 100         for (j = i; j <= n-i; j += i)
256 28389           count[j+i] -= icount;
257 8442           sum += icount;
258             }
259 335           Safefree(count);
260 335           return sum;
261             }
262              
263              
264             #if 0 /* Naive method. */
265             int kth_farey(uint32_t n, UV k, uint32_t* p, uint32_t* q)
266             {
267             UV i, j, p0 = 0, q0 = 1, p1 = 1, q1 = n, p2, q2;
268             UV len = farey_length(n);
269              
270             if (n > 0 && len < 2) return -1; /* overflow */
271             if (n == 0 || k >= len) return 0; /* undefined */
272              
273             if (k > len/2) { /* Exploit symmetry about 1/2, iterate backwards */
274             p0 = 1;
275             p1 = n-1;
276             k = (len-1)-k;
277             }
278             for (i = 0; i < k; i++) {
279             j = (q0 + n) / q1;
280             p2 = j * p1 - p0;
281             q2 = j * q1 - q0;
282             p0 = p1; q0 = q1; p1 = p2; q1 = q2;
283             }
284             *p = p0; *q = q0;
285             return 1;
286             }
287             #else
288 90           static bool _walk_to_k(uint32_t a, uint32_t n, uint32_t k, uint32_t* p, uint32_t* q)
289             {
290             uint32_t g, j, p0, q0, p1, q1, p2, q2;
291              
292 90           g = gcd_ui(a,n);
293 90           p0 = a/g;
294 90           q0 = n/g;
295              
296 90 100         if (k == 0) { *p = p0; *q = q0; return 1; }
297              
298             /* From the single point, use extgcd to get the exact next fraction */
299 62           p1 = p0; q1 = q0;
300 62           next_farey(n, &p1, &q1);
301              
302             /* Now we have two fractions, so quick step through */
303 145 100         while (--k) {
304 83           j = (q0 + n) / q1;
305 83           p2 = j * p1 - p0;
306 83           q2 = j * q1 - q0;
307 83           p0 = p1; p1 = p2; q0 = q1; q1 = q2;
308             }
309 62           *p = p1;
310 62           *q = q1;
311 62           return 1;
312             }
313 128           bool kth_farey(uint32_t n, UV k, uint32_t* p, uint32_t* q)
314             {
315 128           uint32_t lo = 1, hi = n;
316 128           UV cnt = 1;
317              
318 128 100         if (k < 2) {
319 20 100         if (k == 0) { *p = 0; *q = 1; }
320 10           else { *p = 1; *q = n; }
321 20           return 1;
322             }
323 108 100         if (n < 2) return 0;
324              
325             /* For a substantial performance benefit, we will estimate the position
326             * and get its rank. Then look a small distance in the other direction.
327             * For small n this often completely brackets the value after only one
328             * or two calls. For large n, we can often do 2-5 times fewer calls.
329             *
330             * The downside is this is ugly, but it makes this call 2-4x faster.
331             */
332 107 100         if (n >= 5) {
333 95           uint32_t const ginc = ((UV)n+8191)>>13;
334 95           double const dlen = 1 + (0.304*(double)n*n + .29*(double)n + 0.95);
335 95           uint32_t guess = k * ((double)n/dlen);
336 95           UV gcnt = 0;
337 95 100         if (guess <= lo) guess = lo+1; else if (guess >= hi) guess = hi-1;
    100          
338              
339 95 50         if (lo < hi) {
340 95           gcnt = farey_rank(n, guess, n);
341 95 100         if (gcnt <= k) { lo = guess; cnt = gcnt; } else { hi = guess-1; }
342             }
343              
344             /* Look a small distance in the other direction. We want it to be
345             * far enough that we bracket the value, but not so far that we make
346             * too many calls getting back. */
347 95 100         if (gcnt <= k) { guess = (hi-ginc < guess) ? hi : guess+ginc; }
    50          
348 15 100         else { guess = (lo+ginc+1 > guess) ? lo : guess-1-ginc; }
349              
350 95 100         if (lo < hi && guess > lo && guess < hi) {
    50          
    100          
351 67           gcnt = farey_rank(n,guess,n);
352 67 100         if (gcnt <= k) { lo = guess; cnt = gcnt; } else { hi = guess-1; }
353             }
354             }
355              
356             /* Now the binary search. */
357              
358 181 100         while (lo < hi) {
359 74           uint32_t mid = lo + ((hi-lo+1)>>1);
360 74           UV midcnt = farey_rank(n, mid, n);
361 74 100         if (midcnt <= k) { lo = mid; cnt = midcnt; }
362 48           else { hi = mid-1; }
363             }
364 107 100         if (lo == n) {
365 17           *p = (cnt == k);
366 17           *q = 1;
367 17           return k <= cnt;
368             }
369 90           return _walk_to_k(lo, n, k-cnt, p, q);
370             }
371             #endif