#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>

#define CPUTIME (getrusage(RUSAGE_SELF,&ruse),\
  ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec + \
  1e-6 * (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec))

struct rusage ruse;

extern int getrusage();

typedef int fixed;

#define LOOP_COUNT   200000000

/* ftofix and fixtof are used in generic C versions of fixmul and fixdiv */
inline fixed ftofix(double x)
{
   if (x > 32767.0) {
      return 0x7FFFFFFF;
   }

   if (x < -32767.0) {
      return -0x7FFFFFFF;
   }

   return (int)(x * 65536.0 + (x < 0 ? -0.5 : 0.5));
}


inline double fixtof(fixed x)
{
   return (double)x / 65536.0;
}

inline fixed fixmulf(fixed x, fixed y)
{
   return ftofix(fixtof(x) * fixtof(y));
}

inline fixed fixmull(fixed x, fixed y)
{
   long long lx = x;
   long long ly = y;
   long long lres = (lx*ly)>>16;
   int res = lres;
   return res;
}

inline fixed fixmuli(fixed x, fixed y)
{
   fixed sign = (x^y) & 0x80000000;
   int mask_x = x >> 31;
   int mask_y = y >> 31;
   int mask_result = sign >> 31;
   fixed result;

   x = (x^mask_x) - mask_x;
   y = (y^mask_y) - mask_y;

   result = ((y >> 8)*(x >> 8) +
             (((y >> 8)*(x&0xff)) >> 8) +
             (((x >> 8)*(y&0xff)) >> 8));

   return (result^mask_result) - mask_result;
}

inline fixed fixdivf(fixed x, fixed y)
{
   if (y == 0) {
      return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF;
   }
   else
      return ftofix(fixtof(x) / fixtof(y));
}

inline fixed fixdivl(fixed x, fixed y)
{
   if (y == 0) {
      return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF;
   }
   else {
      long long lx = x;
      long long ly = y;
      long long lres = (lx << 16) / ly;
      int res = lres;
      return res;
   }
}

int main(void)
{
   double t0, t1;
   time_t u1,u2;
   fixed x, y, z;
   fixed zacc;
   int c;
   
   printf("sizeof(long long) = %d, sizeof(fixed) = %d\n", sizeof(long long), sizeof(fixed));

   printf("Timing %d calls to fixmulf...", LOOP_COUNT);
   fflush(stdout);
   zacc = 0;
   t0 = CPUTIME;
   /* place code to be timed here */
   for (c=0; c<LOOP_COUNT; c++) {
      z = fixmulf(x,y);
      x += 1317;
      y += 7143;
      zacc += z;
   }
   t1 = CPUTIME;
   printf("CPU time = %f secs.\n",t1-t0);
   printf("zacc = %d\n",zacc);

   printf("Timing %d calls to fixmuli...", LOOP_COUNT);
   fflush(stdout);
   zacc = 0;
   t0 = CPUTIME;
   /* place code to be timed here */
   for (c=0; c<LOOP_COUNT; c++) {
      z = fixmuli(x,y);
      x += 1317;
      y += 7143;
      zacc += z;
   }
   t1 = CPUTIME;
   printf("CPU time = %f secs.\n",t1-t0);
   printf("zacc = %d\n",zacc);

   printf("Timing %d calls to fixmull...", LOOP_COUNT);
   fflush(stdout);
   zacc = 0;
   t0 = CPUTIME;
   /* place code to be timed here */
   for (c=0; c<LOOP_COUNT; c++) {
      z = fixmull(x,y);
      x += 1317;
      y += 7143;
      zacc += z;
   }
   t1 = CPUTIME;
   printf("CPU time = %f secs.\n",t1-t0);
   printf("zacc = %d\n",zacc);

   printf("Timing %d calls to fixdivf...", LOOP_COUNT);
   fflush(stdout);
   zacc = 0;
   t0 = CPUTIME;
   /* place code to be timed here */
   for (c=0; c<LOOP_COUNT; c++) {
      z = fixdivf(x,y);
      x += 1317;
      y += 7143;
      zacc += z;
   }
   t1 = CPUTIME;
   printf("CPU time = %f secs.\n",t1-t0);
   printf("zacc = %d\n",zacc);

   printf("Timing %d calls to fixdivl...", LOOP_COUNT);
   fflush(stdout);
   zacc = 0;
   t0 = CPUTIME;
   /* place code to be timed here */
   for (c=0; c<LOOP_COUNT; c++) {
      z = fixdivl(x,y);
      x += 1317;
      y += 7143;
      zacc += z;
   }
   t1 = CPUTIME;
   printf("CPU time = %f secs.\n",t1-t0);
   printf("zacc = %d\n",zacc);

   return 0;
}
