blob: e86af94a5e7c8a9415fbb38ef65b66f81705c523 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* mpq_add, mpq_sub -- add or subtract rational numbers.
2
3Copyright 1991, 1994-1997, 2000, 2001, 2004, 2005 Free Software Foundation,
4Inc.
5
6This file is part of the GNU MP Library.
7
8The GNU MP Library is free software; you can redistribute it and/or modify
9it under the terms of either:
10
11 * the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
14
15or
16
17 * the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any
19 later version.
20
21or both in parallel, as here.
22
23The GNU MP Library is distributed in the hope that it will be useful, but
24WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26for more details.
27
28You should have received copies of the GNU General Public License and the
29GNU Lesser General Public License along with the GNU MP Library. If not,
30see https://www.gnu.org/licenses/. */
31
32#include "gmp-impl.h"
33
34
35static void __gmpq_aors (REGPARM_3_1 (mpq_ptr, mpq_srcptr, mpq_srcptr, void (*) (mpz_ptr, mpz_srcptr, mpz_srcptr))) REGPARM_ATTR (1);
36#define mpq_aors(w,x,y,fun) __gmpq_aors (REGPARM_3_1 (w, x, y, fun))
37
38REGPARM_ATTR (1) static void
39mpq_aors (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2,
40 void (*fun) (mpz_ptr, mpz_srcptr, mpz_srcptr))
41{
42 mpz_t gcd;
43 mpz_t tmp1, tmp2;
44 mp_size_t op1_num_size = ABSIZ(NUM(op1));
45 mp_size_t op1_den_size = SIZ(DEN(op1));
46 mp_size_t op2_num_size = ABSIZ(NUM(op2));
47 mp_size_t op2_den_size = SIZ(DEN(op2));
48 TMP_DECL;
49
50 TMP_MARK;
51 MPZ_TMP_INIT (gcd, MIN (op1_den_size, op2_den_size));
52 MPZ_TMP_INIT (tmp1, op1_num_size + op2_den_size);
53 MPZ_TMP_INIT (tmp2, op2_num_size + op1_den_size);
54
55 /* ROP might be identical to either operand, so don't store the
56 result there until we are finished with the input operands. We
57 dare to overwrite the numerator of ROP when we are finished
58 with the numerators of OP1 and OP2. */
59
60 mpz_gcd (gcd, DEN(op1), DEN(op2));
61 if (! MPZ_EQUAL_1_P (gcd))
62 {
63 mpz_t t;
64
65 MPZ_TMP_INIT (t, MAX (op1_num_size + op2_den_size,
66 op2_num_size + op1_den_size) + 2 - SIZ(gcd));
67
68 mpz_divexact_gcd (t, DEN(op2), gcd);
69 mpz_divexact_gcd (tmp2, DEN(op1), gcd);
70
71 mpz_mul (tmp1, NUM(op1), t);
72 mpz_mul (t, NUM(op2), tmp2);
73
74 (*fun) (t, tmp1, t);
75
76 mpz_gcd (gcd, t, gcd);
77 if (MPZ_EQUAL_1_P (gcd))
78 {
79 mpz_set (NUM(rop), t);
80 mpz_mul (DEN(rop), DEN(op2), tmp2);
81 }
82 else
83 {
84 mpz_divexact_gcd (NUM(rop), t, gcd);
85 mpz_divexact_gcd (tmp1, DEN(op2), gcd);
86 mpz_mul (DEN(rop), tmp1, tmp2);
87 }
88 }
89 else
90 {
91 /* The common divisor is 1. This is the case (for random input) with
92 probability 6/(pi**2), which is about 60.8%. */
93 mpz_mul (tmp1, NUM(op1), DEN(op2));
94 mpz_mul (tmp2, NUM(op2), DEN(op1));
95 (*fun) (NUM(rop), tmp1, tmp2);
96 mpz_mul (DEN(rop), DEN(op1), DEN(op2));
97 }
98 TMP_FREE;
99}
100
101
102void
103mpq_add (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
104{
105 mpq_aors (rop, op1, op2, mpz_add);
106}
107
108void
109mpq_sub (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
110{
111 mpq_aors (rop, op1, op2, mpz_sub);
112}