div.c revision 1.1.1.1.8.1 1 1.1 mrg /* mpq_div -- divide two rational numbers.
2 1.1 mrg
3 1.1 mrg Copyright 1991, 1994, 1995, 1996, 2000, 2001 Free Software Foundation, Inc.
4 1.1 mrg
5 1.1 mrg This file is part of the GNU MP Library.
6 1.1 mrg
7 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
8 1.1 mrg it under the terms of the GNU Lesser General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3 of the License, or (at your
10 1.1 mrg option) any later version.
11 1.1 mrg
12 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
13 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 1.1 mrg License for more details.
16 1.1 mrg
17 1.1 mrg You should have received a copy of the GNU Lesser General Public License
18 1.1 mrg along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
19 1.1 mrg
20 1.1 mrg #include "gmp.h"
21 1.1 mrg #include "gmp-impl.h"
22 1.1 mrg
23 1.1 mrg
24 1.1 mrg void
25 1.1 mrg mpq_div (mpq_ptr quot, mpq_srcptr op1, mpq_srcptr op2)
26 1.1 mrg {
27 1.1 mrg mpz_t gcd1, gcd2;
28 1.1 mrg mpz_t tmp1, tmp2;
29 1.1 mrg mpz_t numtmp;
30 1.1 mrg mp_size_t op1_num_size;
31 1.1 mrg mp_size_t op1_den_size;
32 1.1 mrg mp_size_t op2_num_size;
33 1.1 mrg mp_size_t op2_den_size;
34 1.1 mrg mp_size_t alloc;
35 1.1 mrg TMP_DECL;
36 1.1 mrg
37 1.1.1.1.8.1 tls op2_num_size = ABSIZ(NUM(op2));
38 1.1 mrg
39 1.1.1.1.8.1 tls if (UNLIKELY (op2_num_size == 0))
40 1.1 mrg DIVIDE_BY_ZERO;
41 1.1 mrg
42 1.1.1.1.8.1 tls op1_num_size = ABSIZ(NUM(op1));
43 1.1.1.1.8.1 tls
44 1.1 mrg if (op1_num_size == 0)
45 1.1 mrg {
46 1.1 mrg /* We special case this to simplify allocation logic; gcd(0,x) = x
47 1.1 mrg is a singular case for the allocations. */
48 1.1.1.1.8.1 tls SIZ(NUM(quot)) = 0;
49 1.1.1.1.8.1 tls PTR(DEN(quot))[0] = 1;
50 1.1.1.1.8.1 tls SIZ(DEN(quot)) = 1;
51 1.1 mrg return;
52 1.1 mrg }
53 1.1 mrg
54 1.1.1.1.8.1 tls op2_den_size = SIZ(DEN(op2));
55 1.1.1.1.8.1 tls op1_den_size = SIZ(DEN(op1));
56 1.1.1.1.8.1 tls
57 1.1 mrg TMP_MARK;
58 1.1 mrg
59 1.1 mrg alloc = MIN (op1_num_size, op2_num_size);
60 1.1 mrg MPZ_TMP_INIT (gcd1, alloc);
61 1.1 mrg
62 1.1 mrg alloc = MIN (op1_den_size, op2_den_size);
63 1.1 mrg MPZ_TMP_INIT (gcd2, alloc);
64 1.1 mrg
65 1.1 mrg alloc = MAX (op1_num_size, op2_num_size);
66 1.1 mrg MPZ_TMP_INIT (tmp1, alloc);
67 1.1 mrg
68 1.1 mrg alloc = MAX (op1_den_size, op2_den_size);
69 1.1 mrg MPZ_TMP_INIT (tmp2, alloc);
70 1.1 mrg
71 1.1 mrg alloc = op1_num_size + op2_den_size;
72 1.1 mrg MPZ_TMP_INIT (numtmp, alloc);
73 1.1 mrg
74 1.1 mrg /* QUOT might be identical to either operand, so don't store the result there
75 1.1 mrg until we are finished with the input operands. We can overwrite the
76 1.1 mrg numerator of QUOT when we are finished with the numerators of OP1 and
77 1.1 mrg OP2. */
78 1.1 mrg
79 1.1.1.1.8.1 tls mpz_gcd (gcd1, NUM(op1), NUM(op2));
80 1.1.1.1.8.1 tls mpz_gcd (gcd2, DEN(op2), DEN(op1));
81 1.1 mrg
82 1.1.1.1.8.1 tls mpz_divexact_gcd (tmp1, NUM(op1), gcd1);
83 1.1.1.1.8.1 tls mpz_divexact_gcd (tmp2, DEN(op2), gcd2);
84 1.1 mrg
85 1.1 mrg mpz_mul (numtmp, tmp1, tmp2);
86 1.1 mrg
87 1.1.1.1.8.1 tls mpz_divexact_gcd (tmp1, NUM(op2), gcd1);
88 1.1.1.1.8.1 tls mpz_divexact_gcd (tmp2, DEN(op1), gcd2);
89 1.1 mrg
90 1.1.1.1.8.1 tls mpz_mul (DEN(quot), tmp1, tmp2);
91 1.1 mrg
92 1.1 mrg /* We needed to go via NUMTMP to take care of QUOT being the same as OP2.
93 1.1 mrg Now move NUMTMP to QUOT->_mp_num. */
94 1.1.1.1.8.1 tls mpz_set (NUM(quot), numtmp);
95 1.1 mrg
96 1.1 mrg /* Keep the denominator positive. */
97 1.1.1.1.8.1 tls if (SIZ(DEN(quot)) < 0)
98 1.1 mrg {
99 1.1.1.1.8.1 tls SIZ(DEN(quot)) = -SIZ(DEN(quot));
100 1.1.1.1.8.1 tls SIZ(NUM(quot)) = -SIZ(NUM(quot));
101 1.1 mrg }
102 1.1 mrg
103 1.1 mrg TMP_FREE;
104 1.1 mrg }
105