#include "config.h"
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_FLOAT_H
#include <float.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include "gmp.h"
#include "gmp-impl.h"
#include "tests.h"
void
tests_start (void)
{
char version[10];
snprintf (version, 10, "%u.%u.%u",
__GNU_MP_VERSION,
__GNU_MP_VERSION_MINOR,
__GNU_MP_VERSION_PATCHLEVEL);
if (strcmp (gmp_version, version) != 0)
{
fprintf (stderr, "tests are not linked to the newly compiled library\n");
fprintf (stderr, " local version is: %s\n", version);
fprintf (stderr, " linked version is: %s\n", gmp_version);
abort ();
}
setbuf (stdout, NULL);
setbuf (stderr, NULL);
tests_memory_start ();
tests_rand_start ();
}
void
tests_end (void)
{
tests_rand_end ();
tests_memory_end ();
}
void
tests_rand_start (void)
{
gmp_randstate_ptr rands;
char *perform_seed;
unsigned long seed;
if (__gmp_rands_initialized)
{
printf ("Please let tests_start() initialize the global __gmp_rands.\n");
printf ("ie. ensure that function is called before the first use of RANDS.\n");
abort ();
}
gmp_randinit_default (__gmp_rands);
__gmp_rands_initialized = 1;
rands = __gmp_rands;
perform_seed = getenv ("GMP_CHECK_RANDOMIZE");
if (perform_seed != NULL)
{
#ifdef HAVE_STRTOUL
seed = strtoul (perform_seed, 0, 0);
#else
seed = atoi (perform_seed);
#endif
if (! (seed == 0 || seed == 1))
{
printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed);
gmp_randseed_ui (rands, seed);
}
else
{
#if HAVE_GETTIMEOFDAY
struct timeval tv;
gettimeofday (&tv, NULL);
seed = tv.tv_sec ^ ((unsigned long) tv.tv_usec << 12);
seed &= 0xffffffff;
#else
time_t tv;
time (&tv);
seed = tv;
#endif
gmp_randseed_ui (rands, seed);
printf ("Seed GMP_CHECK_RANDOMIZE=%lu (include this in bug reports)\n", seed);
}
fflush (stdout);
}
}
void
tests_rand_end (void)
{
RANDS_CLEAR ();
}
mp_limb_t (*calling_conventions_function) (ANYARGS);
void *
align_pointer (void *p, size_t align)
{
gmp_intptr_t d;
d = ((gmp_intptr_t) p) & (align-1);
d = (d != 0 ? align-d : 0);
return (void *) (((char *) p) + d);
}
void *
__gmp_allocate_func_aligned (size_t bytes, size_t align)
{
return align_pointer ((*__gmp_allocate_func) (bytes + align-1), align);
}
void *
__gmp_allocate_or_reallocate (void *ptr, size_t oldsize, size_t newsize)
{
if (ptr == NULL)
return (*__gmp_allocate_func) (newsize);
else
return (*__gmp_reallocate_func) (ptr, oldsize, newsize);
}
char *
__gmp_allocate_strdup (const char *s)
{
size_t len;
char *t;
len = strlen (s);
t = (char *) (*__gmp_allocate_func) (len+1);
memcpy (t, s, len+1);
return t;
}
char *
strtoupper (char *s_orig)
{
char *s;
for (s = s_orig; *s != '\0'; s++)
if (isascii (*s))
*s = toupper (*s);
return s_orig;
}
void
mpz_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
{
ASSERT (size >= 0);
MPN_NORMALIZE (p, size);
MPZ_REALLOC (z, size);
MPN_COPY (PTR(z), p, size);
SIZ(z) = size;
}
void
mpz_init_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
{
ASSERT (size >= 0);
MPN_NORMALIZE (p, size);
ALLOC(z) = MAX (size, 1);
PTR(z) = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC(z));
SIZ(z) = size;
MPN_COPY (PTR(z), p, size);
}
mp_size_t
mpn_diff_lowest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
{
mp_size_t i;
for (i = 0; i < size; i++)
if (p1[i] != p2[i])
return i;
return -1;
}
mp_size_t
mpn_diff_highest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
{
mp_size_t i;
for (i = size-1; i >= 0; i--)
if (p1[i] != p2[i])
return i;
return -1;
}
mp_size_t
byte_diff_lowest (const void *p1, const void *p2, mp_size_t size)
{
mp_size_t i;
for (i = 0; i < size; i++)
if (((const char *) p1)[i] != ((const char *) p2)[i])
return i;
return -1;
}
mp_size_t
byte_diff_highest (const void *p1, const void *p2, mp_size_t size)
{
mp_size_t i;
for (i = size-1; i >= 0; i--)
if (((const char *) p1)[i] != ((const char *) p2)[i])
return i;
return -1;
}
void
mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
{
if (mpz_set_str (z, str, base) != 0)
{
fprintf (stderr, "ERROR: mpz_set_str failed\n");
fprintf (stderr, " str = \"%s\"\n", str);
fprintf (stderr, " base = %d\n", base);
abort();
}
}
void
mpq_set_str_or_abort (mpq_ptr q, const char *str, int base)
{
if (mpq_set_str (q, str, base) != 0)
{
fprintf (stderr, "ERROR: mpq_set_str failed\n");
fprintf (stderr, " str = \"%s\"\n", str);
fprintf (stderr, " base = %d\n", base);
abort();
}
}
void
mpf_set_str_or_abort (mpf_ptr f, const char *str, int base)
{
if (mpf_set_str (f, str, base) != 0)
{
fprintf (stderr, "ERROR mpf_set_str failed\n");
fprintf (stderr, " str = \"%s\"\n", str);
fprintf (stderr, " base = %d\n", base);
abort();
}
}
int
mpz_pow2abs_p (mpz_srcptr z)
{
mp_size_t size, i;
mp_srcptr ptr;
size = SIZ (z);
if (size == 0)
return 0;
size = ABS (size);
ptr = PTR (z);
for (i = 0; i < size-1; i++)
if (ptr[i] != 0)
return 0;
return POW2_P (ptr[i]);
}
void
mpz_erandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
{
mpz_urandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
}
void
mpz_erandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
{
mpz_erandomb (rop, rstate, nbits);
if (mpz_sgn (rop) == 0)
mpz_set_ui (rop, 1L);
}
void
mpz_errandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
{
mpz_rrandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
}
void
mpz_errandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
{
mpz_errandomb (rop, rstate, nbits);
if (mpz_sgn (rop) == 0)
mpz_set_ui (rop, 1L);
}
void
mpz_negrandom (mpz_ptr rop, gmp_randstate_t rstate)
{
mp_limb_t n;
_gmp_rand (&n, rstate, 1);
if (n != 0)
mpz_neg (rop, rop);
}
mp_limb_t
urandom (void)
{
#if GMP_NAIL_BITS == 0
mp_limb_t n;
_gmp_rand (&n, RANDS, GMP_LIMB_BITS);
return n;
#else
mp_limb_t n[2];
_gmp_rand (n, RANDS, GMP_LIMB_BITS);
return n[0] + (n[1] << GMP_NUMB_BITS);
#endif
}
void
call_rand_algs (void (*func) (const char *, gmp_randstate_ptr))
{
gmp_randstate_t rstate;
mpz_t a;
mpz_init (a);
gmp_randinit_default (rstate);
(*func) ("gmp_randinit_default", rstate);
gmp_randclear (rstate);
gmp_randinit_mt (rstate);
(*func) ("gmp_randinit_mt", rstate);
gmp_randclear (rstate);
gmp_randinit_lc_2exp_size (rstate, 8L);
(*func) ("gmp_randinit_lc_2exp_size 8", rstate);
gmp_randclear (rstate);
gmp_randinit_lc_2exp_size (rstate, 16L);
(*func) ("gmp_randinit_lc_2exp_size 16", rstate);
gmp_randclear (rstate);
gmp_randinit_lc_2exp_size (rstate, 128L);
(*func) ("gmp_randinit_lc_2exp_size 128", rstate);
gmp_randclear (rstate);
mpz_set_ui (a, 0L);
gmp_randinit_lc_2exp (rstate, a, 0L, 8L);
(*func) ("gmp_randinit_lc_2exp a=0 c=0 m=8", rstate);
gmp_randclear (rstate);
mpz_set_ui (a, 0L);
gmp_randinit_lc_2exp (rstate, a, 0xFFL, 8L);
(*func) ("gmp_randinit_lc_2exp a=0 c=0xFF m=8", rstate);
gmp_randclear (rstate);
mpz_clear (a);
}
double
tests_infinity_d (void)
{
#if _GMP_IEEE_FLOATS
union ieee_double_extract x;
x.s.exp = 2047;
x.s.manl = 0;
x.s.manh = 0;
x.s.sig = 0;
return x.d;
#else
return 0;
#endif
}
int
tests_isinf (double d)
{
#if _GMP_IEEE_FLOATS
union ieee_double_extract x;
x.d = d;
return (x.s.exp == 2047 && x.s.manl == 0 && x.s.manh == 0);
#else
return 0;
#endif
}
int
tests_hardware_setround (int mode)
{
#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
int rc;
switch (mode) {
case 0: rc = 0; break;
case 1: rc = 3; break;
case 2: rc = 2; break;
case 3: rc = 1; break;
default:
return 0;
}
x86_fldcw ((x86_fstcw () & ~0xC00) | (rc << 10));
return 1;
#endif
return 0;
}
int
tests_hardware_getround (void)
{
#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
switch ((x86_fstcw () & ~0xC00) >> 10) {
case 0: return 0; break;
case 1: return 3; break;
case 2: return 2; break;
case 3: return 1; break;
}
#endif
return -1;
}
int
tests_dbl_mant_bits (void)
{
static int n = -1;
volatile double x, y, d;
if (n != -1)
return n;
n = 1;
x = 2.0;
for (;;)
{
y = x + 1.0;
d = y - x;
if (d != 1.0)
{
#if defined (DBL_MANT_DIG) && DBL_RADIX == 2
if (n != DBL_MANT_DIG)
printf ("Warning, tests_dbl_mant_bits got %d but DBL_MANT_DIG says %d\n", n, DBL_MANT_DIG);
#endif
break;
}
x *= 2;
n++;
if (n > 1000)
{
printf ("Oops, tests_dbl_mant_bits can't determine mantissa size\n");
n = 0;
break;
}
}
return n;
}
jmp_buf tests_sigfpe_target;
RETSIGTYPE
tests_sigfpe_handler (int sig)
{
longjmp (tests_sigfpe_target, 1);
}
void
tests_sigfpe_done (void)
{
signal (SIGFPE, SIG_DFL);
}