/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd and Michael C. Wrinn.	    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include <math.h>

#include "../h/fastmath.h"

#define PI   3.14159265359

#include "../h/cputime.h"

#define	COMMAND(s)	(strcmp (key_buf, s) == 0)
#define	COMMANDS(s)	(strncmp (key_buf, s, strlen(s)) == 0)
char key_buf [256];

main()
{
	char *keytree, *tree_match_parse(), *tree_match_err_at();

	int numTimes, intervalDivide, angleRange;
	float testAngle;

	keytree = tree_match_parse("					\
(	exit								\
	test 								\
	 ([SIN COS SINCOS]						\
	  (%d",&angleRange,",0,,	\"test angle range (degrees)\"	\
	   (%d",&numTimes,",0,,		\"number of samples\")))	\
	time 								\
	 ([sin cos sincos SIN COS SINCOS]				\
	  (%d",&numTimes,",0,,		\"number of iterations\"))	\
	run 								\
	 ([SIN COS SINCOS]						\
	  (%f",&testAngle,",,,		\"angle (degrees)\"))		\
)",0);
	if (keytree == 0)
	 { printf ("ERROR/Parse error at %.30s\n", tree_match_err_at());
	   exit (-1);
	 }
	do
 	 { tree_match (keytree, "SIN TEST> ", key_buf);

	   if (COMMANDS("test"))
	    { double maxDiff = 0.;
	      double check, result, theta;
	      double convert;
	      int i;

	      if (numTimes < intervalDivide)
	       { printf (
"ERROR/ num iterations should exceed num interval divisions\n");
		 continue;
	       }

	      convert = (2 * angleRange * PI) / (numTimes * 180.);

	      if (COMMAND("test SIN"))
	       { for (i = -numTimes/2; i<numTimes/2; i++)
	          { theta = i * convert;
	 	    result = SIN (theta);
	 	    check = sin (theta);

		    if (fabs (result-check) > maxDiff)
		     { maxDiff = fabs (result-check);
		     }
		  }
	       }
	      else if (COMMAND("test COS"))
	       { for (i = -numTimes/2; i<numTimes/2; i++)
	          { theta = i * convert;
	 	    result = COS (theta);
	 	    check = cos (theta);

		    if (fabs (result-check) > maxDiff)
		     { maxDiff = fabs (result-check);
		     }
		  }
	       }
	      else if (COMMAND("test SINCOS"))
	       { float s, c;
		 double sck, cck;
	 	 double maxS, maxC;

		 maxS = maxC = 0.;

	         for (i = -numTimes/2; i<numTimes/2; i++)
	          { theta = i * convert;
		    SINCOS (theta, &s, &c);
		    sck = sin (theta);
		    cck = cos (theta);

		    if (fabs (s-sck) > maxDiff)
		     { maxDiff = fabs(s-sck);
		     }
		    if (fabs (c-cck) > maxDiff)
		     { maxDiff = fabs(c-cck);
		     }
		    if (fabs (s-sck) > maxS)
		     { maxS = fabs(s-sck);
		     }
		    if (fabs (c-cck) > maxC)
		     { maxC = fabs(c-cck);
		     }
		  }
	         printf ("Max sin diff = %lg, max cosine diff = %lg\n",
			 maxS, maxC);
	       }
	      printf ("Maximum error = %lg\n", maxDiff);
	    }
	   else if (COMMANDS ("time"))
	    { double startTime, stopTime;
	      double result;
	      double theta = 1.2345;
	      register int i;
	      startTime = cputime (User);
	      
	      if (COMMAND ("time sin"))
	       { for (i=numTimes; i>0; i--)
		  { result = sin (theta);
		  }
	       }
	      else if (COMMAND ("time cos"))
	       { for (i=numTimes; i>0; i--)
		  { result = cos (theta);
		  }
	       }
	      else if (COMMAND ("time sincos"))
	       { double s, c;
	         for (i=numTimes; i>0; i--)
		  { s = sin (theta);
	 	    c = cos (theta);
		  }
	       }
	      else if (COMMAND ("time SIN"))
	       { for (i=numTimes; i>0; i--)
		  { result = SIN (theta);
		  }
	       }
	      else if (COMMAND ("time COS"))
	       { for (i=numTimes; i>0; i--)
		  { result = COS (theta);
		  }
	       }
	      else if (COMMAND ("time SINCOS"))
	       { double s, c;
	         for (i=numTimes; i>0; i--)
		  { SINCOS (theta, &s, &c);
		  }
	       }
	      stopTime = cputime (User);
	      printf ("Execution time = %lg micro seconds\n", 
		       (stopTime - startTime) * 1000000. / numTimes);
	    }
	   else if (COMMANDS ("run"))
	    { double result;
	      testAngle *= PI / 180.;

	      if (COMMAND ("run SIN"))
	       { result = SIN(testAngle);
	         printf ("%lg\n", result);
	       }
	      else if (COMMAND ("run COS"))
	       { result = COS (testAngle);
		 printf ("%lg\n", result);
	       }
	      else if (COMMAND ("run SINCOS"))
	       { float s, c;
	         SINCOS (testAngle, &s, &c);
	         printf ("sin = %lg  cos = %lg\n", (double)s, (double)c);
	       }
	    }
	 }
	while (!(COMMAND("exit")));
}
