186d7f5d3SJohn Marino /* mpq_div -- divide two rational numbers.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright 1991, 1994, 1995, 1996, 2000, 2001 Free Software Foundation, Inc.
486d7f5d3SJohn Marino
586d7f5d3SJohn Marino This file is part of the GNU MP Library.
686d7f5d3SJohn Marino
786d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
886d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
986d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1086d7f5d3SJohn Marino option) any later version.
1186d7f5d3SJohn Marino
1286d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1386d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1486d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
1586d7f5d3SJohn Marino License for more details.
1686d7f5d3SJohn Marino
1786d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
1886d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
1986d7f5d3SJohn Marino
2086d7f5d3SJohn Marino #include "gmp.h"
2186d7f5d3SJohn Marino #include "gmp-impl.h"
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino
2486d7f5d3SJohn Marino void
mpq_div(mpq_ptr quot,mpq_srcptr op1,mpq_srcptr op2)2586d7f5d3SJohn Marino mpq_div (mpq_ptr quot, mpq_srcptr op1, mpq_srcptr op2)
2686d7f5d3SJohn Marino {
2786d7f5d3SJohn Marino mpz_t gcd1, gcd2;
2886d7f5d3SJohn Marino mpz_t tmp1, tmp2;
2986d7f5d3SJohn Marino mpz_t numtmp;
3086d7f5d3SJohn Marino mp_size_t op1_num_size;
3186d7f5d3SJohn Marino mp_size_t op1_den_size;
3286d7f5d3SJohn Marino mp_size_t op2_num_size;
3386d7f5d3SJohn Marino mp_size_t op2_den_size;
3486d7f5d3SJohn Marino mp_size_t alloc;
3586d7f5d3SJohn Marino TMP_DECL;
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marino op1_num_size = ABS (op1->_mp_num._mp_size);
3886d7f5d3SJohn Marino op1_den_size = op1->_mp_den._mp_size;
3986d7f5d3SJohn Marino op2_num_size = ABS (op2->_mp_num._mp_size);
4086d7f5d3SJohn Marino op2_den_size = op2->_mp_den._mp_size;
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino if (op2_num_size == 0)
4386d7f5d3SJohn Marino DIVIDE_BY_ZERO;
4486d7f5d3SJohn Marino
4586d7f5d3SJohn Marino if (op1_num_size == 0)
4686d7f5d3SJohn Marino {
4786d7f5d3SJohn Marino /* We special case this to simplify allocation logic; gcd(0,x) = x
4886d7f5d3SJohn Marino is a singular case for the allocations. */
4986d7f5d3SJohn Marino quot->_mp_num._mp_size = 0;
5086d7f5d3SJohn Marino quot->_mp_den._mp_d[0] = 1;
5186d7f5d3SJohn Marino quot->_mp_den._mp_size = 1;
5286d7f5d3SJohn Marino return;
5386d7f5d3SJohn Marino }
5486d7f5d3SJohn Marino
5586d7f5d3SJohn Marino TMP_MARK;
5686d7f5d3SJohn Marino
5786d7f5d3SJohn Marino alloc = MIN (op1_num_size, op2_num_size);
5886d7f5d3SJohn Marino MPZ_TMP_INIT (gcd1, alloc);
5986d7f5d3SJohn Marino
6086d7f5d3SJohn Marino alloc = MIN (op1_den_size, op2_den_size);
6186d7f5d3SJohn Marino MPZ_TMP_INIT (gcd2, alloc);
6286d7f5d3SJohn Marino
6386d7f5d3SJohn Marino alloc = MAX (op1_num_size, op2_num_size);
6486d7f5d3SJohn Marino MPZ_TMP_INIT (tmp1, alloc);
6586d7f5d3SJohn Marino
6686d7f5d3SJohn Marino alloc = MAX (op1_den_size, op2_den_size);
6786d7f5d3SJohn Marino MPZ_TMP_INIT (tmp2, alloc);
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino alloc = op1_num_size + op2_den_size;
7086d7f5d3SJohn Marino MPZ_TMP_INIT (numtmp, alloc);
7186d7f5d3SJohn Marino
7286d7f5d3SJohn Marino /* QUOT might be identical to either operand, so don't store the result there
7386d7f5d3SJohn Marino until we are finished with the input operands. We can overwrite the
7486d7f5d3SJohn Marino numerator of QUOT when we are finished with the numerators of OP1 and
7586d7f5d3SJohn Marino OP2. */
7686d7f5d3SJohn Marino
7786d7f5d3SJohn Marino mpz_gcd (gcd1, &(op1->_mp_num), &(op2->_mp_num));
7886d7f5d3SJohn Marino mpz_gcd (gcd2, &(op2->_mp_den), &(op1->_mp_den));
7986d7f5d3SJohn Marino
8086d7f5d3SJohn Marino mpz_divexact_gcd (tmp1, &(op1->_mp_num), gcd1);
8186d7f5d3SJohn Marino mpz_divexact_gcd (tmp2, &(op2->_mp_den), gcd2);
8286d7f5d3SJohn Marino
8386d7f5d3SJohn Marino mpz_mul (numtmp, tmp1, tmp2);
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino mpz_divexact_gcd (tmp1, &(op2->_mp_num), gcd1);
8686d7f5d3SJohn Marino mpz_divexact_gcd (tmp2, &(op1->_mp_den), gcd2);
8786d7f5d3SJohn Marino
8886d7f5d3SJohn Marino mpz_mul (&(quot->_mp_den), tmp1, tmp2);
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino /* We needed to go via NUMTMP to take care of QUOT being the same as OP2.
9186d7f5d3SJohn Marino Now move NUMTMP to QUOT->_mp_num. */
9286d7f5d3SJohn Marino mpz_set (&(quot->_mp_num), numtmp);
9386d7f5d3SJohn Marino
9486d7f5d3SJohn Marino /* Keep the denominator positive. */
9586d7f5d3SJohn Marino if (quot->_mp_den._mp_size < 0)
9686d7f5d3SJohn Marino {
9786d7f5d3SJohn Marino quot->_mp_den._mp_size = -quot->_mp_den._mp_size;
9886d7f5d3SJohn Marino quot->_mp_num._mp_size = -quot->_mp_num._mp_size;
9986d7f5d3SJohn Marino }
10086d7f5d3SJohn Marino
10186d7f5d3SJohn Marino TMP_FREE;
10286d7f5d3SJohn Marino }
103