Austin Schuh | dace2a6 | 2020-08-18 10:56:48 -0700 | [diff] [blame^] | 1 | /* mpq_cmp(u,v) -- Compare U, V. Return positive, zero, or negative |
| 2 | based on if U > V, U == V, or U < V. |
| 3 | |
| 4 | Copyright 1991, 1994, 1996, 2001, 2002, 2005, 2015 Free Software Foundation, Inc. |
| 5 | |
| 6 | This file is part of the GNU MP Library. |
| 7 | |
| 8 | The GNU MP Library is free software; you can redistribute it and/or modify |
| 9 | it 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 | |
| 15 | or |
| 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 | |
| 21 | or both in parallel, as here. |
| 22 | |
| 23 | The GNU MP Library is distributed in the hope that it will be useful, but |
| 24 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 25 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 26 | for more details. |
| 27 | |
| 28 | You should have received copies of the GNU General Public License and the |
| 29 | GNU Lesser General Public License along with the GNU MP Library. If not, |
| 30 | see https://www.gnu.org/licenses/. */ |
| 31 | |
| 32 | #include "gmp-impl.h" |
| 33 | #include "longlong.h" |
| 34 | |
| 35 | static int |
| 36 | mpq_cmp_numden (mpq_srcptr op1, mpz_srcptr num_op2, mpz_srcptr den_op2) |
| 37 | { |
| 38 | mp_size_t num1_size = SIZ(NUM(op1)); |
| 39 | mp_size_t den1_size = SIZ(DEN(op1)); |
| 40 | mp_size_t num2_size = SIZ(num_op2); |
| 41 | mp_size_t den2_size = SIZ(den_op2); |
| 42 | int op2_is_int; |
| 43 | mp_limb_t d1h, d2h; |
| 44 | mp_size_t tmp1_size, tmp2_size; |
| 45 | mp_ptr tmp1_ptr, tmp2_ptr; |
| 46 | mp_size_t num1_sign; |
| 47 | int cc; |
| 48 | TMP_DECL; |
| 49 | |
| 50 | /* need canonical signs to get right result */ |
| 51 | ASSERT (den1_size > 0); |
| 52 | ASSERT (den2_size > 0); |
| 53 | |
| 54 | if (num1_size == 0) |
| 55 | return -num2_size; |
| 56 | if (num2_size == 0) |
| 57 | return num1_size; |
| 58 | if ((num1_size ^ num2_size) < 0) /* I.e. are the signs different? */ |
| 59 | return num1_size; |
| 60 | |
| 61 | num1_sign = num1_size; |
| 62 | num1_size = ABS (num1_size); |
| 63 | |
| 64 | /* THINK: Does storing d1h and d2h make sense? */ |
| 65 | d1h = PTR(DEN(op1))[den1_size - 1]; |
| 66 | d2h = PTR(den_op2)[den2_size - 1]; |
| 67 | op2_is_int = (den2_size | d2h) == 1; |
| 68 | if ((unsigned) op2_is_int == (den1_size | d1h)) /* Both ops are integers */ |
| 69 | /* return mpz_cmp (NUM (op1), num_op2); */ |
| 70 | { |
| 71 | int cmp; |
| 72 | |
| 73 | if (num1_sign != num2_size) |
| 74 | return num1_sign - num2_size; |
| 75 | |
| 76 | cmp = mpn_cmp (PTR(NUM(op1)), PTR(num_op2), num1_size); |
| 77 | return (num1_sign > 0 ? cmp : -cmp); |
| 78 | } |
| 79 | |
| 80 | num2_size = ABS (num2_size); |
| 81 | |
| 82 | tmp1_size = num1_size + den2_size; |
| 83 | tmp2_size = num2_size + den1_size; |
| 84 | |
| 85 | /* 1. Check to see if we can tell which operand is larger by just looking at |
| 86 | the number of limbs. */ |
| 87 | |
| 88 | /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs. |
| 89 | Same for NUM1 x DEN1 with respect to TMP2_SIZE. */ |
| 90 | if (tmp1_size > tmp2_size + 1) |
| 91 | /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1. */ |
| 92 | return num1_sign; |
| 93 | if (tmp2_size + op2_is_int > tmp1_size + 1) |
| 94 | /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1. */ |
| 95 | return -num1_sign; |
| 96 | |
| 97 | /* 2. Same, but compare the number of significant bits. */ |
| 98 | { |
| 99 | int cnt1, cnt2; |
| 100 | mp_bitcnt_t bits1, bits2; |
| 101 | |
| 102 | count_leading_zeros (cnt1, PTR(NUM(op1))[num1_size - 1]); |
| 103 | count_leading_zeros (cnt2, d2h); |
| 104 | bits1 = (mp_bitcnt_t) tmp1_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS; |
| 105 | |
| 106 | count_leading_zeros (cnt1, PTR(num_op2)[num2_size - 1]); |
| 107 | count_leading_zeros (cnt2, d1h); |
| 108 | bits2 = (mp_bitcnt_t) tmp2_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS; |
| 109 | |
| 110 | if (bits1 > bits2 + 1) |
| 111 | return num1_sign; |
| 112 | if (bits2 + op2_is_int > bits1 + 1) |
| 113 | return -num1_sign; |
| 114 | } |
| 115 | |
| 116 | /* 3. Finally, cross multiply and compare. */ |
| 117 | |
| 118 | TMP_MARK; |
| 119 | if (op2_is_int) |
| 120 | { |
| 121 | tmp2_ptr = TMP_ALLOC_LIMBS (tmp2_size); |
| 122 | tmp1_ptr = PTR(NUM(op1)); |
| 123 | --tmp1_size; |
| 124 | } |
| 125 | else |
| 126 | { |
| 127 | TMP_ALLOC_LIMBS_2 (tmp1_ptr,tmp1_size, tmp2_ptr,tmp2_size); |
| 128 | |
| 129 | if (num1_size >= den2_size) |
| 130 | tmp1_size -= 0 == mpn_mul (tmp1_ptr, |
| 131 | PTR(NUM(op1)), num1_size, |
| 132 | PTR(den_op2), den2_size); |
| 133 | else |
| 134 | tmp1_size -= 0 == mpn_mul (tmp1_ptr, |
| 135 | PTR(den_op2), den2_size, |
| 136 | PTR(NUM(op1)), num1_size); |
| 137 | } |
| 138 | |
| 139 | if (num2_size >= den1_size) |
| 140 | tmp2_size -= 0 == mpn_mul (tmp2_ptr, |
| 141 | PTR(num_op2), num2_size, |
| 142 | PTR(DEN(op1)), den1_size); |
| 143 | else |
| 144 | tmp2_size -= 0 == mpn_mul (tmp2_ptr, |
| 145 | PTR(DEN(op1)), den1_size, |
| 146 | PTR(num_op2), num2_size); |
| 147 | |
| 148 | |
| 149 | cc = tmp1_size - tmp2_size != 0 |
| 150 | ? tmp1_size - tmp2_size : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size); |
| 151 | TMP_FREE; |
| 152 | return num1_sign < 0 ? -cc : cc; |
| 153 | } |
| 154 | |
| 155 | int |
| 156 | mpq_cmp (mpq_srcptr op1, mpq_srcptr op2) |
| 157 | { |
| 158 | return mpq_cmp_numden (op1, NUM(op2), DEN(op2)); |
| 159 | } |
| 160 | |
| 161 | int |
| 162 | mpq_cmp_z (mpq_srcptr op1, mpz_srcptr op2) |
| 163 | { |
| 164 | const static mp_limb_t one = 1; |
| 165 | const static mpz_t den = MPZ_ROINIT_N ((mp_limb_t *) &one, 1); |
| 166 | |
| 167 | return mpq_cmp_numden (op1, op2, den); |
| 168 | } |