6 // Minds our p's and q's. The two last computed convergents,
7 // and room to compute the next one.
12 typedef struct pqset_s
*pqset_ptr
;
13 typedef struct pqset_s pqset_t
[1];
15 void pqset_init(pqset_t pq
) {
24 void pqset_clear(pqset_t pq
) {
33 void pqset_print(pqset_t pq
) {
34 gmp_printf("p's: %Zd %Zd %Zd\n", pq
->pold
, pq
->p
, pq
->pnew
);
35 gmp_printf("q's: %Zd %Zd %Zd\n", pq
->qold
, pq
->q
, pq
->qnew
);
38 // Compute the next convergent for regular continued fractions.
39 void pqset_regular_recur(pqset_t pq
, mpz_t denom
) {
40 mpz_addmul(pq
->pold
, denom
, pq
->p
);
41 mpz_swap(pq
->pold
, pq
->p
);
42 mpz_addmul(pq
->qold
, denom
, pq
->q
);
43 mpz_swap(pq
->qold
, pq
->q
);
46 // Compute the next convergent for nonregular continued fractions.
47 void pqset_nonregular_recur(pqset_t pq
, mpz_t num
, mpz_t denom
) {
48 mpz_mul(pq
->pnew
, pq
->p
, denom
);
49 mpz_addmul(pq
->pnew
, pq
->pold
, num
);
50 mpz_mul(pq
->qnew
, pq
->q
, denom
);
51 mpz_addmul(pq
->qnew
, pq
->qold
, num
);
54 // Use pold, qold as temporary variables.
55 // Get rid of nontrivial GCD for {p, q, pnew, qnew}.
56 void pqset_remove_gcd(pqset_ptr pq
) {
57 mpz_gcd(pq
->pold
, pq
->pnew
, pq
->qnew
);
58 mpz_gcd(pq
->qold
, pq
->p
, pq
->q
);
59 mpz_gcd(pq
->pold
, pq
->pold
, pq
->qold
);
60 if (mpz_cmp_ui(pq
->pold
, 1)) {
61 mpz_divexact(pq
->pnew
, pq
->pnew
, pq
->pold
);
62 mpz_divexact(pq
->qnew
, pq
->qnew
, pq
->pold
);
63 mpz_divexact(pq
->p
, pq
->p
, pq
->pold
);
64 mpz_divexact(pq
->q
, pq
->q
, pq
->pold
);
68 void pqset_next(pqset_ptr pq
) {
69 mpz_set(pq
->pold
, pq
->p
); mpz_set(pq
->p
, pq
->pnew
);
70 mpz_set(pq
->qold
, pq
->q
); mpz_set(pq
->q
, pq
->qnew
);
73 // A Mobius transformation: four coefficients and the input.
74 // TODO: Use an array of size 4.
75 struct mobius_data_s
{
79 typedef struct mobius_data_s
*mobius_data_ptr
;
81 void pqset_set_mobius(pqset_t pq
, mobius_data_ptr md
) {
82 mpz_set(pq
->pold
, md
->b
); mpz_set(pq
->p
, md
->a
);
83 mpz_set(pq
->qold
, md
->d
); mpz_set(pq
->q
, md
->c
);
86 // Compute convergents of Mobius function applied to a regular
87 // continued fraction.
88 static void *mobius_convergent(cf_t cf
) {
89 mobius_data_ptr md
= cf_data(cf
);
90 cf_t input
= md
->input
;
93 pqset_set_mobius(pq
, md
);
99 pqset_regular_recur(pq
, denom
);
114 // Start a thread that, when signalled, computes the convergents of a Mobius
115 // transformation of a continued fraction.
116 cf_t
cf_new_mobius_convergent(cf_t x
, mpz_t a
, mpz_t b
, mpz_t c
, mpz_t d
) {
117 mobius_data_ptr md
= malloc(sizeof(*md
));
118 mpz_init(md
->a
); mpz_init(md
->b
); mpz_init(md
->c
); mpz_init(md
->d
);
119 mpz_set(md
->a
, a
); mpz_set(md
->b
, b
); mpz_set(md
->c
, c
); mpz_set(md
->d
, d
);
121 return cf_new(mobius_convergent
, md
);
124 // Start a thread that, when signalled, computes the convergents of a continued
126 cf_t
cf_new_convergent(cf_t x
) {
128 mpz_init(one
); mpz_init(zero
);
129 mpz_set_ui(one
, 1); mpz_set_ui(zero
, 0);
130 cf_t res
= cf_new_mobius_convergent(x
, one
, zero
, zero
, one
);
131 mpz_clear(one
); mpz_clear(zero
);
135 // Compute convergents of Mobius function applied to a nonregular
136 // continued fraction.
137 static void *nonregular_mobius_convergent(cf_t cf
) {
138 mobius_data_ptr md
= cf_data(cf
);
139 cf_t input
= md
->input
;
140 pqset_t pq
; pqset_init(pq
); pqset_set_mobius(pq
, md
);
141 mpz_t num
; mpz_init(num
);
142 mpz_t denom
; mpz_init(denom
);
144 pqset_nonregular_recur(pq
, num
, denom
);
145 pqset_remove_gcd(pq
);
147 cf_put(cf
, pq
->pnew
);
148 cf_put(cf
, pq
->qnew
);
152 cf_get(denom
, input
);
156 cf_get(denom
, input
);
163 mpz_clear(md
->a
); mpz_clear(md
->b
); mpz_clear(md
->c
); mpz_clear(md
->d
);
167 cf_t
cf_new_nonregular_mobius_convergent(cf_t x
, mpz_t a
, mpz_t b
, mpz_t c
, mpz_t d
) {
168 mobius_data_ptr md
= malloc(sizeof(*md
));
169 mpz_init(md
->a
); mpz_init(md
->b
); mpz_init(md
->c
); mpz_init(md
->d
);
170 mpz_set(md
->a
, a
); mpz_set(md
->b
, b
); mpz_set(md
->c
, c
); mpz_set(md
->d
, d
);
172 return cf_new(nonregular_mobius_convergent
, md
);
175 static void *mobius_nonregular_throughput(cf_t cf
) {
176 mobius_data_ptr md
= cf_data(cf
);
177 cf_t input
= md
->input
;
178 pqset_t pq
; pqset_init(pq
); pqset_set_mobius(pq
, md
);
179 mpz_t num
; mpz_init(num
);
180 mpz_t denom
; mpz_init(denom
);
181 mpz_t t0
, t1
; mpz_init(t1
); mpz_init(t0
);
183 pqset_nonregular_recur(pq
, num
, denom
);
184 pqset_remove_gcd(pq
);
185 if (mpz_sgn(pq
->q
)) {
186 mpz_fdiv_qr(pq
->pold
, t0
, pq
->p
, pq
->q
);
187 // mpz_fdiv_qr(qold, t1, pnew, qnew);
188 mpz_mul(pq
->qold
, pq
->pold
, pq
->qnew
);
190 // TODO: What if we're comparing equals?
191 if (mpz_cmp(pq
->qold
, pq
->pnew
) < 0) {
192 mpz_add(pq
->qold
, pq
->qold
, pq
->qnew
);
193 if (mpz_cmp(pq
->qold
, pq
->pnew
) > 0) {
194 // Output continued fraction term.
195 cf_put(cf
, pq
->pold
);
196 // Compute remainder of pnew/qnew.
197 mpz_sub(t1
, pq
->qold
, pq
->pnew
);
198 mpz_sub(t1
, pq
->qnew
, t1
);
200 mpz_set(pq
->pold
, pq
->q
);
201 mpz_set(pq
->qold
, t0
);
202 mpz_set(pq
->p
, pq
->qnew
);
212 cf_get(denom
, input
);
217 cf_get(denom
, input
);
224 mpz_clear(md
->a
); mpz_clear(md
->b
); mpz_clear(md
->c
); mpz_clear(md
->d
);
226 mpz_clear(t1
); mpz_clear(t0
);
230 cf_t
cf_new_nonregular_to_cf(cf_t x
, mpz_t a
, mpz_t b
, mpz_t c
, mpz_t d
) {
231 mobius_data_ptr md
= malloc(sizeof(*md
));
232 mpz_init(md
->a
); mpz_init(md
->b
); mpz_init(md
->c
); mpz_init(md
->d
);
233 mpz_set(md
->a
, a
); mpz_set(md
->b
, b
); mpz_set(md
->c
, c
); mpz_set(md
->d
, d
);
235 return cf_new(mobius_nonregular_throughput
, md
);
238 static void *mobius_decimal(cf_t cf
) {
239 mobius_data_ptr md
= cf_data(cf
);
240 cf_t input
= md
->input
;
241 pqset_t pq
; pqset_init(pq
); pqset_set_mobius(pq
, md
);
242 mpz_t denom
; mpz_init(denom
);
243 mpz_t t0
, t1
, t2
; mpz_init(t2
); mpz_init(t1
); mpz_init(t0
);
245 pqset_regular_recur(pq
, denom
);
247 // If the denominator is zero, we can't do anything yet.
248 if (mpz_sgn(pq
->qold
)) {
249 // The answer is one of {0, ..., 9}.
250 /* Naive attempt to expoit this didn't work well:
253 for (i = 0; i <= 9; i++) {
254 if (mpz_cmp(t0, pq->p) > 0) break;
255 mpz_add(t0, t0, pq->q);
257 mpz_set_ui(pq->pold, i);
258 mpz_sub(t0, t0, pq->p);
259 mpz_sub(t0, pq->q, t0);
260 mpz_mul(pq->qold, pq->pold, pq->qnew);
263 mpz_fdiv_qr(t1
, t0
, pq
->pold
, pq
->qold
);
264 mpz_mul(t2
, t1
, pq
->q
);
265 if (mpz_cmp(t2
, pq
->p
) <= 0) {
266 mpz_add(t2
, t2
, pq
->q
);
267 if (mpz_cmp(t2
, pq
->p
) > 0) {
268 // Output a decimal digit.
270 // Compute t2 = remainder of pnew/qnew.
271 mpz_sub(t2
, t2
, pq
->p
);
272 mpz_sub(t2
, pq
->q
, t2
);
273 // Multiply numerator by 10.
274 mpz_mul_ui(pq
->pold
, t0
, 10);
275 mpz_mul_ui(pq
->p
, t2
, 10);
285 cf_get(denom
, input
);
290 mpz_clear(t0
); mpz_clear(t1
); mpz_clear(t2
);
291 mpz_clear(md
->a
); mpz_clear(md
->b
); mpz_clear(md
->c
); mpz_clear(md
->d
);
295 cf_t
cf_new_mobius_to_decimal(cf_t x
, mpz_t a
, mpz_t b
, mpz_t c
, mpz_t d
) {
296 mobius_data_ptr md
= malloc(sizeof(*md
));
297 mpz_init(md
->a
); mpz_init(md
->b
); mpz_init(md
->c
); mpz_init(md
->d
);
298 mpz_set(md
->a
, a
); mpz_set(md
->b
, b
); mpz_set(md
->c
, c
); mpz_set(md
->d
, d
);
300 return cf_new(mobius_decimal
, md
);
303 cf_t
cf_new_cf_to_decimal(cf_t x
) {
305 mpz_init(one
); mpz_init(zero
);
306 mpz_set_ui(one
, 1); mpz_set_ui(zero
, 0);
307 cf_t res
= cf_new_mobius_to_decimal(x
, one
, zero
, zero
, one
);
308 mpz_clear(one
); mpz_clear(zero
);
312 static void *nonregular_mobius_decimal(cf_t cf
) {
313 mobius_data_ptr md
= cf_data(cf
);
314 cf_t input
= md
->input
;
315 pqset_t pq
; pqset_init(pq
); pqset_set_mobius(pq
, md
);
316 mpz_t num
; mpz_init(num
);
317 mpz_t denom
; mpz_init(denom
);
318 mpz_t t0
, t1
; mpz_init(t1
); mpz_init(t0
);
320 pqset_nonregular_recur(pq
, num
, denom
);
321 pqset_remove_gcd(pq
);
323 // If the denominator is zero, we can't do anything yet.
324 if (mpz_sgn(pq
->q
)) {
325 mpz_fdiv_qr(pq
->pold
, t0
, pq
->p
, pq
->q
);
326 mpz_mul(pq
->qold
, pq
->pold
, pq
->qnew
);
327 // TODO: What if we're comparing equals?
328 if (mpz_cmp(pq
->qold
, pq
->pnew
) < 0) {
329 mpz_add(pq
->qold
, pq
->qold
, pq
->qnew
);
330 if (mpz_cmp(pq
->qold
, pq
->pnew
) > 0) {
331 // Output a decimal digit.
332 cf_put(cf
, pq
->pold
);
333 // Compute t1 = remainder of pnew/qnew.
334 mpz_sub(t1
, pq
->qold
, pq
->pnew
);
335 mpz_sub(t1
, pq
->qnew
, t1
);
336 // Multiply numerator by 10.
337 mpz_mul_ui(pq
->pold
, t0
, 10);
338 mpz_set(pq
->qold
, pq
->q
);
339 mpz_mul_ui(pq
->p
, t1
, 10);
340 mpz_set(pq
->q
, pq
->qnew
);
349 cf_get(denom
, input
);
354 cf_get(denom
, input
);
360 mpz_clear(t0
); mpz_clear(t1
);
361 mpz_clear(md
->a
); mpz_clear(md
->b
); mpz_clear(md
->c
); mpz_clear(md
->d
);
366 cf_t
cf_new_nonregular_mobius_to_decimal(cf_t x
, mpz_t a
, mpz_t b
, mpz_t c
, mpz_t d
) {
367 mobius_data_ptr md
= malloc(sizeof(*md
));
368 mpz_init(md
->a
); mpz_init(md
->b
); mpz_init(md
->c
); mpz_init(md
->d
);
369 mpz_set(md
->a
, a
); mpz_set(md
->b
, b
); mpz_set(md
->c
, c
); mpz_set(md
->d
, d
);
371 return cf_new(nonregular_mobius_decimal
, md
);