/*-=-=-=-=-=-=-=-=-=-=-=- 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:	doubleOp
 *
 * DESCRIPTION:	The functions which implement operator functions on the
 *		double (floating) data types.
 * 
 * AUTHOR/DATE:	John Lloyd, Summer 1987
 *
 *~=~=~=~=~=~= McGill-Computer-Vision-and-Robotics-Laboratory ~=~=~=~=~=~=*/

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

extern int errno;

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

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

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

subtractDouble (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	if (a[1].val.d > 0)
	 { if (a[0].val.d < -HUGE + a[1].val.d)

	    { error (0, "%s -- floating overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	else 
	 { if (a[0].val.d > HUGE + a[1].val.d)
	    { error (0, "%s -- floating overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.d = a[0].val.d - a[1].val.d;
	return (1);
}

divideDouble (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
        if (a[1].val.d == 0.)
	 { error (0, "%s -- divide by zero detected\n", r->name);
	   return (-1);
	 }
	if (fabs (a[1].val.d) < 1.)
	 { if (fabs (a[0].val.d) > fabs (HUGE * a[1].val.d))
	    { error (0, "%s -- floating overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.d = a[0].val.d / a[1].val.d;

	return (1);
}

multiplyDouble (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
        if (fabs (a[0].val.d) > 1. && fabs (a[1].val.d) > 1.)
	 { if (fabs (a[0].val.d) >  fabs (HUGE / a[1].val.d))
	    { error (0, "%s -- floating overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	r->val.d = a[0].val.d * a[1].val.d;

	return (1);
}

modDouble (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	int i;

	if (a[1].val.d == 0.)
	 { error (0, "%s -- divide by zero detected\n", r->name);
	   return (-1);
	 }
	if (IABS (a[1].val.d) < 1.)
	 { if (IABS (a[0].val.d) > IABS (IHUGE * a[1].val.d))
	    { error (0, "%s -- floating overflow detected\n", r->name);
	      return (-1);
	    }
	 }
	i = a[0].val.d / a[1].val.d;
	r->val.d = a[1].val.d * ((a[0].val.d / a[1].val.d) - i);

	return (1);
}

powerDouble (r, n, a)
GTYPE *r;
int n;
GTYPE *a;
{
	errno = 0;
	r->val.d = pow (a[0].val.d, a[1].val.d);
	if (r->val.d == 0. && errno == EDOM)
	 { error (0, "%s -- floating overflow detected\n", r->name);
	   return (-1);
	 }
	else if (r->val.d == HUGE && errno == ERANGE)
	 { error (0, "%s -- floating overflow detected\n", r->name);
	   return (-1);
	 }
	return (1);
}

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