/*
 *  artherr.C from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */

#include <stream.h>
#include "artherr.h"
#include "usercom.h"
#include "portable.h"
#include "arthtyp.h"
#include "hrdarth.h"
#include "yacintfc.h"
#ifdef INTERACTIVE
#include "dspe_app.h"
#include "cgidbg.h"
#endif
#include <float.h>


void ReportOverflows(int32 NumberOfOverflows, int32 SaveOverflows,
	const char * Where)
{
#ifdef INTERACTIVE
	int HowOften = DspApplication::overflow_check_limit();
#else
	const HowOften = 400 ;
#endif
	// Report overflows if this is the first or if we exceed
	// a multiple of HowOften
	if (!SaveOverflows) State.Warning(dec(NumberOfOverflows + SaveOverflows),
		" total overflows in `",Where,"'");
	 else if (NumberOfOverflows/HowOften > SaveOverflows/HowOften) {
		HelpOut << NumberOfOverflows + SaveOverflows << 
		" total overflows in `" << Where << "'.\n" ;
	}
#ifdef INTERACTIVE
	if (DspApplication::is_trace())
		TheLog << NumberOfOverflows << " new overflow with a total of "
			<< NumberOfOverflows + SaveOverflows << " in `" <<
			Where << "'.\n" ;
#endif
}

// These two routines do not give warnings and are used in
// static initializers.

MachWord NormToHardLimitMachWord(double v)
{ 
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < MachWord::min_negative) v = MachWord::min_negative;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > MachWord::max_positive) v = MachWord::max_positive;
	}
	return (MachWordCast) v ;
}

AccMachWord NormToHardLimitAccMachWord(double v)
{
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < AccMachWord::min_negative) v = AccMachWord::min_negative;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > AccMachWord::max_positive) v = AccMachWord::max_positive;
	}
	return (AccMachWordCast) v ;
}



MachWord NormToMachWord(double v)
{ 
	int warn = 0 ;
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < MachWord::min_negative) v = MachWord::min_negative,warn=1 ;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > MachWord::max_positive) v = MachWord::max_positive,warn=1 ;
	}
	if (warn) MachWord::hard_limit_warn();
	return (MachWordCast) v ;
}

AccMachWord NormToAccMachWord(double v)
{
	int warn = 0 ;
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < AccMachWord::min_negative) v = AccMachWord::min_negative,warn=1 ;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > AccMachWord::max_positive) v = AccMachWord::max_positive,warn=1 ;
	}
	if (warn) MachWord::hard_limit_warn("AccMachWord");
	return (AccMachWordCast) v ;
}



void MachWord::hard_limit_warn(const char * type)
{
	State.Warning("`", type, "' overflow, value has been hard limited");
#ifdef INTERACTIVE
        if (DspApplication::is_trace()) TheLog << "`" << type <<
            "' overflow, value has been hard limited.\n"  ;
#endif

}


IntegerMachWord MachWord::convert_int_check(int32 v)
{
	int warn = 0 ;
	if (v > max_int_positive) v = max_int_positive,warn=1;
	else if (v < min_int_negative) v = min_int_negative,warn=1;
	if (warn) hard_limit_warn("IntegerMachWord");
	return v ;
}

UnsignedIntegerMachWord MachWord::convert_unsigned_int_check(int32 v)
{
    int warn = 0 ;
    if (v > max_unsigned_int) v = max_unsigned_int,warn=1;
    else if (v < 0) v = 0,warn=1;
    if (warn) hard_limit_warn("UsignedIntegerMachWord");
	return v ;
}

IntegerMachWord MachWord::convert_int_check(double v)
{
	int warn = 0 ;
	if (v > max_int_positive) v = max_int_positive,warn=1;
	else if (v < min_int_negative) v = min_int_negative,warn=1;
	if (warn) hard_limit_warn("IntegerMachWord");
	return (IntegerMachWord) v ;
}

UnsignedIntegerMachWord MachWord::convert_unsigned_int_check(double v)
{
    int warn = 0 ;
    if (v > max_unsigned_int) v = max_unsigned_int,warn=1;
    else if (v < 0) v = 0,warn=1;
    if (warn) hard_limit_warn("UsignedIntegerMachWord");
	return (UnsignedIntegerMachWord) v ;
}

int32 MachWord::convert_int32_check(MachWord vv)
{
	MachWordCast v = vv.val();
	int warn = 0 ;
	int32 val ;
	int32 min = -0x80000000 ;
	int32 max =  0x7fffffff;
	if (v < min) val = min, warn = 1 ;
	if (v > max) val = max, warn = 1 ;
	if (warn) hard_limit_warn("int32");
	else val = (int32) v ;
	return val ;
}

IntegerMachWord MachWord::convert_check(MachWord vv)
{
	MachWordCast v = vv.val() ;
	int warn = 0 ;
	IntegerMachWord val ;
	if (v < min_int_negative) val = min_int_negative,warn = 1 ;
	if (v > max_int_positive) val = max_int_positive,warn = 1 ;
	if (warn) hard_limit_warn("IntegerMachWord");
	else val = (IntegerMachWord) v ;
	return val ;
}

MachWordCast MachWord::convert_MachWord_check(IntegerMachWord v)
{
	int warn = 0 ;
	MachWordCast val ;
	if (v < min_negative) val = min_negative, warn = 1 ;
	if (v > max_positive) val = max_positive, warn = 1 ;
	if (warn) hard_limit_warn();
	else val = (MachWordCast) v ;
	return val ;
}


