mini-mpq.c revision 1.1.1.1 1 1.1 mrg /* mini-mpq, a minimalistic implementation of a GNU GMP subset.
2 1.1 mrg
3 1.1 mrg Contributed to the GNU project by Marco Bodrato
4 1.1 mrg
5 1.1 mrg Acknowledgment: special thanks to Bradley Lucier for his comments
6 1.1 mrg to the preliminary version of this code.
7 1.1 mrg
8 1.1 mrg Copyright 2018, 2019 Free Software Foundation, Inc.
9 1.1 mrg
10 1.1 mrg This file is part of the GNU MP Library.
11 1.1 mrg
12 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
13 1.1 mrg it under the terms of either:
14 1.1 mrg
15 1.1 mrg * the GNU Lesser General Public License as published by the Free
16 1.1 mrg Software Foundation; either version 3 of the License, or (at your
17 1.1 mrg option) any later version.
18 1.1 mrg
19 1.1 mrg or
20 1.1 mrg
21 1.1 mrg * the GNU General Public License as published by the Free Software
22 1.1 mrg Foundation; either version 2 of the License, or (at your option) any
23 1.1 mrg later version.
24 1.1 mrg
25 1.1 mrg or both in parallel, as here.
26 1.1 mrg
27 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
28 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 1.1 mrg for more details.
31 1.1 mrg
32 1.1 mrg You should have received copies of the GNU General Public License and the
33 1.1 mrg GNU Lesser General Public License along with the GNU MP Library. If not,
34 1.1 mrg see https://www.gnu.org/licenses/. */
35 1.1 mrg
36 1.1 mrg #include <assert.h>
37 1.1 mrg #include <limits.h>
38 1.1 mrg #include <stdio.h>
39 1.1 mrg #include <stdlib.h>
40 1.1 mrg #include <string.h>
41 1.1 mrg
42 1.1 mrg #include "mini-mpq.h"
43 1.1 mrg
44 1.1 mrg #ifndef GMP_LIMB_HIGHBIT
45 1.1 mrg /* Define macros and static functions already defined by mini-gmp.c */
46 1.1 mrg #define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
47 1.1 mrg #define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
48 1.1 mrg #define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
49 1.1 mrg #define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
50 1.1 mrg
51 1.1 mrg static mpz_srcptr
52 1.1 mrg mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
53 1.1 mrg {
54 1.1 mrg x->_mp_alloc = 0;
55 1.1 mrg x->_mp_d = (mp_ptr) xp;
56 1.1 mrg x->_mp_size = xs;
57 1.1 mrg return x;
58 1.1 mrg }
59 1.1 mrg
60 1.1 mrg static void
61 1.1 mrg gmp_die (const char *msg)
62 1.1 mrg {
63 1.1 mrg fprintf (stderr, "%s\n", msg);
64 1.1 mrg abort();
65 1.1 mrg }
66 1.1 mrg #endif
67 1.1 mrg
68 1.1 mrg
69 1.1 mrg /* MPQ helper functions */
71 1.1 mrg static mpq_srcptr
72 1.1 mrg mpq_roinit_normal_nn (mpq_t x, mp_srcptr np, mp_size_t ns,
73 1.1 mrg mp_srcptr dp, mp_size_t ds)
74 1.1 mrg {
75 1.1 mrg mpz_roinit_normal_n (mpq_numref(x), np, ns);
76 1.1 mrg mpz_roinit_normal_n (mpq_denref(x), dp, ds);
77 1.1 mrg return x;
78 1.1 mrg }
79 1.1 mrg
80 1.1 mrg static mpq_srcptr
81 1.1 mrg mpq_roinit_zz (mpq_t x, mpz_srcptr n, mpz_srcptr d)
82 1.1 mrg {
83 1.1 mrg return mpq_roinit_normal_nn (x, n->_mp_d, n->_mp_size,
84 1.1 mrg d->_mp_d, d->_mp_size);
85 1.1 mrg }
86 1.1 mrg
87 1.1 mrg static void
88 1.1 mrg mpq_nan_init (mpq_t x)
89 1.1 mrg {
90 1.1 mrg mpz_init (mpq_numref (x));
91 1.1 mrg mpz_init (mpq_denref (x));
92 1.1 mrg }
93 1.1 mrg
94 1.1 mrg void
95 1.1 mrg mpq_init (mpq_t x)
96 1.1 mrg {
97 1.1 mrg mpz_init (mpq_numref (x));
98 1.1 mrg mpz_init_set_ui (mpq_denref (x), 1);
99 1.1 mrg }
100 1.1 mrg
101 1.1 mrg void
102 1.1 mrg mpq_clear (mpq_t x)
103 1.1 mrg {
104 1.1 mrg mpz_clear (mpq_numref (x));
105 1.1 mrg mpz_clear (mpq_denref (x));
106 1.1 mrg }
107 1.1 mrg
108 1.1 mrg static void
109 1.1 mrg mpq_canonical_sign (mpq_t r)
110 1.1 mrg {
111 1.1 mrg int cmp = mpq_denref (r)->_mp_size;
112 1.1 mrg if (cmp <= 0)
113 1.1 mrg {
114 1.1 mrg if (cmp == 0)
115 1.1 mrg gmp_die("mpq: Fraction with zero denominator.");
116 1.1 mrg mpz_neg (mpq_denref (r), mpq_denref (r));
117 1.1 mrg mpz_neg (mpq_numref (r), mpq_numref (r));
118 1.1 mrg }
119 1.1 mrg }
120 1.1 mrg
121 1.1 mrg static void
122 1.1 mrg mpq_helper_canonicalize (mpq_t r, const mpz_t num, const mpz_t den, mpz_t g)
123 1.1 mrg {
124 1.1 mrg if (num->_mp_size == 0)
125 1.1 mrg mpq_set_ui (r, 0, 1);
126 1.1 mrg else
127 1.1 mrg {
128 1.1 mrg mpz_gcd (g, num, den);
129 1.1 mrg mpz_tdiv_q (mpq_numref (r), num, g);
130 1.1 mrg mpz_tdiv_q (mpq_denref (r), den, g);
131 1.1 mrg mpq_canonical_sign (r);
132 1.1 mrg }
133 1.1 mrg }
134 1.1 mrg
135 1.1 mrg void
136 1.1 mrg mpq_canonicalize (mpq_t r)
137 1.1 mrg {
138 1.1 mrg mpz_t t;
139 1.1 mrg
140 1.1 mrg mpz_init (t);
141 1.1 mrg mpq_helper_canonicalize (r, mpq_numref (r), mpq_denref (r), t);
142 1.1 mrg mpz_clear (t);
143 1.1 mrg }
144 1.1 mrg
145 1.1 mrg void
146 1.1 mrg mpq_swap (mpq_t a, mpq_t b)
147 1.1 mrg {
148 1.1 mrg mpz_swap (mpq_numref (a), mpq_numref (b));
149 1.1 mrg mpz_swap (mpq_denref (a), mpq_denref (b));
150 1.1 mrg }
151 1.1 mrg
152 1.1 mrg
153 1.1 mrg /* MPQ assignment and conversions. */
155 1.1 mrg void
156 1.1 mrg mpz_set_q (mpz_t r, const mpq_t q)
157 1.1 mrg {
158 1.1 mrg mpz_tdiv_q (r, mpq_numref (q), mpq_denref (q));
159 1.1 mrg }
160 1.1 mrg
161 1.1 mrg void
162 1.1 mrg mpq_set (mpq_t r, const mpq_t q)
163 1.1 mrg {
164 1.1 mrg mpz_set (mpq_numref (r), mpq_numref (q));
165 1.1 mrg mpz_set (mpq_denref (r), mpq_denref (q));
166 1.1 mrg }
167 1.1 mrg
168 1.1 mrg void
169 1.1 mrg mpq_set_ui (mpq_t r, unsigned long n, unsigned long d)
170 1.1 mrg {
171 1.1 mrg mpz_set_ui (mpq_numref (r), n);
172 1.1 mrg mpz_set_ui (mpq_denref (r), d);
173 1.1 mrg }
174 1.1 mrg
175 1.1 mrg void
176 1.1 mrg mpq_set_si (mpq_t r, signed long n, unsigned long d)
177 1.1 mrg {
178 1.1 mrg mpz_set_si (mpq_numref (r), n);
179 1.1 mrg mpz_set_ui (mpq_denref (r), d);
180 1.1 mrg }
181 1.1 mrg
182 1.1 mrg void
183 1.1 mrg mpq_set_z (mpq_t r, const mpz_t n)
184 1.1 mrg {
185 1.1 mrg mpz_set_ui (mpq_denref (r), 1);
186 1.1 mrg mpz_set (mpq_numref (r), n);
187 1.1 mrg }
188 1.1 mrg
189 1.1 mrg void
190 1.1 mrg mpq_set_num (mpq_t r, const mpz_t z)
191 1.1 mrg {
192 1.1 mrg mpz_set (mpq_numref (r), z);
193 1.1 mrg }
194 1.1 mrg
195 1.1 mrg void
196 1.1 mrg mpq_set_den (mpq_t r, const mpz_t z)
197 1.1 mrg {
198 1.1 mrg mpz_set (mpq_denref (r), z);
199 1.1 mrg }
200 1.1 mrg
201 1.1 mrg void
202 1.1 mrg mpq_get_num (mpz_t r, const mpq_t q)
203 1.1 mrg {
204 1.1 mrg mpz_set (r, mpq_numref (q));
205 1.1 mrg }
206 1.1 mrg
207 1.1 mrg void
208 1.1 mrg mpq_get_den (mpz_t r, const mpq_t q)
209 1.1 mrg {
210 1.1 mrg mpz_set (r, mpq_denref (q));
211 1.1 mrg }
212 1.1 mrg
213 1.1 mrg
214 1.1 mrg /* MPQ comparisons and the like. */
216 1.1 mrg int
217 1.1 mrg mpq_cmp (const mpq_t a, const mpq_t b)
218 1.1 mrg {
219 1.1 mrg mpz_t t1, t2;
220 1.1 mrg int res;
221 1.1 mrg
222 1.1 mrg mpz_init (t1);
223 1.1 mrg mpz_init (t2);
224 1.1 mrg mpz_mul (t1, mpq_numref (a), mpq_denref (b));
225 1.1 mrg mpz_mul (t2, mpq_numref (b), mpq_denref (a));
226 1.1 mrg res = mpz_cmp (t1, t2);
227 1.1 mrg mpz_clear (t1);
228 1.1 mrg mpz_clear (t2);
229 1.1 mrg
230 1.1 mrg return res;
231 1.1 mrg }
232 1.1 mrg
233 1.1 mrg int
234 1.1 mrg mpq_cmp_z (const mpq_t a, const mpz_t b)
235 1.1 mrg {
236 1.1 mrg mpz_t t;
237 1.1 mrg int res;
238 1.1 mrg
239 1.1 mrg mpz_init (t);
240 1.1 mrg mpz_mul (t, b, mpq_denref (a));
241 1.1 mrg res = mpz_cmp (mpq_numref (a), t);
242 1.1 mrg mpz_clear (t);
243 1.1 mrg
244 1.1 mrg return res;
245 1.1 mrg }
246 1.1 mrg
247 1.1 mrg int
248 1.1 mrg mpq_equal (const mpq_t a, const mpq_t b)
249 1.1 mrg {
250 1.1 mrg return (mpz_cmp (mpq_numref (a), mpq_numref (b)) == 0) &&
251 1.1 mrg (mpz_cmp (mpq_denref (a), mpq_denref (b)) == 0);
252 1.1 mrg }
253 1.1 mrg
254 1.1 mrg int
255 1.1 mrg mpq_cmp_ui (const mpq_t q, unsigned long n, unsigned long d)
256 1.1 mrg {
257 1.1 mrg mpq_t t;
258 1.1 mrg assert (d != 0);
259 1.1 mrg if (ULONG_MAX <= GMP_LIMB_MAX) {
260 1.1 mrg mp_limb_t nl = n, dl = d;
261 1.1 mrg return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, n != 0, &dl, 1));
262 1.1 mrg } else {
263 1.1 mrg int ret;
264 1.1 mrg
265 1.1 mrg mpq_init (t);
266 1.1 mrg mpq_set_ui (t, n, d);
267 1.1 mrg ret = mpq_cmp (q, t);
268 1.1 mrg mpq_clear (t);
269 1.1 mrg
270 1.1 mrg return ret;
271 1.1 mrg }
272 1.1 mrg }
273 1.1 mrg
274 1.1 mrg int
275 1.1 mrg mpq_cmp_si (const mpq_t q, signed long n, unsigned long d)
276 1.1 mrg {
277 1.1 mrg assert (d != 0);
278 1.1 mrg
279 1.1 mrg if (n >= 0)
280 1.1 mrg return mpq_cmp_ui (q, n, d);
281 1.1 mrg else
282 1.1 mrg {
283 1.1 mrg mpq_t t;
284 1.1 mrg
285 1.1 mrg if (ULONG_MAX <= GMP_LIMB_MAX)
286 1.1 mrg {
287 1.1 mrg mp_limb_t nl = GMP_NEG_CAST (unsigned long, n), dl = d;
288 1.1 mrg return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, -1, &dl, 1));
289 1.1 mrg }
290 1.1 mrg else
291 1.1 mrg {
292 1.1 mrg unsigned long l_n = GMP_NEG_CAST (unsigned long, n);
293 1.1 mrg
294 1.1 mrg mpq_roinit_normal_nn (t, mpq_numref (q)->_mp_d, - mpq_numref (q)->_mp_size,
295 1.1 mrg mpq_denref (q)->_mp_d, mpq_denref (q)->_mp_size);
296 1.1 mrg return - mpq_cmp_ui (t, l_n, d);
297 1.1 mrg }
298 1.1 mrg }
299 1.1 mrg }
300 1.1 mrg
301 1.1 mrg int
302 1.1 mrg mpq_sgn (const mpq_t a)
303 1.1 mrg {
304 1.1 mrg return mpz_sgn (mpq_numref (a));
305 1.1 mrg }
306 1.1 mrg
307 1.1 mrg
308 1.1 mrg /* MPQ arithmetic. */
310 1.1 mrg void
311 1.1 mrg mpq_abs (mpq_t r, const mpq_t q)
312 1.1 mrg {
313 1.1 mrg mpz_abs (mpq_numref (r), mpq_numref (q));
314 1.1 mrg mpz_set (mpq_denref (r), mpq_denref (q));
315 1.1 mrg }
316 1.1 mrg
317 1.1 mrg void
318 1.1 mrg mpq_neg (mpq_t r, const mpq_t q)
319 1.1 mrg {
320 1.1 mrg mpz_neg (mpq_numref (r), mpq_numref (q));
321 1.1 mrg mpz_set (mpq_denref (r), mpq_denref (q));
322 1.1 mrg }
323 1.1 mrg
324 1.1 mrg void
325 1.1 mrg mpq_add (mpq_t r, const mpq_t a, const mpq_t b)
326 1.1 mrg {
327 1.1 mrg mpz_t t;
328 1.1 mrg
329 1.1 mrg mpz_init (t);
330 1.1 mrg mpz_gcd (t, mpq_denref (a), mpq_denref (b));
331 1.1 mrg if (mpz_cmp_ui (t, 1) == 0)
332 1.1 mrg {
333 1.1 mrg mpz_mul (t, mpq_numref (a), mpq_denref (b));
334 1.1 mrg mpz_addmul (t, mpq_numref (b), mpq_denref (a));
335 1.1 mrg mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
336 1.1 mrg mpz_swap (mpq_numref (r), t);
337 1.1 mrg }
338 1.1 mrg else
339 1.1 mrg {
340 1.1 mrg mpz_t x, y;
341 1.1 mrg mpz_init (x);
342 1.1 mrg mpz_init (y);
343 1.1 mrg
344 1.1 mrg mpz_tdiv_q (x, mpq_denref (b), t);
345 1.1 mrg mpz_tdiv_q (y, mpq_denref (a), t);
346 1.1 mrg mpz_mul (x, mpq_numref (a), x);
347 1.1 mrg mpz_addmul (x, mpq_numref (b), y);
348 1.1 mrg
349 1.1 mrg mpz_gcd (t, x, t);
350 1.1 mrg mpz_tdiv_q (mpq_numref (r), x, t);
351 1.1 mrg mpz_tdiv_q (x, mpq_denref (b), t);
352 1.1 mrg mpz_mul (mpq_denref (r), x, y);
353 1.1 mrg
354 1.1 mrg mpz_clear (x);
355 1.1 mrg mpz_clear (y);
356 1.1 mrg }
357 1.1 mrg mpz_clear (t);
358 1.1 mrg }
359 1.1 mrg
360 1.1 mrg void
361 1.1 mrg mpq_sub (mpq_t r, const mpq_t a, const mpq_t b)
362 1.1 mrg {
363 1.1 mrg mpq_t t;
364 1.1 mrg
365 1.1 mrg mpq_roinit_normal_nn (t, mpq_numref (b)->_mp_d, - mpq_numref (b)->_mp_size,
366 1.1 mrg mpq_denref (b)->_mp_d, mpq_denref (b)->_mp_size);
367 1.1 mrg mpq_add (r, a, t);
368 1.1 mrg }
369 1.1 mrg
370 1.1 mrg void
371 1.1 mrg mpq_div (mpq_t r, const mpq_t a, const mpq_t b)
372 1.1 mrg {
373 1.1 mrg mpq_t t;
374 1.1 mrg mpq_mul (r, a, mpq_roinit_zz (t, mpq_denref (b), mpq_numref (b)));
375 1.1 mrg }
376 1.1 mrg
377 1.1 mrg void
378 1.1 mrg mpq_mul (mpq_t r, const mpq_t a, const mpq_t b)
379 1.1 mrg {
380 1.1 mrg mpq_t t;
381 1.1 mrg mpq_nan_init (t);
382 1.1 mrg
383 1.1 mrg if (a != b) {
384 1.1 mrg mpz_t g;
385 1.1 mrg
386 1.1 mrg mpz_init (g);
387 1.1 mrg mpq_helper_canonicalize (t, mpq_numref (a), mpq_denref (b), g);
388 1.1 mrg mpq_helper_canonicalize (r, mpq_numref (b), mpq_denref (a), g);
389 1.1 mrg mpz_clear (g);
390 1.1 mrg
391 1.1 mrg a = r;
392 1.1 mrg b = t;
393 1.1 mrg }
394 1.1 mrg
395 1.1 mrg mpz_mul (mpq_numref (r), mpq_numref (a), mpq_numref (b));
396 1.1 mrg mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
397 1.1 mrg mpq_clear (t);
398 1.1 mrg }
399 1.1 mrg
400 1.1 mrg void
401 1.1 mrg mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
402 1.1 mrg {
403 1.1 mrg mp_bitcnt_t z = mpz_scan1 (mpq_numref (q), 0);
404 1.1 mrg z = GMP_MIN (z, e);
405 1.1 mrg mpz_mul_2exp (mpq_denref (r), mpq_denref (q), e - z);
406 1.1 mrg mpz_tdiv_q_2exp (mpq_numref (r), mpq_numref (q), z);
407 1.1 mrg }
408 1.1 mrg
409 1.1 mrg void
410 1.1 mrg mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
411 1.1 mrg {
412 1.1 mrg mp_bitcnt_t z = mpz_scan1 (mpq_denref (q), 0);
413 1.1 mrg z = GMP_MIN (z, e);
414 1.1 mrg mpz_mul_2exp (mpq_numref (r), mpq_numref (q), e - z);
415 1.1 mrg mpz_tdiv_q_2exp (mpq_denref (r), mpq_denref (q), z);
416 1.1 mrg }
417 1.1 mrg
418 1.1 mrg void
419 1.1 mrg mpq_inv (mpq_t r, const mpq_t q)
420 1.1 mrg {
421 1.1 mrg mpq_set (r, q);
422 1.1 mrg mpz_swap (mpq_denref (r), mpq_numref (r));
423 1.1 mrg mpq_canonical_sign (r);
424 1.1 mrg }
425 1.1 mrg
426 1.1 mrg
427 1.1 mrg /* MPQ to/from double. */
429 1.1 mrg void
430 1.1 mrg mpq_set_d (mpq_t r, double x)
431 1.1 mrg {
432 1.1 mrg mpz_set_ui (mpq_denref (r), 1);
433 1.1 mrg
434 1.1 mrg /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
435 1.1 mrg zero or infinity. */
436 1.1 mrg if (x == x * 0.5 || x != x)
437 1.1 mrg mpq_numref (r)->_mp_size = 0;
438 1.1 mrg else
439 1.1 mrg {
440 1.1 mrg double B;
441 1.1 mrg mp_bitcnt_t e;
442 1.1 mrg
443 1.1 mrg B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
444 1.1 mrg for (e = 0; x != x + 0.5; e += GMP_LIMB_BITS)
445 1.1 mrg x *= B;
446 1.1 mrg
447 1.1 mrg mpz_set_d (mpq_numref (r), x);
448 1.1 mrg mpq_div_2exp (r, r, e);
449 1.1 mrg }
450 1.1 mrg }
451 1.1 mrg
452 1.1 mrg double
453 1.1 mrg mpq_get_d (const mpq_t u)
454 1.1 mrg {
455 1.1 mrg mp_bitcnt_t ne, de, ee;
456 1.1 mrg mpz_t z;
457 1.1 mrg double B, ret;
458 1.1 mrg
459 1.1 mrg ne = mpz_sizeinbase (mpq_numref (u), 2);
460 1.1 mrg de = mpz_sizeinbase (mpq_denref (u), 2);
461 1.1 mrg
462 1.1 mrg ee = CHAR_BIT * sizeof (double);
463 1.1 mrg if (de == 1 || ne > de + ee)
464 1.1 mrg ee = 0;
465 1.1 mrg else
466 1.1 mrg ee = (ee + de - ne) / GMP_LIMB_BITS + 1;
467 1.1 mrg
468 1.1 mrg mpz_init (z);
469 1.1 mrg mpz_mul_2exp (z, mpq_numref (u), ee * GMP_LIMB_BITS);
470 1.1 mrg mpz_tdiv_q (z, z, mpq_denref (u));
471 1.1 mrg ret = mpz_get_d (z);
472 1.1 mrg mpz_clear (z);
473 1.1 mrg
474 1.1 mrg B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
475 1.1 mrg for (B = 1 / B; ee != 0; --ee)
476 1.1 mrg ret *= B;
477 1.1 mrg
478 1.1 mrg return ret;
479 1.1 mrg }
480 1.1 mrg
481 1.1 mrg
482 1.1 mrg /* MPQ and strings/streams. */
484 1.1 mrg char *
485 1.1 mrg mpq_get_str (char *sp, int base, const mpq_t q)
486 1.1 mrg {
487 1.1 mrg char *res;
488 1.1 mrg char *rden;
489 1.1 mrg size_t len;
490 1.1 mrg
491 1.1 mrg res = mpz_get_str (sp, base, mpq_numref (q));
492 1.1 mrg if (res == NULL || mpz_cmp_ui (mpq_denref (q), 1) == 0)
493 1.1 mrg return res;
494 1.1 mrg
495 1.1 mrg len = strlen (res) + 1;
496 1.1 mrg rden = sp ? sp + len : NULL;
497 1.1 mrg rden = mpz_get_str (rden, base, mpq_denref (q));
498 1.1 mrg assert (rden != NULL);
499 1.1 mrg
500 1.1 mrg if (sp == NULL) {
501 1.1 mrg void * (*gmp_reallocate_func) (void *, size_t, size_t);
502 1.1 mrg void (*gmp_free_func) (void *, size_t);
503 1.1 mrg size_t lden;
504 1.1 mrg
505 1.1 mrg mp_get_memory_functions (NULL, &gmp_reallocate_func, &gmp_free_func);
506 1.1 mrg lden = strlen (rden) + 1;
507 1.1 mrg res = (char *) gmp_reallocate_func (res, 0, (lden + len) * sizeof (char));
508 1.1 mrg memcpy (res + len, rden, lden);
509 1.1 mrg gmp_free_func (rden, 0);
510 1.1 mrg }
511 1.1 mrg
512 1.1 mrg res [len - 1] = '/';
513 1.1 mrg return res;
514 1.1 mrg }
515 1.1 mrg
516 1.1 mrg size_t
517 1.1 mrg mpq_out_str (FILE *stream, int base, const mpq_t x)
518 1.1 mrg {
519 1.1 mrg char * str;
520 1.1 mrg size_t len;
521 1.1 mrg void (*gmp_free_func) (void *, size_t);
522 1.1 mrg
523 1.1 mrg str = mpq_get_str (NULL, base, x);
524 1.1 mrg len = strlen (str);
525 1.1 mrg len = fwrite (str, 1, len, stream);
526 1.1 mrg mp_get_memory_functions (NULL, NULL, &gmp_free_func);
527 1.1 mrg gmp_free_func (str, 0);
528 1.1 mrg return len;
529 1.1 mrg }
530 1.1 mrg
531 1.1 mrg int
532 1.1 mrg mpq_set_str (mpq_t r, const char *sp, int base)
533 1.1 mrg {
534 1.1 mrg const char *slash;
535 1.1 mrg
536 1.1 mrg slash = strchr (sp, '/');
537 1.1 mrg if (slash == NULL) {
538 1.1 mrg mpz_set_ui (mpq_denref(r), 1);
539 1.1 mrg return mpz_set_str (mpq_numref(r), sp, base);
540 1.1 mrg } else {
541 1.1 mrg char *num;
542 1.1 mrg size_t numlen;
543 1.1 mrg int ret;
544 1.1 mrg void * (*gmp_allocate_func) (size_t);
545 1.1 mrg void (*gmp_free_func) (void *, size_t);
546 1.1 mrg
547 1.1 mrg mp_get_memory_functions (&gmp_allocate_func, NULL, &gmp_free_func);
548 1.1 mrg numlen = slash - sp;
549 1.1 mrg num = (char *) gmp_allocate_func ((numlen + 1) * sizeof (char));
550 1.1 mrg memcpy (num, sp, numlen);
551 1.1 mrg num[numlen] = '\0';
552 1.1 mrg ret = mpz_set_str (mpq_numref(r), num, base);
553 1.1 mrg gmp_free_func (num, 0);
554 1.1 mrg
555 if (ret != 0)
556 return ret;
557
558 return mpz_set_str (mpq_denref(r), slash + 1, base);
559 }
560 }
561