1 1.1 mrg /* mpq_div -- divide two rational numbers. 2 1.1 mrg 3 1.1.1.4 mrg Copyright 1991, 1994-1996, 2000, 2001, 2015, 2018 Free Software 4 1.1.1.4 mrg Foundation, Inc. 5 1.1 mrg 6 1.1 mrg This file is part of the GNU MP Library. 7 1.1 mrg 8 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify 9 1.1.1.3 mrg it under the terms of either: 10 1.1.1.3 mrg 11 1.1.1.3 mrg * the GNU Lesser General Public License as published by the Free 12 1.1.1.3 mrg Software Foundation; either version 3 of the License, or (at your 13 1.1.1.3 mrg option) any later version. 14 1.1.1.3 mrg 15 1.1.1.3 mrg or 16 1.1.1.3 mrg 17 1.1.1.3 mrg * the GNU General Public License as published by the Free Software 18 1.1.1.3 mrg Foundation; either version 2 of the License, or (at your option) any 19 1.1.1.3 mrg later version. 20 1.1.1.3 mrg 21 1.1.1.3 mrg or both in parallel, as here. 22 1.1 mrg 23 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but 24 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 25 1.1.1.3 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26 1.1.1.3 mrg for more details. 27 1.1 mrg 28 1.1.1.3 mrg You should have received copies of the GNU General Public License and the 29 1.1.1.3 mrg GNU Lesser General Public License along with the GNU MP Library. If not, 30 1.1.1.3 mrg see https://www.gnu.org/licenses/. */ 31 1.1 mrg 32 1.1 mrg #include "gmp-impl.h" 33 1.1 mrg 34 1.1 mrg 35 1.1 mrg void 36 1.1 mrg mpq_div (mpq_ptr quot, mpq_srcptr op1, mpq_srcptr op2) 37 1.1 mrg { 38 1.1 mrg mpz_t gcd1, gcd2; 39 1.1 mrg mpz_t tmp1, tmp2; 40 1.1.1.3 mrg mp_size_t op1_size; 41 1.1.1.3 mrg mp_size_t op2_size; 42 1.1 mrg mp_size_t alloc; 43 1.1 mrg TMP_DECL; 44 1.1 mrg 45 1.1.1.3 mrg op2_size = SIZ(NUM(op2)); 46 1.1 mrg 47 1.1.1.3 mrg if (UNLIKELY (op2_size == 0)) 48 1.1 mrg DIVIDE_BY_ZERO; 49 1.1 mrg 50 1.1.1.3 mrg if (UNLIKELY (quot == op2)) 51 1.1.1.3 mrg { 52 1.1.1.4 mrg if (UNLIKELY (op1 == op2)) 53 1.1.1.3 mrg { 54 1.1.1.4 mrg mpq_set_ui (quot, 1, 1); 55 1.1.1.3 mrg return; 56 1.1.1.3 mrg } 57 1.1.1.3 mrg 58 1.1.1.3 mrg /* We checked for op1 == op2: we are not in the x=x/x case. 59 1.1.1.3 mrg We compute x=y/x by computing x=inv(x)*y */ 60 1.1.1.3 mrg MPN_PTR_SWAP (PTR(NUM(quot)), ALLOC(NUM(quot)), 61 1.1.1.3 mrg PTR(DEN(quot)), ALLOC(DEN(quot))); 62 1.1.1.3 mrg if (op2_size > 0) 63 1.1.1.3 mrg { 64 1.1.1.3 mrg SIZ(NUM(quot)) = SIZ(DEN(quot)); 65 1.1.1.3 mrg SIZ(DEN(quot)) = op2_size; 66 1.1.1.3 mrg } 67 1.1.1.3 mrg else 68 1.1.1.3 mrg { 69 1.1.1.3 mrg SIZ(NUM(quot)) = - SIZ(DEN(quot)); 70 1.1.1.3 mrg SIZ(DEN(quot)) = - op2_size; 71 1.1.1.3 mrg } 72 1.1.1.3 mrg mpq_mul (quot, quot, op1); 73 1.1.1.3 mrg return; 74 1.1.1.3 mrg } 75 1.1.1.3 mrg 76 1.1.1.3 mrg op1_size = ABSIZ(NUM(op1)); 77 1.1.1.2 mrg 78 1.1.1.3 mrg if (op1_size == 0) 79 1.1 mrg { 80 1.1 mrg /* We special case this to simplify allocation logic; gcd(0,x) = x 81 1.1 mrg is a singular case for the allocations. */ 82 1.1.1.2 mrg SIZ(NUM(quot)) = 0; 83 1.1.1.4 mrg MPZ_NEWALLOC (DEN(quot), 1)[0] = 1; 84 1.1.1.2 mrg SIZ(DEN(quot)) = 1; 85 1.1 mrg return; 86 1.1 mrg } 87 1.1 mrg 88 1.1.1.3 mrg op2_size = ABS(op2_size); 89 1.1.1.2 mrg 90 1.1 mrg TMP_MARK; 91 1.1 mrg 92 1.1.1.3 mrg alloc = MIN (op1_size, op2_size); 93 1.1 mrg MPZ_TMP_INIT (gcd1, alloc); 94 1.1 mrg 95 1.1.1.3 mrg alloc = MAX (op1_size, op2_size); 96 1.1 mrg MPZ_TMP_INIT (tmp1, alloc); 97 1.1 mrg 98 1.1.1.3 mrg op2_size = SIZ(DEN(op2)); 99 1.1.1.3 mrg op1_size = SIZ(DEN(op1)); 100 1.1 mrg 101 1.1.1.3 mrg alloc = MIN (op1_size, op2_size); 102 1.1.1.3 mrg MPZ_TMP_INIT (gcd2, alloc); 103 1.1 mrg 104 1.1.1.3 mrg alloc = MAX (op1_size, op2_size); 105 1.1.1.3 mrg MPZ_TMP_INIT (tmp2, alloc); 106 1.1.1.3 mrg 107 1.1.1.3 mrg /* QUOT might be identical to OP1, so don't store the result there 108 1.1.1.3 mrg until we are finished with the input operand. We can overwrite 109 1.1.1.3 mrg the numerator of QUOT when we are finished with the numerator of 110 1.1.1.3 mrg OP1. */ 111 1.1 mrg 112 1.1.1.2 mrg mpz_gcd (gcd1, NUM(op1), NUM(op2)); 113 1.1.1.2 mrg mpz_gcd (gcd2, DEN(op2), DEN(op1)); 114 1.1 mrg 115 1.1.1.2 mrg mpz_divexact_gcd (tmp1, NUM(op1), gcd1); 116 1.1.1.2 mrg mpz_divexact_gcd (tmp2, DEN(op2), gcd2); 117 1.1 mrg 118 1.1.1.3 mrg mpz_mul (NUM(quot), tmp1, tmp2); 119 1.1 mrg 120 1.1.1.2 mrg mpz_divexact_gcd (tmp1, NUM(op2), gcd1); 121 1.1.1.2 mrg mpz_divexact_gcd (tmp2, DEN(op1), gcd2); 122 1.1 mrg 123 1.1.1.2 mrg mpz_mul (DEN(quot), tmp1, tmp2); 124 1.1 mrg 125 1.1 mrg /* Keep the denominator positive. */ 126 1.1.1.2 mrg if (SIZ(DEN(quot)) < 0) 127 1.1 mrg { 128 1.1.1.2 mrg SIZ(DEN(quot)) = -SIZ(DEN(quot)); 129 1.1.1.2 mrg SIZ(NUM(quot)) = -SIZ(NUM(quot)); 130 1.1 mrg } 131 1.1 mrg 132 1.1 mrg TMP_FREE; 133 1.1 mrg } 134