Blame mpq/cmp.c

Packit 5c3484
/* mpq_cmp(u,v) -- Compare U, V.  Return positive, zero, or negative
Packit 5c3484
   based on if U > V, U == V, or U < V.
Packit 5c3484
Packit 5c3484
Copyright 1991, 1994, 1996, 2001, 2002, 2005, 2015 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
mpq_cmp_numden (mpq_srcptr op1, mpz_srcptr num_op2, mpz_srcptr den_op2)
Packit 5c3484
{
Packit 5c3484
  mp_size_t num1_size = SIZ(NUM(op1));
Packit 5c3484
  mp_size_t den1_size = SIZ(DEN(op1));
Packit 5c3484
  mp_size_t num2_size = SIZ(num_op2);
Packit 5c3484
  mp_size_t den2_size = SIZ(den_op2);
Packit 5c3484
  int op2_is_int;
Packit 5c3484
  mp_limb_t d1h, d2h;
Packit 5c3484
  mp_size_t tmp1_size, tmp2_size;
Packit 5c3484
  mp_ptr tmp1_ptr, tmp2_ptr;
Packit 5c3484
  mp_size_t num1_sign;
Packit 5c3484
  int cc;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  /* need canonical signs to get right result */
Packit 5c3484
  ASSERT (den1_size > 0);
Packit 5c3484
  ASSERT (den2_size > 0);
Packit 5c3484
Packit 5c3484
  if (num1_size == 0)
Packit 5c3484
    return -num2_size;
Packit 5c3484
  if (num2_size == 0)
Packit 5c3484
    return num1_size;
Packit 5c3484
  if ((num1_size ^ num2_size) < 0) /* I.e. are the signs different? */
Packit 5c3484
    return num1_size;
Packit 5c3484
Packit 5c3484
  num1_sign = num1_size;
Packit 5c3484
  num1_size = ABS (num1_size);
Packit 5c3484
Packit 5c3484
  /* THINK: Does storing d1h and d2h make sense? */
Packit 5c3484
  d1h = PTR(DEN(op1))[den1_size - 1];
Packit 5c3484
  d2h = PTR(den_op2)[den2_size - 1];
Packit 5c3484
  op2_is_int = (den2_size | d2h) == 1;
Packit 5c3484
  if (op2_is_int == (den1_size | d1h)) /* Both ops are integers */
Packit 5c3484
    /* return mpz_cmp (NUM (op1), num_op2); */
Packit 5c3484
    {
Packit 5c3484
      int cmp;
Packit 5c3484
Packit 5c3484
      if (num1_sign != num2_size)
Packit 5c3484
	return num1_sign - num2_size;
Packit 5c3484
Packit 5c3484
      cmp = mpn_cmp (PTR(NUM(op1)), PTR(num_op2), num1_size);
Packit 5c3484
      return (num1_sign > 0 ? cmp : -cmp);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  num2_size = ABS (num2_size);
Packit 5c3484
Packit 5c3484
  tmp1_size = num1_size + den2_size;
Packit 5c3484
  tmp2_size = num2_size + den1_size;
Packit 5c3484
Packit 5c3484
  /* 1. Check to see if we can tell which operand is larger by just looking at
Packit 5c3484
     the number of limbs.  */
Packit 5c3484
Packit 5c3484
  /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs.
Packit 5c3484
     Same for NUM1 x DEN1 with respect to TMP2_SIZE.  */
Packit 5c3484
  if (tmp1_size > tmp2_size + 1)
Packit 5c3484
    /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1.  */
Packit 5c3484
    return num1_sign;
Packit 5c3484
  if (tmp2_size + op2_is_int > tmp1_size + 1)
Packit 5c3484
    /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1.  */
Packit 5c3484
    return -num1_sign;
Packit 5c3484
Packit 5c3484
  /* 2. Same, but compare the number of significant bits.  */
Packit 5c3484
  {
Packit 5c3484
    int cnt1, cnt2;
Packit 5c3484
    mp_bitcnt_t bits1, bits2;
Packit 5c3484
Packit 5c3484
    count_leading_zeros (cnt1, PTR(NUM(op1))[num1_size - 1]);
Packit 5c3484
    count_leading_zeros (cnt2, d2h);
Packit 5c3484
    bits1 = (mp_bitcnt_t) tmp1_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
Packit 5c3484
Packit 5c3484
    count_leading_zeros (cnt1, PTR(num_op2)[num2_size - 1]);
Packit 5c3484
    count_leading_zeros (cnt2, d1h);
Packit 5c3484
    bits2 = (mp_bitcnt_t) tmp2_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
Packit 5c3484
Packit 5c3484
    if (bits1 > bits2 + 1)
Packit 5c3484
      return num1_sign;
Packit 5c3484
    if (bits2 + op2_is_int > bits1 + 1)
Packit 5c3484
      return -num1_sign;
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
  /* 3. Finally, cross multiply and compare.  */
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
  if (op2_is_int)
Packit 5c3484
    {
Packit 5c3484
      tmp2_ptr = TMP_ALLOC_LIMBS (tmp2_size);
Packit 5c3484
      tmp1_ptr = PTR(NUM(op1));
Packit 5c3484
      --tmp1_size;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
  TMP_ALLOC_LIMBS_2 (tmp1_ptr,tmp1_size, tmp2_ptr,tmp2_size);
Packit 5c3484
Packit 5c3484
  if (num1_size >= den2_size)
Packit 5c3484
    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
Packit 5c3484
			       PTR(NUM(op1)), num1_size,
Packit 5c3484
			       PTR(den_op2), den2_size);
Packit 5c3484
  else
Packit 5c3484
    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
Packit 5c3484
			       PTR(den_op2), den2_size,
Packit 5c3484
			       PTR(NUM(op1)), num1_size);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
   if (num2_size >= den1_size)
Packit 5c3484
     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
Packit 5c3484
				PTR(num_op2), num2_size,
Packit 5c3484
				PTR(DEN(op1)), den1_size);
Packit 5c3484
   else
Packit 5c3484
     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
Packit 5c3484
				PTR(DEN(op1)), den1_size,
Packit 5c3484
				PTR(num_op2), num2_size);
Packit 5c3484
Packit 5c3484
Packit 5c3484
  cc = tmp1_size - tmp2_size != 0
Packit 5c3484
    ? tmp1_size - tmp2_size : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size);
Packit 5c3484
  TMP_FREE;
Packit 5c3484
  return num1_sign < 0 ? -cc : cc;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
mpq_cmp (mpq_srcptr op1, mpq_srcptr op2)
Packit 5c3484
{
Packit 5c3484
  return mpq_cmp_numden (op1, NUM(op2), DEN(op2));
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
mpq_cmp_z (mpq_srcptr op1, mpz_srcptr op2)
Packit 5c3484
{
Packit 5c3484
  const static mp_limb_t one = 1;
Packit 5c3484
  const static mpz_t den = MPZ_ROINIT_N ((mp_limb_t *) &one, 1);
Packit 5c3484
Packit 5c3484
  return mpq_cmp_numden (op1, op2, den);
Packit 5c3484
}