Пример #1
0
static int
hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0,
		   struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1,
		   mp_size_t res1, struct hgcd_matrix *hgcd)
{
  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
  mp_size_t s = n/2 + 1;

  mp_bitcnt_t dbits, abits, margin;
  mpz_t appr_r0, appr_r1, t, q;
  struct hgcd_ref appr;

  if (!res0)
    {
      if (!res1)
	return 1;

      fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n");
      return 0;
    }

  /* NOTE: No *_clear calls on error return, since we're going to
     abort anyway. */
  mpz_init (t);
  mpz_init (q);
  hgcd_ref_init (&appr);
  mpz_init (appr_r0);
  mpz_init (appr_r1);

  if (mpz_size (ref_r0) <= s)
    {
      fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16);
      return 0;
    }
  if (mpz_size (ref_r1) <= s)
    {
      fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16);
      return 0;
    }

  mpz_sub (t, ref_r0, ref_r1);
  dbits = mpz_sizeinbase (t, 2);
  if (dbits > s*GMP_NUMB_BITS)
    {
      fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16);
      return 0;
    }

  if (!res1)
    {
      mpz_set (appr_r0, a);
      mpz_set (appr_r1, b);
    }
  else
    {
      unsigned i;

      for (i = 0; i<2; i++)
	{
	  unsigned j;

	  for (j = 0; j<2; j++)
	    {
	      mp_size_t mn = hgcd->n;
	      MPN_NORMALIZE (hgcd->p[i][j], mn);
	      mpz_realloc (appr.m[i][j], mn);
	      MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn);
	      SIZ (appr.m[i][j]) = mn;
	    }
	}
      mpz_mul (appr_r0, appr.m[1][1], a);
      mpz_mul (t, appr.m[0][1], b);
      mpz_sub (appr_r0, appr_r0, t);
      if (mpz_sgn (appr_r0) <= 0
	  || mpz_size (appr_r0) <= s)
	{
	  fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16);
	  return 0;
	}

      mpz_mul (appr_r1, appr.m[1][0], a);
      mpz_mul (t, appr.m[0][0], b);
      mpz_sub (appr_r1, t, appr_r1);
      if (mpz_sgn (appr_r1) <= 0
	  || mpz_size (appr_r1) <= s)
	{
	  fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16);
	  return 0;
	}
    }

  mpz_sub (t, appr_r0, appr_r1);
  abits = mpz_sizeinbase (t, 2);
  if (abits < dbits)
    {
      fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16);
      return 0;
    }

  /* We lose one bit each time we discard the least significant limbs.
     For the lehmer code, that can happen at most s * (GMP_NUMB_BITS)
     / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire
     limb (or more?) for each level of recursion. */

  margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1);
  {
    mp_size_t rn;
    for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2)
      margin += GMP_NUMB_BITS;
  }

  if (verbose_flag && abits > dbits)
    fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n",
	     (unsigned) n, (unsigned) s*GMP_NUMB_BITS,
	     (unsigned) dbits, (unsigned) abits,
	     (int) abits - s * GMP_NUMB_BITS, (unsigned) margin);

  if (abits > s*GMP_NUMB_BITS + margin)
    {
      fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n",
	       (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin);
      return 0;
    }

  while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0)
    {
      ASSERT (mpz_size (appr_r0) > s);
      ASSERT (mpz_size (appr_r1) > s);

      if (mpz_cmp (appr_r0, appr_r1) > 0)
	{
	  if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1))
	    break;
	  mpz_addmul (appr.m[0][1], q, appr.m[0][0]);
	  mpz_addmul (appr.m[1][1], q, appr.m[1][0]);
	}
      else
	{
	  if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0))
	    break;
	  mpz_addmul (appr.m[0][0], q, appr.m[0][1]);
	  mpz_addmul (appr.m[1][0], q, appr.m[1][1]);
	}
    }

  if (mpz_cmp (appr_r0, ref_r0) != 0
      || mpz_cmp (appr_r1, ref_r1) != 0
      || !hgcd_ref_equal (ref, &appr))
    {
      fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16);
      fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16);

      fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16);
      fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16);

      return 0;
    }
  mpz_clear (t);
  mpz_clear (q);
  hgcd_ref_clear (&appr);
  mpz_clear (appr_r0);
  mpz_clear (appr_r1);

  return 1;
}
Пример #2
0
static mp_size_t
one_test (mpz_t a, mpz_t b, int i)
{
  struct hgcd_matrix hgcd;
  struct hgcd_ref ref;

  mpz_t ref_r0;
  mpz_t ref_r1;
  mpz_t hgcd_r0;
  mpz_t hgcd_r1;

  mp_size_t res[2];
  mp_size_t asize;
  mp_size_t bsize;

  mp_size_t hgcd_init_scratch;
  mp_size_t hgcd_scratch;

  mp_ptr hgcd_init_tp;
  mp_ptr hgcd_tp;

  asize = a->_mp_size;
  bsize = b->_mp_size;

  ASSERT (asize >= bsize);

  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);

  hgcd_scratch = mpn_hgcd_itch (asize);
  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);

#if 0
  fprintf (stderr,
	   "one_test: i = %d asize = %d, bsize = %d\n",
	   i, a->_mp_size, b->_mp_size);

  gmp_fprintf (stderr,
	       "one_test: i = %d\n"
	       "  a = %Zx\n"
	       "  b = %Zx\n",
	       i, a, b);
#endif
  hgcd_ref_init (&ref);

  mpz_init_set (ref_r0, a);
  mpz_init_set (ref_r1, b);
  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);

  mpz_init_set (hgcd_r0, a);
  mpz_init_set (hgcd_r1, b);
  if (bsize < asize)
    {
      _mpz_realloc (hgcd_r1, asize);
      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
    }
  res[1] = mpn_hgcd (hgcd_r0->_mp_d,
		     hgcd_r1->_mp_d,
		     asize,
		     &hgcd, hgcd_tp);

  if (res[0] != res[1])
    {
      fprintf (stderr, "ERROR in test %d\n", i);
      fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
      fprintf (stderr, "op1=");                 debug_mp (a, -16);
      fprintf (stderr, "op2=");                 debug_mp (b, -16);
      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
      fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
      abort ();
    }
  if (res[0] > 0)
    {
      if (!hgcd_ref_equal (&hgcd, &ref)
	  || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
	  || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
	{
	  fprintf (stderr, "ERROR in test %d\n", i);
	  fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
	  fprintf (stderr, "op1=");                 debug_mp (a, -16);
	  fprintf (stderr, "op2=");                 debug_mp (b, -16);
	  abort ();
	}
    }

  refmpn_free_limbs (hgcd_init_tp);
  refmpn_free_limbs (hgcd_tp);
  hgcd_ref_clear (&ref);
  mpz_clear (ref_r0);
  mpz_clear (ref_r1);
  mpz_clear (hgcd_r0);
  mpz_clear (hgcd_r1);

  return res[0];
}
Пример #3
0
static mp_size_t
one_test (mpz_t a, mpz_t b, int i)
{
  struct hgcd_matrix hgcd;
  struct hgcd_ref ref;

  mpz_t ref_r0;
  mpz_t ref_r1;
  mpz_t hgcd_r0;
  mpz_t hgcd_r1;

  int res[2];
  mp_size_t asize;
  mp_size_t bsize;

  mp_size_t hgcd_init_scratch;
  mp_size_t hgcd_scratch;

  mp_ptr hgcd_init_tp;
  mp_ptr hgcd_tp;
  mp_limb_t marker[4];

  asize = a->_mp_size;
  bsize = b->_mp_size;

  ASSERT (asize >= bsize);

  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch + 2) + 1;
  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);

  hgcd_scratch = mpn_hgcd_appr_itch (asize);
  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch + 2) + 1;

  mpn_random (marker, 4);

  hgcd_init_tp[-1] = marker[0];
  hgcd_init_tp[hgcd_init_scratch] = marker[1];
  hgcd_tp[-1] = marker[2];
  hgcd_tp[hgcd_scratch] = marker[3];

#if 0
  fprintf (stderr,
	   "one_test: i = %d asize = %d, bsize = %d\n",
	   i, a->_mp_size, b->_mp_size);

  gmp_fprintf (stderr,
	       "one_test: i = %d\n"
	       "  a = %Zx\n"
	       "  b = %Zx\n",
	       i, a, b);
#endif
  hgcd_ref_init (&ref);

  mpz_init_set (ref_r0, a);
  mpz_init_set (ref_r1, b);
  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);

  mpz_init_set (hgcd_r0, a);
  mpz_init_set (hgcd_r1, b);
  if (bsize < asize)
    {
      _mpz_realloc (hgcd_r1, asize);
      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
    }
  res[1] = mpn_hgcd_appr (hgcd_r0->_mp_d,
			  hgcd_r1->_mp_d,
			  asize,
			  &hgcd, hgcd_tp);

  if (hgcd_init_tp[-1] != marker[0]
      || hgcd_init_tp[hgcd_init_scratch] != marker[1]
      || hgcd_tp[-1] != marker[2]
      || hgcd_tp[hgcd_scratch] != marker[3])
    {
      fprintf (stderr, "ERROR in test %d\n", i);
      fprintf (stderr, "scratch space overwritten!\n");

      if (hgcd_init_tp[-1] != marker[0])
	gmp_fprintf (stderr,
		     "before init_tp: %Mx\n"
		     "expected: %Mx\n",
		     hgcd_init_tp[-1], marker[0]);
      if (hgcd_init_tp[hgcd_init_scratch] != marker[1])
	gmp_fprintf (stderr,
		     "after init_tp: %Mx\n"
		     "expected: %Mx\n",
		     hgcd_init_tp[hgcd_init_scratch], marker[1]);
      if (hgcd_tp[-1] != marker[2])
	gmp_fprintf (stderr,
		     "before tp: %Mx\n"
		     "expected: %Mx\n",
		     hgcd_tp[-1], marker[2]);
      if (hgcd_tp[hgcd_scratch] != marker[3])
	gmp_fprintf (stderr,
		     "after tp: %Mx\n"
		     "expected: %Mx\n",
		     hgcd_tp[hgcd_scratch], marker[3]);

      abort ();
    }

  if (!hgcd_appr_valid_p (a, b, res[0], &ref, ref_r0, ref_r1,
			  res[1], &hgcd))
    {
      fprintf (stderr, "ERROR in test %d\n", i);
      fprintf (stderr, "Invalid results for hgcd and hgcd_ref\n");
      fprintf (stderr, "op1=");                 debug_mp (a, -16);
      fprintf (stderr, "op2=");                 debug_mp (b, -16);
      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
      fprintf (stderr, "mpn_hgcd_appr: %ld\n", (long) res[1]);
      abort ();
    }

  refmpn_free_limbs (hgcd_init_tp - 1);
  refmpn_free_limbs (hgcd_tp - 1);
  hgcd_ref_clear (&ref);
  mpz_clear (ref_r0);
  mpz_clear (ref_r1);
  mpz_clear (hgcd_r0);
  mpz_clear (hgcd_r1);

  return res[0];
}