//
// LiDIA - a library for computational number theory
// Copyright(c) 1995 by the LiDIA Group
//
// File:udigit_appl.c
// Author:Thomas Pfahler(TPf)
// Last change:TPf, Apr 10 1995, initial version
//



#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)

#include <LiDIA:udigit.h>
#include <LiDIA:random.h>
#include <LiDIA:bigint.h>

#else

#include <LiDIA/udigit.h>
#include <LiDIA/random.h>
#include <LiDIA/bigint.h>

#endif

#include <assert.h>




inline bigint 
GLUE(const udigit & hi, const udigit & lo)
{
  return (bigint) lo + ((bigint) hi << (SIZEOF_LONG * 8));
}



main()
{
  lidia_size_t  anz, i, h;
  cout << endl << "\n anz = ";
  cin >> anz;
  h = anz/40;
  if (h == 0)
	h = 1;

  udigit a, b, c, d, x, y, hi, lo;
  bigint A, B, C, D;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    hi = udigit_add(lo, a, b, c);

    A = (bigint) a + (bigint) b + (bigint) c;
    B = GLUE(hi, lo);
    assert(A == B);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Add-Test succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    hi = udigit_sub(lo, a, b, c);

    A = (bigint) a - (bigint) b - (bigint) c;
    B = (bigint) lo - ((bigint) hi << (SIZEOF_LONG * 8));
    assert(A == B);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Sub-Test succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    hi = udigit_add(lo, a, b, c);
    y = udigit_sub(x, lo, b, c);

    assert(x == a);
    assert(y == hi);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Add-Sub-Test 1 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    hi = udigit_sub(lo, a, b, c);
    y = udigit_add(x, lo, b, c);

    assert(x == a);
    assert(y == hi);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Add-Sub-Test 2 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    hi = udigit_mul(lo, a, b);

    A = (bigint) a *(bigint) b;
    B = GLUE(hi, lo);
    assert(A == B);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Mul-Test succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    a = a % c;
    y = udigit_div(x, a, b, c);

    A = GLUE(a, b);
    div_rem(B, C, A, c);
    assert(B == x);
    assert(C == y);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Div-Test succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    c = random();
    a = random() % c;
    b = random() % c;
    x = udigit_add_mod(a, b, c);
    y = udigit_sub_mod(x, b, c);

    A = ((bigint) a + (bigint) b) % (bigint) (c);
    assert(a == y);
    assert(A == x);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Add-Sub-MOD-Test 1 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    c = random();
    a = random() % c;
    b = random() % c;
    x = udigit_sub_mod(a, b, c);
    y = udigit_add_mod(x, b, c);

    A = ((bigint) a - (bigint) b) % (bigint) (c);
    while (A.is_negative())
      A += c;
    assert(a == y);
    assert(A == x);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Add-Sub-MOD-Test 2 succeeded") << endl;

/* *******************************************************************
    the following part may fail because of the probabilistic 
    primality test used for udigits

    
  for (i = 0; i < anz; i++)
  {
    c = random();
    c = udigit_next_prime(c);

    assert(udigit_is_prime(c,15));
	assert(is_prime((bigint)c,8));
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Primality test 1 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    a = udigit_next_prime(a);
    x = udigit_next_prime(a);
    y = udigit_previous_prime(x);

    assert(a == y);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Primality test 2 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    c = udigit_next_prime(c);
    x = udigit_inv_mod(a, c);
    y = udigit_mul_mod(x, a, c);

    assert(y == 1);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Mul-Inv-MOD-Test 1 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    c = udigit_next_prime(c);
    c = 2 * c;
    a = a % c;
    if (!(a & 1))
      a = (a + 1) % c;

    x = udigit_inv_mod(a, c);
    y = udigit_mul_mod(x, a, c);

    assert(y == 1);
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Mul-Inv-MOD-Test 2 succeeded") << endl;


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    c = udigit_next_prime(c);

    if (udigit_jacobi(a, c) == 1)
    {
      x = udigit_sqrt_mod(a, c);
      y = udigit_mul_mod(x, x, c);

      a = a % c;
      assert(y == a);
    }
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Sqrt-MOD-Test succeeded") << endl;
  
******************************************************************* */


  for (i = 0; i < anz; i++)
  {
    a = random();
    b = random();
    c = random();
    c = udigit_xgcd(x, y, a, b);
    d = udigit_gcd(a, b);

    assert(c == d);
    assert(a % c == 0);
    assert(b % c == 0);
    assert(c == (x * a - y * b));
	if (i % h == 0)
	  cout << "+" << flush;
  }
  cout << endl << " " << ("Gcd-Test succeeded") << endl;

}
