#include <stdio.h>         /* everybody needs this */

#ifndef PDOS /* {{ */      /* PDOS is wierd */

#ifndef REALIX /* {{ */    /* REAL/IX doesn't have stdlib.h */
#include <stdlib.h>
#endif /* REALIX }} */

#include <string.h>
#include <time.h>

#ifndef __MSDOS__ /* {{ */

#if defined(UNIX_Old) || defined(VMS) /* {{ */
#define TIMES            /* Use times() time function */
#endif /* defined }} */

#else /* }{ */

#define TICS    *(long far *)0x0000046CL
#define HZ      (1 / 0.055)

#endif /* !__MSDOS__ }} */

#ifdef TIMES /* {{ */
#ifndef VMS /* {{ */
#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>
#else /* }{ */
#define HZ      60         /* this is a guess for VMS */
#endif /* VMS }} */

#else /* }{ */

#include <sys/resource.h>

#endif /* TIMES }} */

#else /* }{ */

#include "SYRAM:H"
#define TICS    _syram->_tics
#define HZ      100

#endif /* !PDOS }} */


#define PIITER  2925
#define ARYSIZ  8136
#define SORSIZ   196
#define SIVSIZ  8450
#define LOOPS   1000

#define MTHMARK (10.0 * 4.25)
#define ARYMARK (10.0 * 4.24)
#define SIVMARK (10.0 * 4.24)
#define SORMARK (10.0 * 4.23)
#define ACKMARK (10.0 * 4.25)
#define TOTMARK (MTHMARK + ARYMARK + SIVMARK + SORMARK + ACKMARK)


#ifdef REG                 /* define REG to explicitly use register vars */
#undef REG                 /* PDOS needs this since it is stupid */
#define REG register
#else
#define REG
#endif


double starttime;
double benchtime;
double nulltime;


#ifdef _STDC_ /* {{ */

double gettime(void);
double calc_pi(void);
void array(void);
void cpymem(int *, int *, int);
void sort(void);
void selection_sort(int [], int);
void sieve(void);
long ackerman(long, long);

#else /* }{ */

double gettime();
double calc_pi();
void array();
void cpymem();
void sort();
void selection_sort();
void sieve();
long ackerman();

#endif /* _STDC_ }} */


int main(argc, argv)
int argc;
char *argv[];
{
   REG int i;
   REG int loops;
   REG double b = 0.0, ba = 0.0;
   int dummy;

   if (argc > 1)
   {
      loops = atoi(argv[1]);
   }
   else
   {
      loops = LOOPS;
   }

   starttime = gettime();

   dummy = 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
   }

   nulltime = gettime() - starttime;

   printf("\n%d iterations\n\n     Math Index: ", loops);

   starttime = gettime();

   dummy= 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
      calc_pi();
   }

   if ((benchtime = gettime() - starttime - nulltime) == 0.0)
   {
      fputs("too few iterations\n", stderr);
   }
   else
   {
#ifndef SECS
      printf("%5.1f\n", (MTHMARK * (double)loops / LOOPS) / benchtime);
#else
      printf("%5.4f\n", benchtime);
#endif
      b += benchtime;
      ba += (MTHMARK * (double)loops / LOOPS) / benchtime;
   }

   printf("    Array Index: ");

   starttime = gettime();

   dummy = 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
      array();
   }

   if ((benchtime = gettime() - starttime - nulltime) == 0.0)
   {
      fputs("too few iterations\n", stderr);
   }
   else
   {
#ifndef SECS
      printf("%5.1f\n", (ARYMARK * (double)loops / LOOPS) / benchtime);
#else
      printf("%5.4f\n", benchtime);
#endif
      b += benchtime;
      ba += (ARYMARK * (double)loops / LOOPS) / benchtime;
   }

   printf("  Sorting Index: ");

   starttime = gettime();

   dummy = 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
      sort();
   }

   if ((benchtime = gettime() - starttime - nulltime) == 0.0)
   {
      fputs("too few iterations\n", stderr);
   }
   else
   {
#ifndef SECS
      printf("%5.1f\n", (SORMARK * (double)loops / LOOPS) / benchtime);
#else
      printf("%5.4f\n", benchtime);
#endif
      b += benchtime;
      ba += (SORMARK * (double)loops / LOOPS) / benchtime;
   }

   printf("    Sieve Index: ");

   starttime = gettime();

   dummy = 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
      sieve();
   }

   if ((benchtime = gettime() - starttime - nulltime) == 0.0)
   {
      fputs("too few iterations\n", stderr);
   }
   else
   {
#ifndef SECS
      printf("%5.1f\n", (SIVMARK * (double)loops / LOOPS) / benchtime);
#else
      printf("%5.4f\n", benchtime);
#endif
      b += benchtime;
      ba += (SIVMARK * (double)loops / LOOPS) / benchtime;
   }

   printf("Recursion Index: ");

   starttime = gettime();

   dummy = 0;
   for (i = 0; i < loops; i++)
   {
      dummy++;
      ackerman(3L, 4L);
   }

   if ((benchtime = gettime() - starttime - nulltime) == 0.0)
   {
      fputs("too few iterations\n", stderr);
   }
   else
   {
#ifndef SECS
      printf("%5.1f\n", (ACKMARK * (double)loops / LOOPS) / benchtime);
#else
      printf("%5.4f\n", benchtime);
#endif
      b += benchtime;
      ba += (ACKMARK * (double)loops / LOOPS) / benchtime;
   }

#ifndef SECS
   printf("\nSchmidt Computing Index: %5.1f,%5.1f\n", (TOTMARK * (double)loops / LOOPS) / b, ba / 5);
#else
   printf("\nSchmidt Computing Index: %5.4f\n", b);
#endif

   return 0;

} /* main */


double gettime()
{
#ifdef __MSDOS__
   return (double)TICS / HZ;
#endif

#ifdef PDOS
   return (double)TICS / HZ ;
#endif

#ifdef TIMES /* {{ */

#ifndef VMS /* {{ */
   struct tms  tm;
#else /* }{ */
   struct tbuffer tm;
#endif /* }} */

   times(&tm);

#ifndef VMS
   return (double)tm.tms_utime / HZ;
#else
   return (double)tm.proc_user_time / HZ;
#endif

#else /* }{ */

   struct rusage ru;

   getrusage(RUSAGE_SELF, &ru);

   return (double)ru.ru_utime.tv_sec + ru.ru_utime.tv_usec * 1.0e-6;

#endif /* TIMES }} */

} /* gettime */


double calc_pi()
{
   REG int i;
   double d = 0;

   for (i = 0; i < PIITER; i++)
   {
      d += (i % 2 == 0 ? 1 : -1) * 4.0 / (i * 2 + 1);
   }

   return d;

} /* calc_pi */


void array()
{
   int buff1[ARYSIZ], buff2[ARYSIZ];
   REG int i;

   for (i = 0; i < ARYSIZ; i++)
   {
      buff1[i] = i;
   }

   cpymem(buff2, buff1, ARYSIZ);

   i = 0;
   while (i < ARYSIZ && buff2[i] != (ARYSIZ / 10) * 9)
   {
      i++;
   }

} /* array */


void cpymem(dst, src, len)
REG int *dst;
REG int *src;
REG int len;
{
   while (len--)
   {
      dst[len] = src[len];
   }

} /* cpymem */


void sort()
{
   int buff1[SORSIZ];
   REG int i;

   for (i = 0; i < SORSIZ; i++)
   {
      buff1[i] = i * 3 % SORSIZ;
   }

   selection_sort(buff1, SORSIZ);

} /* sort */


void selection_sort(list, n)
REG int list[];
REG int n;
{
   REG int i;
   REG int j;
   REG int k;

   for (i = 0; i < n; i++)
   {
      k = i;
      for (j = i+1; j < n; j++)
      {
         if (list[j] < list[k])
         {
            k = j;
         }
      }

      j = list[i];
      list[i] = list[k];
      list[k] = j;
   }

} /* selection_sort */


void sieve()
{
   char flags[SIVSIZ+1];
   REG int i;
   REG int k;
   REG int prime;

   for (i = 0; i <= SIVSIZ; ++i)
   {
      flags[i] = 1;
   }

   for (i = 0; i <= SIVSIZ; ++i)
   {
      if (flags[i])
      {
         prime = i + i + 3;
         for (k = i + prime; k <= SIVSIZ; k += prime)
         {
            flags[k] = 0;
         }
      }
   }

} /* sieve */


long ackerman(x, y)
long x, y;
{
   if (x == 0)
   {
      return(y+1);
   }

   if (y == 0)
   {
      return(ackerman(x-1, 1L));
   }

   return(ackerman(x-1, ackerman(x, y-1)));

} /* ackerman */
