mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-22 04:30:03 +00:00
473 lines
9.4 KiB
C
473 lines
9.4 KiB
C
/*
|
|
Test the library maths functions using trusted precomputed test
|
|
vectors.
|
|
|
|
These vectors were originally generated on a sun3 with a 68881 using
|
|
80 bit precision, but ...
|
|
|
|
Each function is called with a variety of interesting arguments.
|
|
Note that many of the polynomials we use behave badly when the
|
|
domain is stressed, so the numbers in the vectors depend on what is
|
|
useful to test - eg sin(1e30) is pointless - the arg has to be
|
|
reduced modulo pi, and after that there's no bits of significance
|
|
left to evaluate with - any number would be just as precise as any
|
|
other.
|
|
|
|
|
|
*/
|
|
|
|
#include "test.h"
|
|
#include <math.h>
|
|
#include <ieeefp.h>
|
|
#include <float.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
int inacc;
|
|
|
|
int merror;
|
|
double mretval = 64;
|
|
int traperror = 1;
|
|
char *mname;
|
|
|
|
int verbose;
|
|
|
|
/* To test exceptions - we trap them all and return a known value */
|
|
int
|
|
_DEFUN(matherr,(e),
|
|
struct exception *e)
|
|
{
|
|
if (traperror)
|
|
{
|
|
merror = e->type + 12;
|
|
mname = e->name;
|
|
e->retval = mretval;
|
|
errno = merror + 24;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void _DEFUN(translate_to,(file,r),
|
|
FILE *file _AND
|
|
double r)
|
|
{
|
|
__ieee_double_shape_type bits;
|
|
bits.value = r;
|
|
fprintf(file, "0x%08x, 0x%08x", bits.parts.msw, bits.parts.lsw);
|
|
}
|
|
|
|
int
|
|
_DEFUN(ffcheck,( is, p, name, serrno, merror),
|
|
double is _AND
|
|
one_line_type *p _AND
|
|
char *name _AND
|
|
int serrno _AND
|
|
int merror)
|
|
{
|
|
/* Make sure the answer isn't to far wrong from the correct value */
|
|
__ieee_double_shape_type correct, isbits;
|
|
int mag;
|
|
isbits.value = is;
|
|
|
|
correct.parts.msw = p->qs[0].msw;
|
|
correct.parts.lsw = p->qs[0].lsw;
|
|
|
|
mag = mag_of_error(correct.value, is);
|
|
|
|
if (mag < p->error_bit)
|
|
{
|
|
inacc ++;
|
|
|
|
printf("%s:%d, inaccurate answer: bit %d (%08x%08x %08x%08x) (%g %g)\n",
|
|
name, p->line, mag,
|
|
correct.parts.msw,
|
|
correct.parts.lsw,
|
|
isbits.parts.msw,
|
|
isbits.parts.lsw,
|
|
correct.value, is);
|
|
}
|
|
|
|
#if 0
|
|
if (p->qs[0].merror != merror)
|
|
{
|
|
printf("testing %s_vec.c:%d, matherr wrong: %d %d\n",
|
|
name, p->line, merror, p->qs[0].merror);
|
|
}
|
|
|
|
if (p->qs[0].errno_val != errno)
|
|
{
|
|
printf("testing %s_vec.c:%d, errno wrong: %d %d\n",
|
|
name, p->line, errno, p->qs[0].errno_val);
|
|
|
|
}
|
|
#endif
|
|
return mag;
|
|
}
|
|
|
|
double
|
|
_DEFUN(thedouble, (msw, lsw),
|
|
long msw _AND
|
|
long lsw)
|
|
{
|
|
__ieee_double_shape_type x;
|
|
|
|
x.parts.msw = msw;
|
|
x.parts.lsw = lsw;
|
|
return x.value;
|
|
}
|
|
|
|
int calc;
|
|
int reduce;
|
|
|
|
|
|
_DEFUN(frontline,(f, mag, p, result, merror, errno, args, name),
|
|
FILE *f _AND
|
|
int mag _AND
|
|
one_line_type *p _AND
|
|
double result _AND
|
|
int merror _AND
|
|
int errno _AND
|
|
char *args _AND
|
|
char *name)
|
|
{
|
|
if (reduce && p->error_bit < mag)
|
|
{
|
|
fprintf(f, "{%2d,", p->error_bit);
|
|
}
|
|
else
|
|
{
|
|
fprintf(f, "{%2d,",mag);
|
|
}
|
|
|
|
|
|
fprintf(f,"%2d,%3d,", merror,errno);
|
|
fprintf(f, "__LINE__, ");
|
|
|
|
if (calc)
|
|
{
|
|
translate_to(f, result);
|
|
}
|
|
else
|
|
{
|
|
translate_to(f, thedouble(p->qs[0].msw, p->qs[0].lsw));
|
|
}
|
|
|
|
fprintf(f, ", ");
|
|
|
|
fprintf(f,"0x%08x, 0x%08x", p->qs[1].msw, p->qs[1].lsw);
|
|
|
|
|
|
if (args[2])
|
|
{
|
|
fprintf(f, ", ");
|
|
fprintf(f,"0x%08x, 0x%08x", p->qs[2].msw, p->qs[2].lsw);
|
|
}
|
|
|
|
fprintf(f,"}, /* %g=f(%g",result,
|
|
thedouble(p->qs[1].msw, p->qs[1].lsw));
|
|
|
|
if (args[2])
|
|
{
|
|
fprintf(f,", %g", thedouble(p->qs[2].msw,p->qs[2].lsw));
|
|
}
|
|
fprintf(f, ")*/\n");
|
|
}
|
|
|
|
_DEFUN(finish,(f, vector, result , p, args, name),
|
|
FILE *f _AND
|
|
int vector _AND
|
|
double result _AND
|
|
one_line_type *p _AND
|
|
char *args _AND
|
|
char *name)
|
|
{
|
|
int mag;
|
|
|
|
mag = ffcheck(result, p,name, merror, errno);
|
|
if (vector)
|
|
{
|
|
frontline(f, mag, p, result, merror, errno, args , name);
|
|
}
|
|
}
|
|
int redo;
|
|
|
|
_DEFUN(run_vector_1,(vector, p, func, name, args),
|
|
int vector _AND
|
|
one_line_type *p _AND
|
|
char *func _AND
|
|
char *name _AND
|
|
char *args)
|
|
{
|
|
FILE *f;
|
|
int mag;
|
|
double result;
|
|
|
|
if (vector)
|
|
{
|
|
|
|
VECOPEN(name, f);
|
|
|
|
if (redo)
|
|
{
|
|
double k;
|
|
|
|
for (k = -.2; k < .2; k+= 0.00132)
|
|
{
|
|
|
|
fprintf(f,"{1,1, 1,1, 0,0,0x%08x,0x%08x, 0x%08x, 0x%08x},\n",
|
|
k,k+4);
|
|
|
|
}
|
|
|
|
for (k = -1.2; k < 1.2; k+= 0.01)
|
|
{
|
|
|
|
fprintf(f,"{1,1, 1,1, 0,0,0x%08x,0x%08x, 0x%08x, 0x%08x},\n",
|
|
k,k+4);
|
|
|
|
}
|
|
for (k = -M_PI *2; k < M_PI *2; k+= M_PI/2)
|
|
{
|
|
|
|
fprintf(f,"{1,1, 1,1, 0,0,0x%08x,0x%08x, 0x%08x, 0x%08x},\n",
|
|
k,k+4);
|
|
|
|
}
|
|
|
|
for (k = -30; k < 30; k+= 1.7)
|
|
{
|
|
|
|
fprintf(f,"{2,2, 1,1, 0,0, 0x%08x,0x%08x, 0x%08x, 0x%08x},\n",
|
|
k,k+4);
|
|
|
|
}
|
|
VECCLOSE(f, name, args);
|
|
return;
|
|
}
|
|
}
|
|
|
|
newfunc(name);
|
|
while (p->line)
|
|
{
|
|
double arg1 = thedouble(p->qs[1].msw, p->qs[1].lsw);
|
|
double arg2 = thedouble(p->qs[2].msw, p->qs[2].lsw);
|
|
|
|
double r;
|
|
double rf;
|
|
|
|
errno = 0;
|
|
merror = 0;
|
|
mname = 0;
|
|
|
|
|
|
line(p->line);
|
|
|
|
merror = 0;
|
|
errno = 123;
|
|
|
|
if (strcmp(args,"dd")==0)
|
|
{
|
|
typedef double _EXFUN((*pdblfunc),(double));
|
|
|
|
/* Double function returning a double */
|
|
|
|
result = ((pdblfunc)(func))(arg1);
|
|
|
|
finish(f,vector, result, p, args, name);
|
|
}
|
|
else if (strcmp(args,"ff")==0)
|
|
{
|
|
float arga;
|
|
double a;
|
|
|
|
typedef float _EXFUN((*pdblfunc),(float));
|
|
|
|
/* Double function returning a double */
|
|
|
|
if (arg1 < FLT_MAX )
|
|
{
|
|
arga = arg1;
|
|
result = ((pdblfunc)(func))(arga);
|
|
finish(f, vector, result, p,args, name);
|
|
}
|
|
}
|
|
else if (strcmp(args,"ddd")==0)
|
|
{
|
|
typedef double _EXFUN((*pdblfunc),(double,double));
|
|
|
|
result = ((pdblfunc)(func))(arg1,arg2);
|
|
finish(f, vector, result, p,args, name);
|
|
}
|
|
else if (strcmp(args,"fff")==0)
|
|
{
|
|
double a,b;
|
|
|
|
float arga;
|
|
float argb;
|
|
|
|
typedef float _EXFUN((*pdblfunc),(float,float));
|
|
|
|
|
|
if (arg1 < FLT_MAX && arg2 < FLT_MAX)
|
|
{
|
|
arga = arg1;
|
|
argb = arg2;
|
|
result = ((pdblfunc)(func))(arga, argb);
|
|
finish(f, vector, result, p,args, name);
|
|
}
|
|
}
|
|
else if (strcmp(args,"did")==0)
|
|
{
|
|
typedef double _EXFUN((*pdblfunc),(int,double));
|
|
|
|
result = ((pdblfunc)(func))((int)arg1,arg2);
|
|
finish(f, vector, result, p,args, name);
|
|
}
|
|
else if (strcmp(args,"fif")==0)
|
|
{
|
|
double a,b;
|
|
|
|
float arga;
|
|
float argb;
|
|
|
|
typedef float _EXFUN((*pdblfunc),(int,float));
|
|
|
|
|
|
if (arg1 < FLT_MAX && arg2 < FLT_MAX)
|
|
{
|
|
arga = arg1;
|
|
argb = arg2;
|
|
result = ((pdblfunc)(func))((int)arga, argb);
|
|
finish(f, vector, result, p,args, name);
|
|
}
|
|
}
|
|
|
|
p++;
|
|
}
|
|
if (vector)
|
|
{
|
|
VECCLOSE(f, name, args);
|
|
}
|
|
}
|
|
|
|
void
|
|
_DEFUN_VOID(test_math)
|
|
{
|
|
test_acos(0);
|
|
test_acosf(0);
|
|
test_acosh(0);
|
|
test_acoshf(0);
|
|
test_asin(0);
|
|
test_asinf(0);
|
|
test_asinh(0);
|
|
test_asinhf(0);
|
|
test_atan(0);
|
|
test_atan2(0);
|
|
test_atan2f(0);
|
|
test_atanf(0);
|
|
test_atanh(0);
|
|
test_atanhf(0);
|
|
test_ceil(0);
|
|
test_ceilf(0);
|
|
test_cos(0);
|
|
test_cosf(0);
|
|
test_cosh(0);
|
|
test_coshf(0);
|
|
test_erf(0);
|
|
test_erfc(0);
|
|
test_erfcf(0);
|
|
test_erff(0);
|
|
test_exp(0);
|
|
test_expf(0);
|
|
test_fabs(0);
|
|
test_fabsf(0);
|
|
test_floor(0);
|
|
test_floorf(0);
|
|
test_fmod(0);
|
|
test_fmodf(0);
|
|
test_gamma(0);
|
|
test_gammaf(0);
|
|
test_hypot(0);
|
|
test_hypotf(0);
|
|
test_j0(0);
|
|
test_j0f(0);
|
|
test_j1(0);
|
|
test_j1f(0);
|
|
test_jn(0);
|
|
test_jnf(0);
|
|
test_log(0);
|
|
test_log10(0);
|
|
test_log10f(0);
|
|
test_log1p(0);
|
|
test_log1pf(0);
|
|
test_log2(0);
|
|
test_log2f(0);
|
|
test_logf(0);
|
|
test_sin(0);
|
|
test_sinf(0);
|
|
test_sinh(0);
|
|
test_sinhf(0);
|
|
test_sqrt(0);
|
|
test_sqrtf(0);
|
|
test_tan(0);
|
|
test_tanf(0);
|
|
test_tanh(0);
|
|
test_tanhf(0);
|
|
test_y0(0);
|
|
test_y0f(0);
|
|
test_y1(0);
|
|
test_y1f(0);
|
|
test_y1f(0);
|
|
test_ynf(0);
|
|
}
|
|
|
|
/* These have to be played with to get to compile on machines which
|
|
don't have the fancy <foo>f entry points
|
|
*/
|
|
|
|
#if 0
|
|
float _DEFUN(cosf,(a), float a) { return cos((double)a); }
|
|
float _DEFUN(sinf,(a), float a) { return sin((double)a); }
|
|
float _DEFUN(log1pf,(a), float a) { return log1p((double)a); }
|
|
float _DEFUN(tanf,(a), float a) { return tan((double)a); }
|
|
float _DEFUN(ceilf,(a), float a) { return ceil(a); }
|
|
float _DEFUN(floorf,(a), float a) { return floor(a); }
|
|
#endif
|
|
|
|
/*ndef HAVE_FLOAT*/
|
|
#if 0
|
|
|
|
float fmodf(a,b) float a,b; { return fmod(a,b); }
|
|
float hypotf(a,b) float a,b; { return hypot(a,b); }
|
|
|
|
float acosf(a) float a; { return acos(a); }
|
|
float acoshf(a) float a; { return acosh(a); }
|
|
float asinf(a) float a; { return asin(a); }
|
|
float asinhf(a) float a; { return asinh(a); }
|
|
float atanf(a) float a; { return atan(a); }
|
|
float atanhf(a) float a; { return atanh(a); }
|
|
|
|
float coshf(a) float a; { return cosh(a); }
|
|
float erff(a) float a; { return erf(a); }
|
|
float erfcf(a) float a; { return erfc(a); }
|
|
float expf(a) float a; { return exp(a); }
|
|
float fabsf(a) float a; { return fabs(a); }
|
|
|
|
float gammaf(a) float a; { return gamma(a); }
|
|
float j0f(a) float a; { return j0(a); }
|
|
float j1f(a) float a; { return j1(a); }
|
|
float log10f(a) float a; { return log10(a); }
|
|
|
|
float logf(a) float a; { return log(a); }
|
|
|
|
float sinhf(a) float a; { return sinh(a); }
|
|
float sqrtf(a) float a; { return sqrt(a); }
|
|
|
|
float tanhf(a) float a; { return tanh(a); }
|
|
float y0f(a) float a; { return y0(a); }
|
|
float y1f(a) float a; { return y1(a); }
|
|
#endif
|