Blame tests/mpz/t-gcd.c

Packit 5c3484
/* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
Packit 5c3484
Packit 5c3484
Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012 Free
Packit 5c3484
Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library test suite.
Packit 5c3484
Packit 5c3484
The GNU MP Library test suite is free software; you can redistribute it
Packit 5c3484
and/or modify it under the terms of the GNU General Public License as
Packit 5c3484
published by the Free Software Foundation; either version 3 of the License,
Packit 5c3484
or (at your option) any later version.
Packit 5c3484
Packit 5c3484
The GNU MP Library test suite is distributed in the hope that it will be
Packit 5c3484
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5c3484
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 5c3484
Public License for more details.
Packit 5c3484
Packit 5c3484
You should have received a copy of the GNU General Public License along with
Packit 5c3484
the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "tests.h"
Packit 5c3484
Packit 5c3484
void one_test (mpz_t, mpz_t, mpz_t, int);
Packit 5c3484
void debug_mp (mpz_t, int);
Packit 5c3484
Packit 5c3484
static int gcdext_valid_p (const mpz_t, const mpz_t, const mpz_t, const mpz_t);
Packit 5c3484
Packit 5c3484
/* Keep one_test's variables global, so that we don't need
Packit 5c3484
   to reinitialize them for each test.  */
Packit 5c3484
mpz_t gcd1, gcd2, s, temp1, temp2, temp3;
Packit 5c3484
Packit 5c3484
#define MAX_SCHOENHAGE_THRESHOLD HGCD_REDUCE_THRESHOLD
Packit 5c3484
Packit 5c3484
/* Define this to make all operands be large enough for Schoenhage gcd
Packit 5c3484
   to be used.  */
Packit 5c3484
#ifndef WHACK_SCHOENHAGE
Packit 5c3484
#define WHACK_SCHOENHAGE 0
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if WHACK_SCHOENHAGE
Packit 5c3484
#define MIN_OPERAND_BITSIZE (MAX_SCHOENHAGE_THRESHOLD * GMP_NUMB_BITS)
Packit 5c3484
#else
Packit 5c3484
#define MIN_OPERAND_BITSIZE 1
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_data (void)
Packit 5c3484
{
Packit 5c3484
  static const struct {
Packit 5c3484
    const char *a;
Packit 5c3484
    const char *b;
Packit 5c3484
    const char *want;
Packit 5c3484
  } data[] = {
Packit 5c3484
    /* This tickled a bug in gmp 4.1.2 mpn/x86/k6/gcd_finda.asm. */
Packit 5c3484
    { "0x3FFC000007FFFFFFFFFF00000000003F83FFFFFFFFFFFFFFF80000000000000001",
Packit 5c3484
      "0x1FFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000000000000000001",
Packit 5c3484
      "5" }
Packit 5c3484
  };
Packit 5c3484
Packit 5c3484
  mpz_t  a, b, got, want;
Packit 5c3484
  int    i;
Packit 5c3484
Packit 5c3484
  mpz_inits (a, b, got, want, NULL);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (data); i++)
Packit 5c3484
    {
Packit 5c3484
      mpz_set_str_or_abort (a, data[i].a, 0);
Packit 5c3484
      mpz_set_str_or_abort (b, data[i].b, 0);
Packit 5c3484
      mpz_set_str_or_abort (want, data[i].want, 0);
Packit 5c3484
      mpz_gcd (got, a, b);
Packit 5c3484
      MPZ_CHECK_FORMAT (got);
Packit 5c3484
      if (mpz_cmp (got, want) != 0)
Packit 5c3484
	{
Packit 5c3484
	  printf    ("mpz_gcd wrong on data[%d]\n", i);
Packit 5c3484
	  printf    (" a  %s\n", data[i].a);
Packit 5c3484
	  printf    (" b  %s\n", data[i].b);
Packit 5c3484
	  mpz_trace (" a", a);
Packit 5c3484
	  mpz_trace (" b", b);
Packit 5c3484
	  mpz_trace (" want", want);
Packit 5c3484
	  mpz_trace (" got ", got);
Packit 5c3484
	  abort ();
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (a, b, got, want, NULL);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
make_chain_operands (mpz_t ref, mpz_t a, mpz_t b, gmp_randstate_t rs, int nb1, int nb2, int chain_len)
Packit 5c3484
{
Packit 5c3484
  mpz_t bs, temp1, temp2;
Packit 5c3484
  int j;
Packit 5c3484
Packit 5c3484
  mpz_inits (bs, temp1, temp2, NULL);
Packit 5c3484
Packit 5c3484
  /* Generate a division chain backwards, allowing otherwise unlikely huge
Packit 5c3484
     quotients.  */
Packit 5c3484
Packit 5c3484
  mpz_set_ui (a, 0);
Packit 5c3484
  mpz_urandomb (bs, rs, 32);
Packit 5c3484
  mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb1 + 1);
Packit 5c3484
  mpz_rrandomb (b, rs, mpz_get_ui (bs));
Packit 5c3484
  mpz_add_ui (b, b, 1);
Packit 5c3484
  mpz_set (ref, b);
Packit 5c3484
Packit 5c3484
  for (j = 0; j < chain_len; j++)
Packit 5c3484
    {
Packit 5c3484
      mpz_urandomb (bs, rs, 32);
Packit 5c3484
      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
Packit 5c3484
      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
Packit 5c3484
      mpz_add_ui (temp2, temp2, 1);
Packit 5c3484
      mpz_mul (temp1, b, temp2);
Packit 5c3484
      mpz_add (a, a, temp1);
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rs, 32);
Packit 5c3484
      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
Packit 5c3484
      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
Packit 5c3484
      mpz_add_ui (temp2, temp2, 1);
Packit 5c3484
      mpz_mul (temp1, a, temp2);
Packit 5c3484
      mpz_add (b, b, temp1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (bs, temp1, temp2, NULL);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Test operands from a table of seed data.  This variant creates the operands
Packit 5c3484
   using plain ol' mpz_rrandomb.  This is a hack for better coverage of the gcd
Packit 5c3484
   code, which depends on that the random number generators give the exact
Packit 5c3484
   numbers we expect.  */
Packit 5c3484
void
Packit 5c3484
check_kolmo1 (void)
Packit 5c3484
{
Packit 5c3484
  static const struct {
Packit 5c3484
    unsigned int seed;
Packit 5c3484
    int nb;
Packit 5c3484
    const char *want;
Packit 5c3484
  } data[] = {
Packit 5c3484
    { 59618, 38208, "5"},
Packit 5c3484
    { 76521, 49024, "3"},
Packit 5c3484
    { 85869, 54976, "1"},
Packit 5c3484
    { 99449, 63680, "1"},
Packit 5c3484
    {112453, 72000, "1"}
Packit 5c3484
  };
Packit 5c3484
Packit 5c3484
  gmp_randstate_t rs;
Packit 5c3484
  mpz_t  bs, a, b, want;
Packit 5c3484
  int    i, unb, vnb, nb;
Packit 5c3484
Packit 5c3484
  gmp_randinit_default (rs);
Packit 5c3484
Packit 5c3484
  mpz_inits (bs, a, b, want, NULL);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (data); i++)
Packit 5c3484
    {
Packit 5c3484
      nb = data[i].nb;
Packit 5c3484
Packit 5c3484
      gmp_randseed_ui (rs, data[i].seed);
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rs, 32);
Packit 5c3484
      unb = mpz_get_ui (bs) % nb;
Packit 5c3484
      mpz_urandomb (bs, rs, 32);
Packit 5c3484
      vnb = mpz_get_ui (bs) % nb;
Packit 5c3484
Packit 5c3484
      mpz_rrandomb (a, rs, unb);
Packit 5c3484
      mpz_rrandomb (b, rs, vnb);
Packit 5c3484
Packit 5c3484
      mpz_set_str_or_abort (want, data[i].want, 0);
Packit 5c3484
Packit 5c3484
      one_test (a, b, want, -1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (bs, a, b, want, NULL);
Packit 5c3484
  gmp_randclear (rs);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Test operands from a table of seed data.  This variant creates the operands
Packit 5c3484
   using a division chain.  This is a hack for better coverage of the gcd
Packit 5c3484
   code, which depends on that the random number generators give the exact
Packit 5c3484
   numbers we expect.  */
Packit 5c3484
void
Packit 5c3484
check_kolmo2 (void)
Packit 5c3484
{
Packit 5c3484
  static const struct {
Packit 5c3484
    unsigned int seed;
Packit 5c3484
    int nb, chain_len;
Packit 5c3484
  } data[] = {
Packit 5c3484
    {  917, 15, 5 },
Packit 5c3484
    { 1032, 18, 6 },
Packit 5c3484
    { 1167, 18, 6 },
Packit 5c3484
    { 1174, 18, 6 },
Packit 5c3484
    { 1192, 18, 6 },
Packit 5c3484
  };
Packit 5c3484
Packit 5c3484
  gmp_randstate_t rs;
Packit 5c3484
  mpz_t  bs, a, b, want;
Packit 5c3484
  int    i;
Packit 5c3484
Packit 5c3484
  gmp_randinit_default (rs);
Packit 5c3484
Packit 5c3484
  mpz_inits (bs, a, b, want, NULL);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (data); i++)
Packit 5c3484
    {
Packit 5c3484
      gmp_randseed_ui (rs, data[i].seed);
Packit 5c3484
      make_chain_operands (want, a, b, rs, data[i].nb, data[i].nb, data[i].chain_len);
Packit 5c3484
      one_test (a, b, want, -1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (bs, a, b, want, NULL);
Packit 5c3484
  gmp_randclear (rs);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char **argv)
Packit 5c3484
{
Packit 5c3484
  mpz_t op1, op2, ref;
Packit 5c3484
  int i, chain_len;
Packit 5c3484
  gmp_randstate_ptr rands;
Packit 5c3484
  mpz_t bs;
Packit 5c3484
  unsigned long bsi, size_range;
Packit 5c3484
  long int reps = 200;
Packit 5c3484
Packit 5c3484
  tests_start ();
Packit 5c3484
  TESTS_REPS (reps, argv, argc);
Packit 5c3484
Packit 5c3484
  rands = RANDS;
Packit 5c3484
Packit 5c3484
  mpz_inits (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
Packit 5c3484
Packit 5c3484
  check_data ();
Packit 5c3484
  check_kolmo1 ();
Packit 5c3484
  check_kolmo2 ();
Packit 5c3484
Packit 5c3484
  /* Testcase to exercise the u0 == u1 case in mpn_gcdext_lehmer_n. */
Packit 5c3484
  mpz_set_ui (op2, GMP_NUMB_MAX); /* FIXME: Huge limb doesn't always fit */
Packit 5c3484
  mpz_mul_2exp (op1, op2, 100);
Packit 5c3484
  mpz_add (op1, op1, op2);
Packit 5c3484
  mpz_mul_ui (op2, op2, 2);
Packit 5c3484
  one_test (op1, op2, NULL, -1);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < reps; i++)
Packit 5c3484
    {
Packit 5c3484
      /* Generate plain operands with unknown gcd.  These types of operands
Packit 5c3484
	 have proven to trigger certain bugs in development versions of the
Packit 5c3484
	 gcd code.  The "hgcd->row[3].rsize > M" ASSERT is not triggered by
Packit 5c3484
	 the division chain code below, but that is most likely just a result
Packit 5c3484
	 of that other ASSERTs are triggered before it.  */
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rands, 32);
Packit 5c3484
      size_range = mpz_get_ui (bs) % 17 + 2;
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rands, size_range);
Packit 5c3484
      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
Packit 5c3484
      mpz_urandomb (bs, rands, size_range);
Packit 5c3484
      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rands, 8);
Packit 5c3484
      bsi = mpz_get_ui (bs);
Packit 5c3484
Packit 5c3484
      if ((bsi & 0x3c) == 4)
Packit 5c3484
	mpz_mul (op1, op1, op2);	/* make op1 a multiple of op2 */
Packit 5c3484
      else if ((bsi & 0x3c) == 8)
Packit 5c3484
	mpz_mul (op2, op1, op2);	/* make op2 a multiple of op1 */
Packit 5c3484
Packit 5c3484
      if ((bsi & 1) != 0)
Packit 5c3484
	mpz_neg (op1, op1);
Packit 5c3484
      if ((bsi & 2) != 0)
Packit 5c3484
	mpz_neg (op2, op2);
Packit 5c3484
Packit 5c3484
      one_test (op1, op2, NULL, i);
Packit 5c3484
Packit 5c3484
      /* Generate a division chain backwards, allowing otherwise unlikely huge
Packit 5c3484
	 quotients.  */
Packit 5c3484
Packit 5c3484
      mpz_urandomb (bs, rands, 32);
Packit 5c3484
      chain_len = mpz_get_ui (bs) % LOG2C (GMP_NUMB_BITS * MAX_SCHOENHAGE_THRESHOLD);
Packit 5c3484
      mpz_urandomb (bs, rands, 32);
Packit 5c3484
      chain_len = mpz_get_ui (bs) % (1 << chain_len) / 32;
Packit 5c3484
Packit 5c3484
      make_chain_operands (ref, op1, op2, rands, 16, 12, chain_len);
Packit 5c3484
Packit 5c3484
      one_test (op1, op2, ref, i);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
Packit 5c3484
Packit 5c3484
  tests_end ();
Packit 5c3484
  exit (0);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
debug_mp (mpz_t x, int base)
Packit 5c3484
{
Packit 5c3484
  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
one_test (mpz_t op1, mpz_t op2, mpz_t ref, int i)
Packit 5c3484
{
Packit 5c3484
  /*
Packit 5c3484
  printf ("%d %d %d\n", SIZ (op1), SIZ (op2), ref != NULL ? SIZ (ref) : 0);
Packit 5c3484
  fflush (stdout);
Packit 5c3484
  */
Packit 5c3484
Packit 5c3484
  /*
Packit 5c3484
  fprintf (stderr, "op1=");  debug_mp (op1, -16);
Packit 5c3484
  fprintf (stderr, "op2=");  debug_mp (op2, -16);
Packit 5c3484
  */
Packit 5c3484
Packit 5c3484
  mpz_gcdext (gcd1, s, NULL, op1, op2);
Packit 5c3484
  MPZ_CHECK_FORMAT (gcd1);
Packit 5c3484
  MPZ_CHECK_FORMAT (s);
Packit 5c3484
Packit 5c3484
  if (ref && mpz_cmp (ref, gcd1) != 0)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "ERROR in test %d\n", i);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
Packit 5c3484
      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
Packit 5c3484
      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
Packit 5c3484
      fprintf (stderr, "expected result:\n");   debug_mp (ref, -16);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
Packit 5c3484
      abort ();
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (!gcdext_valid_p(op1, op2, gcd1, s))
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "ERROR in test %d\n", i);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returned invalid result\n");
Packit 5c3484
      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
Packit 5c3484
      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
Packit 5c3484
      fprintf (stderr, "s=");                   debug_mp (s, -16);
Packit 5c3484
      abort ();
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_gcd (gcd2, op1, op2);
Packit 5c3484
  MPZ_CHECK_FORMAT (gcd2);
Packit 5c3484
Packit 5c3484
  if (mpz_cmp (gcd2, gcd1) != 0)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "ERROR in test %d\n", i);
Packit 5c3484
      fprintf (stderr, "mpz_gcd returned incorrect result\n");
Packit 5c3484
      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
Packit 5c3484
      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
Packit 5c3484
      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
Packit 5c3484
      fprintf (stderr, "mpz_gcd returns:\n");   debug_mp (gcd2, -16);
Packit 5c3484
      abort ();
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* This should probably move to t-gcd_ui.c */
Packit 5c3484
  if (mpz_fits_ulong_p (op1) || mpz_fits_ulong_p (op2))
Packit 5c3484
    {
Packit 5c3484
      if (mpz_fits_ulong_p (op1))
Packit 5c3484
	mpz_gcd_ui (gcd2, op2, mpz_get_ui (op1));
Packit 5c3484
      else
Packit 5c3484
	mpz_gcd_ui (gcd2, op1, mpz_get_ui (op2));
Packit 5c3484
      if (mpz_cmp (gcd2, gcd1))
Packit 5c3484
	{
Packit 5c3484
	  fprintf (stderr, "ERROR in test %d\n", i);
Packit 5c3484
	  fprintf (stderr, "mpz_gcd_ui returned incorrect result\n");
Packit 5c3484
	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
Packit 5c3484
	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
Packit 5c3484
	  fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
Packit 5c3484
	  fprintf (stderr, "mpz_gcd_ui returns:\n");   debug_mp (gcd2, -16);
Packit 5c3484
	  abort ();
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_gcdext (gcd2, temp1, temp2, op1, op2);
Packit 5c3484
  MPZ_CHECK_FORMAT (gcd2);
Packit 5c3484
  MPZ_CHECK_FORMAT (temp1);
Packit 5c3484
  MPZ_CHECK_FORMAT (temp2);
Packit 5c3484
Packit 5c3484
  mpz_mul (temp1, temp1, op1);
Packit 5c3484
  mpz_mul (temp2, temp2, op2);
Packit 5c3484
  mpz_add (temp1, temp1, temp2);
Packit 5c3484
Packit 5c3484
  if (mpz_cmp (gcd1, gcd2) != 0
Packit 5c3484
      || mpz_cmp (gcd2, temp1) != 0)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "ERROR in test %d\n", i);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
Packit 5c3484
      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
Packit 5c3484
      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
Packit 5c3484
      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
Packit 5c3484
      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd2, -16);
Packit 5c3484
      abort ();
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t.
Packit 5c3484
   Uses temp1, temp2 and temp3. */
Packit 5c3484
static int
Packit 5c3484
gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s)
Packit 5c3484
{
Packit 5c3484
  /* It's not clear that gcd(0,0) is well defined, but we allow it and require that
Packit 5c3484
     gcd(0,0) = 0. */
Packit 5c3484
  if (mpz_sgn (g) < 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (a) == 0)
Packit 5c3484
    {
Packit 5c3484
      /* Must have g == abs (b). Any value for s is in some sense "correct",
Packit 5c3484
	 but it makes sense to require that s == 0. */
Packit 5c3484
      return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0;
Packit 5c3484
    }
Packit 5c3484
  else if (mpz_sgn (b) == 0)
Packit 5c3484
    {
Packit 5c3484
      /* Must have g == abs (a), s == sign (a) */
Packit 5c3484
      return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (g) <= 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  mpz_tdiv_qr (temp1, temp3, a, g);
Packit 5c3484
  if (mpz_sgn (temp3) != 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  mpz_tdiv_qr (temp2, temp3, b, g);
Packit 5c3484
  if (mpz_sgn (temp3) != 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  /* Require that 2 |s| < |b/g|, or |s| == 1. */
Packit 5c3484
  if (mpz_cmpabs_ui (s, 1) > 0)
Packit 5c3484
    {
Packit 5c3484
      mpz_mul_2exp (temp3, s, 1);
Packit 5c3484
      if (mpz_cmpabs (temp3, temp2) >= 0)
Packit 5c3484
	return 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Compute the other cofactor. */
Packit 5c3484
  mpz_mul(temp2, s, a);
Packit 5c3484
  mpz_sub(temp2, g, temp2);
Packit 5c3484
  mpz_tdiv_qr(temp2, temp3, temp2, b);
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (temp3) != 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  /* Require that 2 |t| < |a/g| or |t| == 1*/
Packit 5c3484
  if (mpz_cmpabs_ui (temp2, 1) > 0)
Packit 5c3484
    {
Packit 5c3484
      mpz_mul_2exp (temp2, temp2, 1);
Packit 5c3484
      if (mpz_cmpabs (temp2, temp1) >= 0)
Packit 5c3484
	return 0;
Packit 5c3484
    }
Packit 5c3484
  return 1;
Packit 5c3484
}