1 /*
2 Name: imrat.c
3 Purpose: Arbitrary precision rational arithmetic routines.
4 Author: M. J. Fromberger <http://spinning-yarns.org/michael/>
5
6 Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 #include "imrat.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <assert.h>
32
33 #define TEMP(K) (temp + (K))
34 #define SETUP(E, C) \
35 do{if((res = (E)) != MP_OK) goto CLEANUP; ++(C);}while(0)
36
37 /* Argument checking:
38 Use CHECK() where a return value is required; NRCHECK() elsewhere */
39 #define CHECK(TEST) assert(TEST)
40 #define NRCHECK(TEST) assert(TEST)
41
42 /* Reduce the given rational, in place, to lowest terms and canonical form.
43 Zero is represented as 0/1, one as 1/1. Signs are adjusted so that the sign
44 of the numerator is definitive. */
45 static mp_result s_rat_reduce(mp_rat r);
46
47 /* Common code for addition and subtraction operations on rationals. */
48 static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c,
49 mp_result (*comb_f)(mp_int, mp_int, mp_int));
50
mp_rat_init(mp_rat r)51 mp_result mp_rat_init(mp_rat r)
52 {
53 mp_result res;
54
55 if ((res = mp_int_init(MP_NUMER_P(r))) != MP_OK)
56 return res;
57 if ((res = mp_int_init(MP_DENOM_P(r))) != MP_OK) {
58 mp_int_clear(MP_NUMER_P(r));
59 return res;
60 }
61
62 return mp_int_set_value(MP_DENOM_P(r), 1);
63 }
64
mp_rat_alloc(void)65 mp_rat mp_rat_alloc(void)
66 {
67 mp_rat out = malloc(sizeof(*out));
68
69 if (out != NULL) {
70 if (mp_rat_init(out) != MP_OK) {
71 free(out);
72 return NULL;
73 }
74 }
75
76 return out;
77 }
78
mp_rat_reduce(mp_rat r)79 mp_result mp_rat_reduce(mp_rat r) {
80 return s_rat_reduce(r);
81 }
82
mp_rat_init_size(mp_rat r,mp_size n_prec,mp_size d_prec)83 mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec)
84 {
85 mp_result res;
86
87 if ((res = mp_int_init_size(MP_NUMER_P(r), n_prec)) != MP_OK)
88 return res;
89 if ((res = mp_int_init_size(MP_DENOM_P(r), d_prec)) != MP_OK) {
90 mp_int_clear(MP_NUMER_P(r));
91 return res;
92 }
93
94 return mp_int_set_value(MP_DENOM_P(r), 1);
95 }
96
mp_rat_init_copy(mp_rat r,mp_rat old)97 mp_result mp_rat_init_copy(mp_rat r, mp_rat old)
98 {
99 mp_result res;
100
101 if ((res = mp_int_init_copy(MP_NUMER_P(r), MP_NUMER_P(old))) != MP_OK)
102 return res;
103 if ((res = mp_int_init_copy(MP_DENOM_P(r), MP_DENOM_P(old))) != MP_OK)
104 mp_int_clear(MP_NUMER_P(r));
105
106 return res;
107 }
108
mp_rat_set_value(mp_rat r,mp_small numer,mp_small denom)109 mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom)
110 {
111 mp_result res;
112
113 if (denom == 0)
114 return MP_UNDEF;
115
116 if ((res = mp_int_set_value(MP_NUMER_P(r), numer)) != MP_OK)
117 return res;
118 if ((res = mp_int_set_value(MP_DENOM_P(r), denom)) != MP_OK)
119 return res;
120
121 return s_rat_reduce(r);
122 }
123
mp_rat_set_uvalue(mp_rat r,mp_usmall numer,mp_usmall denom)124 mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom)
125 {
126 mp_result res;
127
128 if (denom == 0)
129 return MP_UNDEF;
130
131 if ((res = mp_int_set_uvalue(MP_NUMER_P(r), numer)) != MP_OK)
132 return res;
133 if ((res = mp_int_set_uvalue(MP_DENOM_P(r), denom)) != MP_OK)
134 return res;
135
136 return s_rat_reduce(r);
137 }
138
mp_rat_clear(mp_rat r)139 void mp_rat_clear(mp_rat r)
140 {
141 mp_int_clear(MP_NUMER_P(r));
142 mp_int_clear(MP_DENOM_P(r));
143
144 }
145
mp_rat_free(mp_rat r)146 void mp_rat_free(mp_rat r)
147 {
148 NRCHECK(r != NULL);
149
150 if (r->num.digits != NULL)
151 mp_rat_clear(r);
152
153 free(r);
154 }
155
mp_rat_numer(mp_rat r,mp_int z)156 mp_result mp_rat_numer(mp_rat r, mp_int z)
157 {
158 return mp_int_copy(MP_NUMER_P(r), z);
159 }
160
mp_rat_numer_ref(mp_rat r)161 mp_int mp_rat_numer_ref(mp_rat r)
162 {
163 return MP_NUMER_P(r);
164 }
165
166
mp_rat_denom(mp_rat r,mp_int z)167 mp_result mp_rat_denom(mp_rat r, mp_int z)
168 {
169 return mp_int_copy(MP_DENOM_P(r), z);
170 }
171
mp_rat_denom_ref(mp_rat r)172 mp_int mp_rat_denom_ref(mp_rat r)
173 {
174 return MP_DENOM_P(r);
175 }
176
mp_rat_sign(mp_rat r)177 mp_sign mp_rat_sign(mp_rat r)
178 {
179 return MP_SIGN(MP_NUMER_P(r));
180 }
181
mp_rat_copy(mp_rat a,mp_rat c)182 mp_result mp_rat_copy(mp_rat a, mp_rat c)
183 {
184 mp_result res;
185
186 if ((res = mp_int_copy(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
187 return res;
188
189 res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c));
190 return res;
191 }
192
mp_rat_zero(mp_rat r)193 void mp_rat_zero(mp_rat r)
194 {
195 mp_int_zero(MP_NUMER_P(r));
196 mp_int_set_value(MP_DENOM_P(r), 1);
197
198 }
199
mp_rat_abs(mp_rat a,mp_rat c)200 mp_result mp_rat_abs(mp_rat a, mp_rat c)
201 {
202 mp_result res;
203
204 if ((res = mp_int_abs(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
205 return res;
206
207 res = mp_int_abs(MP_DENOM_P(a), MP_DENOM_P(c));
208 return res;
209 }
210
mp_rat_neg(mp_rat a,mp_rat c)211 mp_result mp_rat_neg(mp_rat a, mp_rat c)
212 {
213 mp_result res;
214
215 if ((res = mp_int_neg(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
216 return res;
217
218 res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c));
219 return res;
220 }
221
mp_rat_recip(mp_rat a,mp_rat c)222 mp_result mp_rat_recip(mp_rat a, mp_rat c)
223 {
224 mp_result res;
225
226 if (mp_rat_compare_zero(a) == 0)
227 return MP_UNDEF;
228
229 if ((res = mp_rat_copy(a, c)) != MP_OK)
230 return res;
231
232 mp_int_swap(MP_NUMER_P(c), MP_DENOM_P(c));
233
234 /* Restore the signs of the swapped elements */
235 {
236 mp_sign tmp = MP_SIGN(MP_NUMER_P(c));
237
238 MP_SIGN(MP_NUMER_P(c)) = MP_SIGN(MP_DENOM_P(c));
239 MP_SIGN(MP_DENOM_P(c)) = tmp;
240 }
241
242 return MP_OK;
243 }
244
mp_rat_add(mp_rat a,mp_rat b,mp_rat c)245 mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c)
246 {
247 return s_rat_combine(a, b, c, mp_int_add);
248
249 }
250
mp_rat_sub(mp_rat a,mp_rat b,mp_rat c)251 mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c)
252 {
253 return s_rat_combine(a, b, c, mp_int_sub);
254
255 }
256
mp_rat_mul(mp_rat a,mp_rat b,mp_rat c)257 mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c)
258 {
259 mp_result res;
260
261 if ((res = mp_int_mul(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK)
262 return res;
263
264 if (mp_int_compare_zero(MP_NUMER_P(c)) != 0) {
265 if ((res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c))) != MP_OK)
266 return res;
267 }
268
269 return s_rat_reduce(c);
270 }
271
mp_rat_div(mp_rat a,mp_rat b,mp_rat c)272 mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c)
273 {
274 mp_result res = MP_OK;
275
276 if (mp_rat_compare_zero(b) == 0)
277 return MP_UNDEF;
278
279 if (c == a || c == b) {
280 mpz_t tmp;
281
282 if ((res = mp_int_init(&tmp)) != MP_OK) return res;
283 if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), &tmp)) != MP_OK)
284 goto CLEANUP;
285 if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK)
286 goto CLEANUP;
287 res = mp_int_copy(&tmp, MP_NUMER_P(c));
288
289 CLEANUP:
290 mp_int_clear(&tmp);
291 }
292 else {
293 if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), MP_NUMER_P(c))) != MP_OK)
294 return res;
295 if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK)
296 return res;
297 }
298
299 if (res != MP_OK)
300 return res;
301 else
302 return s_rat_reduce(c);
303 }
304
mp_rat_add_int(mp_rat a,mp_int b,mp_rat c)305 mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c)
306 {
307 mpz_t tmp;
308 mp_result res;
309
310 if ((res = mp_int_init_copy(&tmp, b)) != MP_OK)
311 return res;
312
313 if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK)
314 goto CLEANUP;
315
316 if ((res = mp_rat_copy(a, c)) != MP_OK)
317 goto CLEANUP;
318
319 if ((res = mp_int_add(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK)
320 goto CLEANUP;
321
322 res = s_rat_reduce(c);
323
324 CLEANUP:
325 mp_int_clear(&tmp);
326 return res;
327 }
328
mp_rat_sub_int(mp_rat a,mp_int b,mp_rat c)329 mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c)
330 {
331 mpz_t tmp;
332 mp_result res;
333
334 if ((res = mp_int_init_copy(&tmp, b)) != MP_OK)
335 return res;
336
337 if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK)
338 goto CLEANUP;
339
340 if ((res = mp_rat_copy(a, c)) != MP_OK)
341 goto CLEANUP;
342
343 if ((res = mp_int_sub(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK)
344 goto CLEANUP;
345
346 res = s_rat_reduce(c);
347
348 CLEANUP:
349 mp_int_clear(&tmp);
350 return res;
351 }
352
mp_rat_mul_int(mp_rat a,mp_int b,mp_rat c)353 mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c)
354 {
355 mp_result res;
356
357 if ((res = mp_rat_copy(a, c)) != MP_OK)
358 return res;
359
360 if ((res = mp_int_mul(MP_NUMER_P(c), b, MP_NUMER_P(c))) != MP_OK)
361 return res;
362
363 return s_rat_reduce(c);
364 }
365
mp_rat_div_int(mp_rat a,mp_int b,mp_rat c)366 mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c)
367 {
368 mp_result res;
369
370 if (mp_int_compare_zero(b) == 0)
371 return MP_UNDEF;
372
373 if ((res = mp_rat_copy(a, c)) != MP_OK)
374 return res;
375
376 if ((res = mp_int_mul(MP_DENOM_P(c), b, MP_DENOM_P(c))) != MP_OK)
377 return res;
378
379 return s_rat_reduce(c);
380 }
381
mp_rat_expt(mp_rat a,mp_small b,mp_rat c)382 mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c)
383 {
384 mp_result res;
385
386 /* Special cases for easy powers. */
387 if (b == 0)
388 return mp_rat_set_value(c, 1, 1);
389 else if(b == 1)
390 return mp_rat_copy(a, c);
391
392 /* Since rationals are always stored in lowest terms, it is not necessary to
393 reduce again when raising to an integer power. */
394 if ((res = mp_int_expt(MP_NUMER_P(a), b, MP_NUMER_P(c))) != MP_OK)
395 return res;
396
397 return mp_int_expt(MP_DENOM_P(a), b, MP_DENOM_P(c));
398 }
399
mp_rat_compare(mp_rat a,mp_rat b)400 int mp_rat_compare(mp_rat a, mp_rat b)
401 {
402 /* Quick check for opposite signs. Works because the sign of the numerator
403 is always definitive. */
404 if (MP_SIGN(MP_NUMER_P(a)) != MP_SIGN(MP_NUMER_P(b))) {
405 if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS)
406 return 1;
407 else
408 return -1;
409 }
410 else {
411 /* Compare absolute magnitudes; if both are positive, the answer stands,
412 otherwise it needs to be reflected about zero. */
413 int cmp = mp_rat_compare_unsigned(a, b);
414
415 if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS)
416 return cmp;
417 else
418 return -cmp;
419 }
420 }
421
mp_rat_compare_unsigned(mp_rat a,mp_rat b)422 int mp_rat_compare_unsigned(mp_rat a, mp_rat b)
423 {
424 /* If the denominators are equal, we can quickly compare numerators without
425 multiplying. Otherwise, we actually have to do some work. */
426 if (mp_int_compare_unsigned(MP_DENOM_P(a), MP_DENOM_P(b)) == 0)
427 return mp_int_compare_unsigned(MP_NUMER_P(a), MP_NUMER_P(b));
428
429 else {
430 mpz_t temp[2];
431 mp_result res;
432 int cmp = INT_MAX, last = 0;
433
434 /* t0 = num(a) * den(b), t1 = num(b) * den(a) */
435 SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last);
436 SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last);
437
438 if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK ||
439 (res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK)
440 goto CLEANUP;
441
442 cmp = mp_int_compare_unsigned(TEMP(0), TEMP(1));
443
444 CLEANUP:
445 while (--last >= 0)
446 mp_int_clear(TEMP(last));
447
448 return cmp;
449 }
450 }
451
mp_rat_compare_zero(mp_rat r)452 int mp_rat_compare_zero(mp_rat r)
453 {
454 return mp_int_compare_zero(MP_NUMER_P(r));
455 }
456
mp_rat_compare_value(mp_rat r,mp_small n,mp_small d)457 int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d)
458 {
459 mpq_t tmp;
460 mp_result res;
461 int out = INT_MAX;
462
463 if ((res = mp_rat_init(&tmp)) != MP_OK)
464 return out;
465 if ((res = mp_rat_set_value(&tmp, n, d)) != MP_OK)
466 goto CLEANUP;
467
468 out = mp_rat_compare(r, &tmp);
469
470 CLEANUP:
471 mp_rat_clear(&tmp);
472 return out;
473 }
474
mp_rat_is_integer(mp_rat r)475 int mp_rat_is_integer(mp_rat r)
476 {
477 return (mp_int_compare_value(MP_DENOM_P(r), 1) == 0);
478 }
479
mp_rat_to_ints(mp_rat r,mp_small * num,mp_small * den)480 mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den)
481 {
482 mp_result res;
483
484 if ((res = mp_int_to_int(MP_NUMER_P(r), num)) != MP_OK)
485 return res;
486
487 res = mp_int_to_int(MP_DENOM_P(r), den);
488 return res;
489 }
490
mp_rat_to_string(mp_rat r,mp_size radix,char * str,int limit)491 mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit)
492 {
493 char *start;
494 int len;
495 mp_result res;
496
497 /* Write the numerator. The sign of the rational number is written by the
498 underlying integer implementation. */
499 if ((res = mp_int_to_string(MP_NUMER_P(r), radix, str, limit)) != MP_OK)
500 return res;
501
502 /* If the value is zero, don't bother writing any denominator */
503 if (mp_int_compare_zero(MP_NUMER_P(r)) == 0)
504 return MP_OK;
505
506 /* Locate the end of the numerator, and make sure we are not going to exceed
507 the limit by writing a slash. */
508 len = strlen(str);
509 start = str + len;
510 limit -= len;
511 if(limit == 0)
512 return MP_TRUNC;
513
514 *start++ = '/';
515 limit -= 1;
516
517 res = mp_int_to_string(MP_DENOM_P(r), radix, start, limit);
518 return res;
519 }
520
mp_rat_to_decimal(mp_rat r,mp_size radix,mp_size prec,mp_round_mode round,char * str,int limit)521 mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec,
522 mp_round_mode round, char *str, int limit)
523 {
524 mpz_t temp[3];
525 mp_result res;
526 char *start = str;
527 int len, lead_0, left = limit, last = 0;
528
529 SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(r)), last);
530 SETUP(mp_int_init(TEMP(last)), last);
531 SETUP(mp_int_init(TEMP(last)), last);
532
533 /* Get the unsigned integer part by dividing denominator into the absolute
534 value of the numerator. */
535 mp_int_abs(TEMP(0), TEMP(0));
536 if ((res = mp_int_div(TEMP(0), MP_DENOM_P(r), TEMP(0), TEMP(1))) != MP_OK)
537 goto CLEANUP;
538
539 /* Now: T0 = integer portion, unsigned;
540 T1 = remainder, from which fractional part is computed. */
541
542 /* Count up leading zeroes after the radix point. */
543 for (lead_0 = 0; lead_0 < prec && mp_int_compare(TEMP(1), MP_DENOM_P(r)) < 0;
544 ++lead_0) {
545 if ((res = mp_int_mul_value(TEMP(1), radix, TEMP(1))) != MP_OK)
546 goto CLEANUP;
547 }
548
549 /* Multiply remainder by a power of the radix sufficient to get the right
550 number of significant figures. */
551 if (prec > lead_0) {
552 if ((res = mp_int_expt_value(radix, prec - lead_0, TEMP(2))) != MP_OK)
553 goto CLEANUP;
554 if ((res = mp_int_mul(TEMP(1), TEMP(2), TEMP(1))) != MP_OK)
555 goto CLEANUP;
556 }
557 if ((res = mp_int_div(TEMP(1), MP_DENOM_P(r), TEMP(1), TEMP(2))) != MP_OK)
558 goto CLEANUP;
559
560 /* Now: T1 = significant digits of fractional part;
561 T2 = leftovers, to use for rounding.
562
563 At this point, what we do depends on the rounding mode. The default is
564 MP_ROUND_DOWN, for which everything is as it should be already.
565 */
566 switch (round) {
567 int cmp;
568
569 case MP_ROUND_UP:
570 if (mp_int_compare_zero(TEMP(2)) != 0) {
571 if (prec == 0)
572 res = mp_int_add_value(TEMP(0), 1, TEMP(0));
573 else
574 res = mp_int_add_value(TEMP(1), 1, TEMP(1));
575 }
576 break;
577
578 case MP_ROUND_HALF_UP:
579 case MP_ROUND_HALF_DOWN:
580 if ((res = mp_int_mul_pow2(TEMP(2), 1, TEMP(2))) != MP_OK)
581 goto CLEANUP;
582
583 cmp = mp_int_compare(TEMP(2), MP_DENOM_P(r));
584
585 if (round == MP_ROUND_HALF_UP)
586 cmp += 1;
587
588 if (cmp > 0) {
589 if (prec == 0)
590 res = mp_int_add_value(TEMP(0), 1, TEMP(0));
591 else
592 res = mp_int_add_value(TEMP(1), 1, TEMP(1));
593 }
594 break;
595
596 case MP_ROUND_DOWN:
597 break; /* No action required */
598
599 default:
600 return MP_BADARG; /* Invalid rounding specifier */
601 }
602
603 /* The sign of the output should be the sign of the numerator, but if all the
604 displayed digits will be zero due to the precision, a negative shouldn't
605 be shown. */
606 if (MP_SIGN(MP_NUMER_P(r)) == MP_NEG &&
607 (mp_int_compare_zero(TEMP(0)) != 0 ||
608 mp_int_compare_zero(TEMP(1)) != 0)) {
609 *start++ = '-';
610 left -= 1;
611 }
612
613 if ((res = mp_int_to_string(TEMP(0), radix, start, left)) != MP_OK)
614 goto CLEANUP;
615
616 len = strlen(start);
617 start += len;
618 left -= len;
619
620 if (prec == 0)
621 goto CLEANUP;
622
623 *start++ = '.';
624 left -= 1;
625
626 if (left < prec + 1) {
627 res = MP_TRUNC;
628 goto CLEANUP;
629 }
630
631 memset(start, '0', lead_0 - 1);
632 left -= lead_0;
633 start += lead_0 - 1;
634
635 res = mp_int_to_string(TEMP(1), radix, start, left);
636
637 CLEANUP:
638 while (--last >= 0)
639 mp_int_clear(TEMP(last));
640
641 return res;
642 }
643
mp_rat_string_len(mp_rat r,mp_size radix)644 mp_result mp_rat_string_len(mp_rat r, mp_size radix)
645 {
646 mp_result n_len, d_len = 0;
647
648 n_len = mp_int_string_len(MP_NUMER_P(r), radix);
649
650 if (mp_int_compare_zero(MP_NUMER_P(r)) != 0)
651 d_len = mp_int_string_len(MP_DENOM_P(r), radix);
652
653 /* Though simplistic, this formula is correct. Space for the sign flag is
654 included in n_len, and the space for the NUL that is counted in n_len
655 counts for the separator here. The space for the NUL counted in d_len
656 counts for the final terminator here. */
657
658 return n_len + d_len;
659
660 }
661
mp_rat_decimal_len(mp_rat r,mp_size radix,mp_size prec)662 mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec)
663 {
664 int z_len, f_len;
665
666 z_len = mp_int_string_len(MP_NUMER_P(r), radix);
667
668 if (prec == 0)
669 f_len = 1; /* terminator only */
670 else
671 f_len = 1 + prec + 1; /* decimal point, digits, terminator */
672
673 return z_len + f_len;
674 }
675
mp_rat_read_string(mp_rat r,mp_size radix,const char * str)676 mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str)
677 {
678 return mp_rat_read_cstring(r, radix, str, NULL);
679 }
680
mp_rat_read_cstring(mp_rat r,mp_size radix,const char * str,char ** end)681 mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str,
682 char **end)
683 {
684 mp_result res;
685 char *endp;
686
687 if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK &&
688 (res != MP_TRUNC))
689 return res;
690
691 /* Skip whitespace between numerator and (possible) separator */
692 while (isspace((unsigned char) *endp))
693 ++endp;
694
695 /* If there is no separator, we will stop reading at this point. */
696 if (*endp != '/') {
697 mp_int_set_value(MP_DENOM_P(r), 1);
698 if (end != NULL)
699 *end = endp;
700 return res;
701 }
702
703 ++endp; /* skip separator */
704 if ((res = mp_int_read_cstring(MP_DENOM_P(r), radix, endp, end)) != MP_OK)
705 return res;
706
707 /* Make sure the value is well-defined */
708 if (mp_int_compare_zero(MP_DENOM_P(r)) == 0)
709 return MP_UNDEF;
710
711 /* Reduce to lowest terms */
712 return s_rat_reduce(r);
713 }
714
715 /* Read a string and figure out what format it's in. The radix may be supplied
716 as zero to use "default" behaviour.
717
718 This function will accept either a/b notation or decimal notation.
719 */
mp_rat_read_ustring(mp_rat r,mp_size radix,const char * str,char ** end)720 mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str,
721 char **end)
722 {
723 char *endp;
724 mp_result res;
725
726 if (radix == 0)
727 radix = 10; /* default to decimal input */
728
729 if ((res = mp_rat_read_cstring(r, radix, str, &endp)) != MP_OK) {
730 if (res == MP_TRUNC) {
731 if (*endp == '.')
732 res = mp_rat_read_cdecimal(r, radix, str, &endp);
733 }
734 else
735 return res;
736 }
737
738 if (end != NULL)
739 *end = endp;
740
741 return res;
742 }
743
mp_rat_read_decimal(mp_rat r,mp_size radix,const char * str)744 mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str)
745 {
746 return mp_rat_read_cdecimal(r, radix, str, NULL);
747 }
748
mp_rat_read_cdecimal(mp_rat r,mp_size radix,const char * str,char ** end)749 mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str,
750 char **end)
751 {
752 mp_result res;
753 mp_sign osign;
754 char *endp;
755
756 while (isspace((unsigned char) *str))
757 ++str;
758
759 switch (*str) {
760 case '-':
761 osign = MP_NEG;
762 break;
763 default:
764 osign = MP_ZPOS;
765 }
766
767 if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK &&
768 (res != MP_TRUNC))
769 return res;
770
771 /* This needs to be here. */
772 (void) mp_int_set_value(MP_DENOM_P(r), 1);
773
774 if (*endp != '.') {
775 if (end != NULL)
776 *end = endp;
777 return res;
778 }
779
780 /* If the character following the decimal point is whitespace or a sign flag,
781 we will consider this a truncated value. This special case is because
782 mp_int_read_string() will consider whitespace or sign flags to be valid
783 starting characters for a value, and we do not want them following the
784 decimal point.
785
786 Once we have done this check, it is safe to read in the value of the
787 fractional piece as a regular old integer.
788 */
789 ++endp;
790 if (*endp == '\0') {
791 if (end != NULL)
792 *end = endp;
793 return MP_OK;
794 }
795 else if(isspace((unsigned char) *endp) || *endp == '-' || *endp == '+') {
796 return MP_TRUNC;
797 }
798 else {
799 mpz_t frac;
800 mp_result save_res;
801 char *save = endp;
802 int num_lz = 0;
803
804 /* Make a temporary to hold the part after the decimal point. */
805 if ((res = mp_int_init(&frac)) != MP_OK)
806 return res;
807
808 if ((res = mp_int_read_cstring(&frac, radix, endp, &endp)) != MP_OK &&
809 (res != MP_TRUNC))
810 goto CLEANUP;
811
812 /* Save this response for later. */
813 save_res = res;
814
815 if (mp_int_compare_zero(&frac) == 0)
816 goto FINISHED;
817
818 /* Discard trailing zeroes (somewhat inefficiently) */
819 while (mp_int_divisible_value(&frac, radix))
820 if ((res = mp_int_div_value(&frac, radix, &frac, NULL)) != MP_OK)
821 goto CLEANUP;
822
823 /* Count leading zeros after the decimal point */
824 while (save[num_lz] == '0')
825 ++num_lz;
826
827 /* Find the least power of the radix that is at least as large as the
828 significant value of the fractional part, ignoring leading zeroes. */
829 (void) mp_int_set_value(MP_DENOM_P(r), radix);
830
831 while (mp_int_compare(MP_DENOM_P(r), &frac) < 0) {
832 if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK)
833 goto CLEANUP;
834 }
835
836 /* Also shift by enough to account for leading zeroes */
837 while (num_lz > 0) {
838 if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK)
839 goto CLEANUP;
840
841 --num_lz;
842 }
843
844 /* Having found this power, shift the numerator leftward that many, digits,
845 and add the nonzero significant digits of the fractional part to get the
846 result. */
847 if ((res = mp_int_mul(MP_NUMER_P(r), MP_DENOM_P(r), MP_NUMER_P(r))) != MP_OK)
848 goto CLEANUP;
849
850 { /* This addition needs to be unsigned. */
851 MP_SIGN(MP_NUMER_P(r)) = MP_ZPOS;
852 if ((res = mp_int_add(MP_NUMER_P(r), &frac, MP_NUMER_P(r))) != MP_OK)
853 goto CLEANUP;
854
855 MP_SIGN(MP_NUMER_P(r)) = osign;
856 }
857 if ((res = s_rat_reduce(r)) != MP_OK)
858 goto CLEANUP;
859
860 /* At this point, what we return depends on whether reading the fractional
861 part was truncated or not. That information is saved from when we
862 called mp_int_read_string() above. */
863 FINISHED:
864 res = save_res;
865 if (end != NULL)
866 *end = endp;
867
868 CLEANUP:
869 mp_int_clear(&frac);
870
871 return res;
872 }
873 }
874
875 /* Private functions for internal use. Make unchecked assumptions about format
876 and validity of inputs. */
877
s_rat_reduce(mp_rat r)878 static mp_result s_rat_reduce(mp_rat r)
879 {
880 mpz_t gcd;
881 mp_result res = MP_OK;
882
883 if (mp_int_compare_zero(MP_NUMER_P(r)) == 0) {
884 mp_int_set_value(MP_DENOM_P(r), 1);
885 return MP_OK;
886 }
887
888 /* If the greatest common divisor of the numerator and denominator is greater
889 than 1, divide it out. */
890 if ((res = mp_int_init(&gcd)) != MP_OK)
891 return res;
892
893 if ((res = mp_int_gcd(MP_NUMER_P(r), MP_DENOM_P(r), &gcd)) != MP_OK)
894 goto CLEANUP;
895
896 if (mp_int_compare_value(&gcd, 1) != 0) {
897 if ((res = mp_int_div(MP_NUMER_P(r), &gcd, MP_NUMER_P(r), NULL)) != MP_OK)
898 goto CLEANUP;
899 if ((res = mp_int_div(MP_DENOM_P(r), &gcd, MP_DENOM_P(r), NULL)) != MP_OK)
900 goto CLEANUP;
901 }
902
903 /* Fix up the signs of numerator and denominator */
904 if (MP_SIGN(MP_NUMER_P(r)) == MP_SIGN(MP_DENOM_P(r)))
905 MP_SIGN(MP_NUMER_P(r)) = MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS;
906 else {
907 MP_SIGN(MP_NUMER_P(r)) = MP_NEG;
908 MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS;
909 }
910
911 CLEANUP:
912 mp_int_clear(&gcd);
913
914 return res;
915 }
916
s_rat_combine(mp_rat a,mp_rat b,mp_rat c,mp_result (* comb_f)(mp_int,mp_int,mp_int))917 static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c,
918 mp_result (*comb_f)(mp_int, mp_int, mp_int))
919 {
920 mp_result res;
921
922 /* Shortcut when denominators are already common */
923 if (mp_int_compare(MP_DENOM_P(a), MP_DENOM_P(b)) == 0) {
924 if ((res = (comb_f)(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK)
925 return res;
926 if ((res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c))) != MP_OK)
927 return res;
928
929 return s_rat_reduce(c);
930 }
931 else {
932 mpz_t temp[2];
933 int last = 0;
934
935 SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last);
936 SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last);
937
938 if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK)
939 goto CLEANUP;
940 if ((res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK)
941 goto CLEANUP;
942 if ((res = (comb_f)(TEMP(0), TEMP(1), MP_NUMER_P(c))) != MP_OK)
943 goto CLEANUP;
944
945 res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c));
946
947 CLEANUP:
948 while (--last >= 0)
949 mp_int_clear(TEMP(last));
950
951 if (res == MP_OK)
952 return s_rat_reduce(c);
953 else
954 return res;
955 }
956 }
957
958 /* Here there be dragons */
959