/* bigint2.c */

/* Test bigint functions.  Note that these functions are for internal
   use by the C library only. */

#undef NDEBUG
#include <stdio.h>
#include <float.h>
#include <assert.h>
#include <emx/bigint.h>

/* 67 extra bits, see pow5_tests(). */

#define POWERS_OF_FIVE  (LDBL_MAX_10_EXP + LDBL_DIG + 1)
#define BBITS           (LDBL_MAX_EXP + 67)
#define BWORDS          _BI_WORDS (BBITS)

static void mul_test1 (int i, int j)
{
  int ov;
  _BI_DECLARE (x, BWORDS);
  _BI_DECLARE (y, BWORDS);
  _BI_DECLARE (z, BWORDS);
  _BI_DECLARE (t, BWORDS);

  _BI_INIT (x); _BI_INIT (y); _BI_INIT (z); _BI_INIT (t);
  ov = _bi_pow5 (&x, BWORDS, i, 0, NULL); assert (!ov);
  ov = _bi_pow5 (&y, BWORDS, j, 0, NULL); assert (!ov);
  ov = _bi_pow5 (&z, BWORDS, i + j, 0, NULL); assert (!ov);
  ov = _bi_mul_bb (&t, BWORDS, &x, &y); assert (!ov);
  if (_bi_cmp_bb (&t, &z) != 0)
    abort ();
}


static void mul_tests (void)
{
  static int samples[]
    = {0, 1, 2, 3, 4, 5, 6, 7, 17, 42, 50, 51, 52, 53, 54, 55,
       63, 77, 111, 222, 516, 1013, 3791, 4917, 4918, 4919, 4920};
  int i, j;

  for (i = 0; i < sizeof (samples) / sizeof (samples[0]); ++i)
    {
      printf ("Test %d of %d\n",
              i + 1, (int)(sizeof (samples) / sizeof (samples[0])));
      for (j = 0; j < POWERS_OF_FIVE - samples[i]; ++j)
        mul_test1 (samples[i], j);
    }
}


static void pow5_test1 (int shift, const _bi_bigint *factor)
{
  _BI_DECLARE (x, BWORDS);
  _BI_DECLARE (y, BWORDS);
  int i, ov;
  static int n;

  printf ("Test %d of 24\n", ++n);
  _BI_INIT (x); _BI_INIT (y);
  ov = _bi_shl_b (&x, BWORDS, factor, shift); assert (!ov);
  for (i = 0; i < POWERS_OF_FIVE; ++i)
    {
      ov = _bi_pow5 (&y, BWORDS, i, shift, factor); assert (!ov);
      if (_bi_cmp_bb (&x, &y) != 0)
        abort ();
      if (i != POWERS_OF_FIVE - 1)
        {
          ov = _bi_mul_bw (&x, BWORDS, &x, 5);
          assert (!ov);
        }
    }
}


static void pow5_tests (void)
{
  _BI_DECLARE (factor, 2);

  _BI_INIT (factor);
  _bi_set_w (&factor, 2, 1);
  pow5_test1 (0, &factor);
  pow5_test1 (1, &factor);
  pow5_test1 (2, &factor);
  pow5_test1 (3, &factor);
  pow5_test1 (4, &factor);
  pow5_test1 (5, &factor);
  pow5_test1 (6, &factor);
  pow5_test1 (17, &factor);
  pow5_test1 (60, &factor);
  pow5_test1 (63, &factor);
  pow5_test1 (66, &factor);
  _bi_set_w (&factor, 2, 2);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 3);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 4);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 5);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 6);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 7);
  pow5_test1 (0, &factor);
  _bi_set_w (&factor, 2, 0x12345678);
  pow5_test1 (0, &factor);
  pow5_test1 (1, &factor);
  pow5_test1 (2, &factor);
  pow5_test1 (3, &factor);
  _bi_set_d (&factor, 2, 0x123456789abcdef0ULL);
  pow5_test1 (0, &factor);
  pow5_test1 (1, &factor);
  pow5_test1 (2, &factor);
  pow5_test1 (3, &factor);
}


int main (void)
{
  printf ("Testing _bi_pow5()...\n");
  pow5_tests ();
  printf ("Testing _bi_mul_bb()...\n");
  mul_tests ();
  return 0;
}
