/*  hrdcmp.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include "artherr.h"
#include "debug.h"
#include "hrdcmp.h"
#include "cgidbg.h"
#include "arthfnc.h"


CxMachWord MakeCxMachWord(const complex& arg)
{
	return ((int16) real(arg), (int16) imag(arg));
}

CxAccMachWord MakeCxAccMachWord(const complex& arg)
{
	return ((int32) real(arg), (int32) imag(arg));
}


#define DefineCxMachWordOperators(CxMachWord,MachWord,rl,ig,int16)	\
void CxMachWord::operator+=(const CxMachWord& x)			\
{								\
	rl += MachReal(x);					\
	ig += MachImag(x);					\
}								\
								\
void CxMachWord::operator-=(const CxMachWord& x)			\
{								\
	rl -= MachReal(x);					\
	ig -= MachImag(x);					\
}								\
								\
void CxMachWord::operator*=(const CxMachWord& x)			\
{								\
	rl = rl * MachReal(x) -	ig * MachImag(x) ;		\
	ig = ig * MachReal(x) +	MachImag(x) * rl  ;		\
}								\
								\
void CxMachWord::operator*=(MachWord x)			\
{								\
	rl = rl * x ;						\
	ig = ig * x ;						\
}								\
								\
void CxMachWord::operator/=(const CxMachWord& x) \
{								 \
	complex C((int16)(rl),(int16)(ig)) ; \
	complex D((int16)(MachReal(x)),(int16)(MachImag(x))); \
	complex E = C/D ; \
	rl = (int16) real(E); \
	ig = (int16) imag(E); \
}								 \
								\
void CxMachWord::operator/=(MachWord x)			\
{								\
	rl = rl / x ;						\
	ig = ig / x ;						\
}								\
								\
void CxMachWord::operator&=(const CxMachWord& x)			\
{								\
	rl &= MachReal(x);					\
	ig &= MachImag(x);					\
}								\
								\
void CxMachWord::operator|=(const CxMachWord& x)			\
{								\
	rl |= MachReal(x);					\
	ig |= MachImag(x);					\
}								\
								\
void CxMachWord::operator^=(const CxMachWord& x)			\
{								\
	rl ^= MachReal(x);					\
	ig ^= MachImag(x);					\
}								\
								\
void CxMachWord::operator%=(const CxMachWord& x)			\
{								\
	rl %= MachReal(x);					\
	ig %= MachImag(x);					\
}								\
								\
CxMachWord operator+(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) + MachReal(b) ;			\
	int16 xig = MachImag(a) + MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator-(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) - MachReal(b) ;			\
	int16 xig = MachImag(a) - MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator*(const CxMachWord& a,MachWord b)		\
{								\
	int16 xrl = MachReal(a) * b ;				\
	int16 xig = MachImag(a) * b ;				\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator*(MachWord b,const CxMachWord& a)		\
{								\
	int16 xrl = MachReal(a) * b ;				\
	int16 xig = MachImag(a) * b ;				\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator*(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) * MachReal(b) -			\
		MachImag(a) * MachImag(b)  ;			\
	int16 xig = MachImag(a) * MachReal(b) +			\
		MachImag(b) * MachReal(a)  ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator/(const CxMachWord& a,const CxMachWord& b)	\
{								\
	complex C = ((complex) a)/((complex) b) ;		\
	return CxMachWord((int32)real(C),(int32)imag(C));	\
}
					\
CxMachWord operator/(const CxMachWord& a,MachWord b)	\
{								\
	complex C = ((complex) a)/ b.val() ;		\
	return CxMachWord((int32)real(C),(int32)imag(C));	\
}								\
								\
CxMachWord operator&(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) & MachReal(b) ;			\
	int16 xig = MachImag(a) & MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator|(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) | MachReal(b) ;			\
	int16 xig = MachImag(a) | MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator^(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) ^ MachReal(b) ;			\
	int16 xig = MachImag(a) ^ MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator%(const CxMachWord& a,const CxMachWord& b)	\
{								\
	int16 xrl = MachReal(a) % MachReal(b) ;			\
	int16 xig = MachImag(a) % MachImag(b) ;			\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator<<(const CxMachWord& a,int b)			\
{								\
	int16 xrl = MachReal(a) << b ;				\
	int16 xig = MachImag(a) << b ;				\
	return CxMachWord(xrl,xig);				\
}								\
								\
CxMachWord operator>>(const CxMachWord& a, int b)			\
{								\
	int16 xrl = MachReal(a) >> b ;				\
	int16 xig = MachImag(a) >> b ;				\
	return CxMachWord(xrl,xig);				\
}								\


DefineCxMachWordOperators(CxMachWord,MachWord,rl,ig,int16) 
DefineCxMachWordOperators(CxAccMachWord,AccMachWord,Real,Imag,int32)






int ArithAccCheckOverflow(AccOverflowCheck& Val)
{
	// LogMsg("Enter Check overflow");
	int Return = 0 ;
	if (Val > AccMachWord::max_positive) {
		Val = AccMachWord::max_positive ;
		Return = 1;
	} else if (Val < AccMachWord::min_negative) {
		Val = AccMachWord::min_negative ;
		Return = 1;
	}
	// LogMsg("Exit Acc Check overflow");
	return Return ;
}

int ArithCheckOverflow(OverflowCheck& Val)
{
	// LogMsg("Enter Check overflow");
	int Return = 0 ;
	if (Val > MachWord::max_positive) {
		Val = MachWord::max_positive ;
		Return = 1;
	} else if (Val < MachWord::min_negative) {
		Val = MachWord::min_negative ;
		Return = 1;
	}
	// LogMsg("Exit Check overflow");
	return Return ;
}

static int32 SaveOverflows = 0;

static MachWord CheckOverflowConvert(double Val,int Sign)
{
	// LogOut << "CheckOverflowConvert(" << Val << "," << Sign << ")\n" ;
	if (Val > ((double) MachWord::max_positive) +.99999) {
		// LogOut << "Overflow\n" ;
		MachWord Temp;
		Temp = MachWord::max_positive ;
		Val = int16(Temp) ;
		ReportOverflows(SaveOverflows,SaveOverflows++,
			"generating full scale data");
	}
	MachWord Return = (MachWordCast) Val ;
	if (Sign) Return = -Return ;
	// LogOut << "Returning " << Return << "\n" ;
	return Return ;
}

static MachWord CheckOverflowConvert(double Val,int Sign,int Scale)
{
	MachWord Temp = CheckOverflowConvert(Val,Sign);
	if (!Scale) return Temp ;
	if (Scale > 0) return Temp>>Scale ;
	int OverOcc = 0;
	for (;Scale;Scale++) {
		MachWord PrevTemp = Temp ;
		Temp <<= 1 ;
		if (!OverOcc) if ((PrevTemp * Temp) < (MachWord) (int16) 0) {
			ReportOverflows(SaveOverflows,SaveOverflows++,
				"shifting up full scale data");
			OverOcc = 1;
		}
	}
}


CxMachWord RoundDouble(complex Val)
{
	return CxMachWord(RoundDouble(real(Val)),RoundDouble(imag(Val)));
}

MachWord RoundDouble(double Val)
{
	int Sign = Val < 0 ;
	if (Sign) Val = - Val ;
	return CheckOverflowConvert(Val+.5,Sign);
}


CxMachWord FullScale(complex Val, int Scale)
{
	return CxMachWord(FullScale(real(Val),Scale),
		FullScale(imag(Val),Scale));
}

CxMachWord FullScale(complex Val)
{
	return CxMachWord(FullScale(real(Val)),FullScale(imag(Val)));
}

MachWord FullScale(double Val, int Scale)
{
	int Sign = Val < 0 ;
	if (Sign) Val = - Val ;
	Val = ((double) MachWord::max_positive) * Val + .5 ;
	return CheckOverflowConvert(Val,Sign,Scale);
}

MachWord FullScale(double Val)
{
	// LogOut << "FullScale(" << Val << ")\n" ;
	int Sign = Val < 0 ;
	if (Sign) Val = - Val ;
	int Temp = MachWord::max_positive ;
	Val = ((double) MachWord::max_positive) * Val + .5 ;
	MachWord ret =  CheckOverflowConvert(Val,Sign);
	// LogOut << "Returning " << ret << "\n" ;
	return ret ;
}



void Normalize(MachWord * Array, int32 Size, enum NormalizeOption Opt)
{
	
	MachWord HighLimit ;
	MachWord Max = (int16) 0 ;
	for (int32 i = 0 ; i < Size; i++) {
		MachWord Temp = Array[i];
		if (Temp < (MachWord) (int16) 0) Temp = -Temp ;
		if (Temp > Max) Max = Temp ;
	}
	int Shift = 0;
	if (!Max) return ;
	switch (Opt) {
case NormFull:
		{
			double Factor = ((double)MachWord::max_positive) /(double) int16(Max) ;
			for (i = 0 ; i < Size;i++) Array[i] = Factor * (double)
				int16(Array[i]) ;
			return ;
		}
case NormPower2FFTPass:
		{
			MachWord LowLimit ;
			LowLimit = MachWord::max_positive ;
			LowLimit >>= 3;
			while (Max > LowLimit) {
				Max = Max >> 1 ;
				Shift--;
			} 
		}
		HighLimit = MachWord::max_positive ;
		HighLimit >>= 2 ;
		break ;
case NormPower2Full:
		HighLimit = MachWord::max_positive ;
		HighLimit >>= 1 ;
		break ;
default :
		DbgError("Normalize","bad option");
	}
	while (Max < HighLimit) {
		Max =  Max << 1 ;
		Shift++;
	}
	if (Shift < 0) for (i = 0 ; i < Size ; i++) 
		Array[i] = Array[i] >> -Shift ;
	else if (Shift > 0) for (i = 0 ; i < Size;i++)
		Array[i] = Array[i] << Shift ;
}

void Normalize(CxMachWord * Array, int32 Size, NormalizeOption Option)
{
	Normalize((MachWord *) Array,Size << 1, Option);
}

MachWord AccScale(AccMachWord Val,int Scale)
{
	if (Scale > 0) return (MachWord) (int16) (Val >> (16+Scale)) ;
	Val >>= (16 - Scale) ;
	int32 Temp = MachWord::max_positive ;
	AccMachWord UppLimit = Temp ;
	if (Val > UppLimit || Val < -UppLimit) ReportOverflows(
		SaveOverflows,SaveOverflows++,
			"converting MachWord to AccMachWord");
	return (int16) Val ;
}

MachWord AccScale(AccMachWord Val)
{
	return (MachWord) (int16) (Val >> 15) ;
}


CxMachWord AccScale(CxAccMachWord Val, int Scale)
{
	return CxMachWord(AccScale(MachReal(Val),Scale),
		AccScale(MachImag(Val),Scale));

}

CxMachWord AccScale(CxAccMachWord Val)
{
	return CxMachWord(AccScale(MachReal(Val)),
		AccScale(MachImag(Val)));

}

complex GetComplexFromPtr(MachWord * v) 
{
	return complex(GetDoubleFromPtr(v));
}

complex GetComplexFromPtr(AccMachWord * v)
{
	return complex(GetDoubleFromPtr(v));
}

complex GetComplexFromPtr(CxMachWord * v)
{
	return complex((double)v->rl.value,(double)v->ig.value);
}

complex GetComplexFromPtr(CxAccMachWord * v)
{
	return complex((double)v->Real.value,(double)v->Imag.value);
}


