Blame math/atest-exp2.c

Packit 6c4009
/* Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Geoffrey Keating <Geoff.Keating@anu.edu.au>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <gmp.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
Packit 6c4009
#define PRINT_ERRORS 0
Packit 6c4009
Packit 6c4009
#define TOL 80
Packit 6c4009
#define N2 18
Packit 6c4009
#define FRAC (32*4)
Packit 6c4009
Packit 6c4009
#define mpbpl (CHAR_BIT * sizeof (mp_limb_t))
Packit 6c4009
#define SZ (FRAC / mpbpl + 1)
Packit 6c4009
typedef mp_limb_t mp1[SZ], mp2[SZ * 2];
Packit 6c4009
Packit 6c4009
#if BITS_PER_MP_LIMB == 64
Packit 6c4009
# define LIMB64(L, H) 0x ## H ## L
Packit 6c4009
#elif BITS_PER_MP_LIMB == 32
Packit 6c4009
# define LIMB64(L, H) 0x ## L, 0x ## H
Packit 6c4009
#else
Packit 6c4009
# error
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Once upon a time these constants were generated to 400 bits.
Packit 6c4009
   We only need FRAC bits (128) at present, but we retain 384 bits
Packit 6c4009
   in the text Just In Case.  */
Packit 6c4009
#define CONSTSZ(INT, F1, F2, F3, F4, F5, F6, F7, F8, F9, Fa, Fb, Fc) \
Packit 6c4009
	LIMB64(F4, F3), LIMB64(F2, F1), INT
Packit 6c4009
Packit 6c4009
static const mp1 mp_exp1 = {
Packit 6c4009
  CONSTSZ (2, b7e15162, 8aed2a6a, bf715880, 9cf4f3c7, 62e7160f, 38b4da56,
Packit 6c4009
           a784d904, 5190cfef, 324e7738, 926cfbe5, f4bf8d8d, 8c31d763)
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static const mp1 mp_log2 = {
Packit 6c4009
  CONSTSZ (0, b17217f7, d1cf79ab, c9e3b398, 03f2f6af, 40f34326, 7298b62d,
Packit 6c4009
           8a0d175b, 8baafa2b, e7b87620, 6debac98, 559552fb, 4afa1b10)
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
print_mpn_fp (const mp_limb_t *x, unsigned int dp, unsigned int base)
Packit 6c4009
{
Packit 6c4009
   static const char hexdig[16] = "0123456789abcdef";
Packit 6c4009
   unsigned int i;
Packit 6c4009
   mp1 tx;
Packit 6c4009
Packit 6c4009
   memcpy (tx, x, sizeof (mp1));
Packit 6c4009
   if (base == 16)
Packit 6c4009
     fputs ("0x", stdout);
Packit 6c4009
   assert (x[SZ-1] < base);
Packit 6c4009
   fputc (hexdig[x[SZ - 1]], stdout);
Packit 6c4009
   fputc ('.', stdout);
Packit 6c4009
   for (i = 0; i < dp; i++)
Packit 6c4009
     {
Packit 6c4009
       tx[SZ - 1] = 0;
Packit 6c4009
       mpn_mul_1 (tx, tx, SZ, base);
Packit 6c4009
       assert (tx[SZ - 1] < base);
Packit 6c4009
       fputc (hexdig[tx[SZ - 1]], stdout);
Packit 6c4009
     }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Compute e^x.  */
Packit 6c4009
static void
Packit 6c4009
exp_mpn (mp1 ex, mp1 x)
Packit 6c4009
{
Packit 6c4009
   unsigned int n;
Packit 6c4009
   mp1 xp;
Packit 6c4009
   mp2 tmp;
Packit 6c4009
   mp_limb_t chk __attribute__ ((unused));
Packit 6c4009
   mp1 tol;
Packit 6c4009
Packit 6c4009
   memset (xp, 0, sizeof (mp1));
Packit 6c4009
   memset (ex, 0, sizeof (mp1));
Packit 6c4009
   xp[FRAC / mpbpl] = (mp_limb_t)1 << FRAC % mpbpl;
Packit 6c4009
   memset (tol, 0, sizeof (mp1));
Packit 6c4009
   tol[(FRAC - TOL) / mpbpl] = (mp_limb_t)1 << (FRAC - TOL) % mpbpl;
Packit 6c4009
Packit 6c4009
   n = 0;
Packit 6c4009
Packit 6c4009
   do
Packit 6c4009
     {
Packit 6c4009
       /* Calculate sum(x^n/n!) until the next term is sufficiently small.  */
Packit 6c4009
Packit 6c4009
       mpn_mul_n (tmp, xp, x, SZ);
Packit 6c4009
       assert(tmp[SZ * 2 - 1] == 0);
Packit 6c4009
       if (n > 0)
Packit 6c4009
	 mpn_divmod_1 (xp, tmp + FRAC / mpbpl, SZ, n);
Packit 6c4009
       chk = mpn_add_n (ex, ex, xp, SZ);
Packit 6c4009
       assert (chk == 0);
Packit 6c4009
       ++n;
Packit 6c4009
       assert (n < 80); /* Catch too-high TOL.  */
Packit 6c4009
     }
Packit 6c4009
   while (n < 10 || mpn_cmp (xp, tol, SZ) >= 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Calculate 2^x.  */
Packit 6c4009
static void
Packit 6c4009
exp2_mpn (mp1 ex, mp1 x)
Packit 6c4009
{
Packit 6c4009
  mp2 tmp;
Packit 6c4009
  mpn_mul_n (tmp, x, mp_log2, SZ);
Packit 6c4009
  assert(tmp[SZ * 2 - 1] == 0);
Packit 6c4009
  exp_mpn (ex, tmp + FRAC / mpbpl);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
mpn_bitsize(const mp_limb_t *SRC_PTR, mp_size_t SIZE)
Packit 6c4009
{
Packit 6c4009
  int i, j;
Packit 6c4009
  for (i = SIZE - 1; i > 0; --i)
Packit 6c4009
    if (SRC_PTR[i] != 0)
Packit 6c4009
      break;
Packit 6c4009
  for (j = mpbpl - 1; j >= 0; --j)
Packit 6c4009
    if ((SRC_PTR[i] & (mp_limb_t)1 << j) != 0)
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
  return i * mpbpl + j;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  mp1 ex, x, xt, e2, e3;
Packit 6c4009
  int i;
Packit 6c4009
  int errors = 0;
Packit 6c4009
  int failures = 0;
Packit 6c4009
  mp1 maxerror;
Packit 6c4009
  int maxerror_s = 0;
Packit 6c4009
  const double sf = pow (2, mpbpl);
Packit 6c4009
Packit 6c4009
  /* assert(mpbpl == mp_bits_per_limb); */
Packit 6c4009
  assert(FRAC / mpbpl * mpbpl == FRAC);
Packit 6c4009
Packit 6c4009
  memset (maxerror, 0, sizeof (mp1));
Packit 6c4009
  memset (xt, 0, sizeof (mp1));
Packit 6c4009
  xt[(FRAC - N2) / mpbpl] = (mp_limb_t)1 << (FRAC - N2) % mpbpl;
Packit 6c4009
Packit 6c4009
  for (i = 0; i < (1 << N2); ++i)
Packit 6c4009
    {
Packit 6c4009
      int e2s, e3s, j;
Packit 6c4009
      double de2;
Packit 6c4009
Packit 6c4009
      mpn_mul_1 (x, xt, SZ, i);
Packit 6c4009
      exp2_mpn (ex, x);
Packit 6c4009
      de2 = exp2 (i / (double) (1 << N2));
Packit 6c4009
      for (j = SZ - 1; j >= 0; --j)
Packit 6c4009
	{
Packit 6c4009
	  e2[j] = (mp_limb_t) de2;
Packit 6c4009
	  de2 = (de2 - e2[j]) * sf;
Packit 6c4009
	}
Packit 6c4009
      if (mpn_cmp (ex, e2, SZ) >= 0)
Packit 6c4009
	mpn_sub_n (e3, ex, e2, SZ);
Packit 6c4009
      else
Packit 6c4009
	mpn_sub_n (e3, e2, ex, SZ);
Packit 6c4009
Packit 6c4009
      e2s = mpn_bitsize (e2, SZ);
Packit 6c4009
      e3s = mpn_bitsize (e3, SZ);
Packit 6c4009
      if (e3s >= 0 && e2s - e3s < 54)
Packit 6c4009
	{
Packit 6c4009
#if PRINT_ERRORS
Packit 6c4009
	  printf ("%06x ", i * (0x100000 / (1 << N2)));
Packit 6c4009
	  print_mpn_fp (ex, (FRAC / 4) + 1, 16);
Packit 6c4009
	  putchar ('\n');
Packit 6c4009
	  fputs ("       ",stdout);
Packit 6c4009
	  print_mpn_fp (e2, (FRAC / 4) + 1, 16);
Packit 6c4009
	  putchar ('\n');
Packit 6c4009
	  printf (" %c     ",
Packit 6c4009
		  e2s - e3s < 54 ? e2s - e3s == 53 ? 'e' : 'F' : 'P');
Packit 6c4009
	  print_mpn_fp (e3, (FRAC / 4) + 1, 16);
Packit 6c4009
	  putchar ('\n');
Packit 6c4009
#endif
Packit 6c4009
	  errors += (e2s - e3s == 53);
Packit 6c4009
	  failures += (e2s - e3s < 53);
Packit 6c4009
	}
Packit 6c4009
      if (e3s >= maxerror_s
Packit 6c4009
	  && mpn_cmp (e3, maxerror, SZ) > 0)
Packit 6c4009
	{
Packit 6c4009
	  memcpy (maxerror, e3, sizeof (mp1));
Packit 6c4009
	  maxerror_s = e3s;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Check exp_mpn against precomputed value of exp(1).  */
Packit 6c4009
  memset (x, 0, sizeof (mp1));
Packit 6c4009
  x[FRAC / mpbpl] = (mp_limb_t)1 << FRAC % mpbpl;
Packit 6c4009
  exp_mpn (ex, x);
Packit 6c4009
  if (mpn_cmp (ex, mp_exp1, SZ) >= 0)
Packit 6c4009
    mpn_sub_n (e3, ex, mp_exp1, SZ);
Packit 6c4009
  else
Packit 6c4009
    mpn_sub_n (e3, mp_exp1, ex, SZ);
Packit 6c4009
Packit 6c4009
  printf ("%d failures; %d errors; error rate %0.2f%%\n", failures, errors,
Packit 6c4009
	  errors * 100.0 / (double) (1 << N2));
Packit 6c4009
  fputs ("maximum error:   ", stdout);
Packit 6c4009
  print_mpn_fp (maxerror, (FRAC / 4) + 1, 16);
Packit 6c4009
  putchar ('\n');
Packit 6c4009
  fputs ("error in exp(1): ", stdout);
Packit 6c4009
  print_mpn_fp (e3, (FRAC / 4) + 1, 16);
Packit 6c4009
  putchar ('\n');
Packit 6c4009
Packit 6c4009
  return failures == 0 ? 0 : 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TIMEOUT 300
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"