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

/*=~=~=~=~ McGill-Computer-Vision-and-Robotics-Laboratory--C-Module ~=~=~=~=
 *		
 * MODULE NAME:	integerOp
 *
 * DESCRIPTION:	The functions which implement operator functions on the
 *		integer data types.
 * 
 * AUTHOR/DATE:	John Lloyd, Summer 1987
 *
 *~=~=~=~=~=~= McGill-Computer-Vision-and-Robotics-Laboratory ~=~=~=~=~=~=*/

#include <errno.h>
#include <math.h>
#include "cdefs.h"
#include "types.h"
#include "parameters.h"

extern int errno;

#define IABS(x) ((x) < 0 ? -(x) : (x))

static int productSign (x, y)
int x, y;
{
	if (x == 0 || y == 0)
	 { return (0);
	 }
	else if ( (x < 0 && y > 0) || (x > 0 && y < 0) )
	 { return (-1);
	 }
	else
	 { return (1);
	 }
}

copyInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	r->val.i = a[0].val.i;
	return (1);
}

addInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (a[1].val.i > 0)
	 { if (a[0].val.i > IHUGE - a[1].val.i)
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	else 
	 { if (a[0].val.i < (-IHUGE-1) - a[1].val.i)
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.i = a[0].val.i + a[1].val.i;

	return (1);
}

subtractInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (a[1].val.i > 0)
	 { if (a[0].val.i < (-IHUGE-1) + a[1].val.i)
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	else 
	 { if (a[0].val.i > IHUGE + a[1].val.i)
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.i = a[0].val.i - a[1].val.i;

	return (1);
}

divideInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (a[1].val.i == 0)
	 { error (0, "%s -- divide by zero detected\n", r->name);
	   return (-1);
	 }
	r->val.i = a[0].val.i / a[1].val.i;

	return (1);
}

multiplyInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (productSign (a[0].val.i, a[1].val.i) == 1)
	 { if (IABS(a[0].val.i) > IHUGE / IABS(a[1].val.i))
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	else if (productSign (a[0].val.i, a[1].val.i) == -1)
         { if (-IABS(a[0].val.i) < (-IHUGE-1) / IABS(a[1].val.i))
	    { error (0, "%s -- integer overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.i = a[0].val.i * a[1].val.i;

	return (1);
}

modInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (a[1].val.i == 0)
	 { error (0, "%s -- divide by zero detected\n", r->name);
	   return (-1);
	 }
	r->val.i = a[0].val.i % a[1].val.i;

	return (1);
}

powerInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	double f1, f2, fr;

	errno = 0;
	f1 = a[0].val.i;
	f2 = a[1].val.i;
	fr = pow (f1, f2);
	if (fr == 0. && errno == EDOM)
	 { error (0, "%s -- integer overflow detected\n", r->name);
	   return (-1);
	 }
      	else if (fr == HUGE && errno == ERANGE)
	 { error (0, "%s -- integer overflow detected\n", r->name);
	   return (-1);
	 }
	else if (!(fr < (IHUGE + .5)))
	 { error (0, "%s -- integer overflow detected\n", r->name);
	   return (-1);
	 }
	else if (!(fr > (-IHUGE- 1.5)))
	 { error (0, "%s -- integer overflow detected\n", r->name);
	   return (-1);
	 }
 	r->val.i = fr;

	return (1);
}

negateInteger (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	r->val.i = -a[0].val.i;
	return (1);
}
