Blob Blame Raw


#ifndef T_INTERVAL_INCLUDED
#define T_INTERVAL_INCLUDED

#include <assert.h>
#include <limits.h>
#include "tcommon.h"

#undef DVAPI
#undef DVVAR
#ifdef TNZCORE_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//=============================================================================

//  class TInterval implementa "Interval Arithmetic" (non vengono computati gli
//  errori macchina):
//  TInterval(min, max) (min <= max) rapresenta l'intervallo reale chiuso [min, max];
//  per m_min == m_max si ottiene l'algebra dei reali;
//  TInterval (m_min = 1, m_max = -1) rappresenta l'intervallo vuoto

class TInterval
{
	double m_min, m_max;

public:
	//  costruisce l'intervallo vuoto
	//  TInterval (m_min = 1, m_max = -1) rappresenta l'intervallo vuoto
	TInterval() : m_min(1), m_max(-1) {}
	//-----------------------------------------------------
	//  costruisce gli intervalli degeneri [x, x] che rappresentano i reali
	TInterval(double x) : m_min(x), m_max(x) {}
	//-----------------------------------------------------
	TInterval(double min, double max)
	{
		assert(min <= max); //  non vuoto
		m_min = min;
		m_max = max;
	}
	//-----------------------------------------------------
	TInterval(const TInterval &w)
	{
		assert(w.m_min <= w.m_max ||
			   (w.m_min == 1 && w.m_max == -1)); //  intervallo vuoto
		m_min = w.m_min;
		m_max = w.m_max;
	}
	//-----------------------------------------------------
	inline TInterval &operator=(const TInterval &w)
	{
		assert(w.m_min <= w.m_max ||
			   (w.m_min == 1 && w.m_max == -1)); //  intervallo vuoto
		m_min = w.m_min;
		m_max = w.m_max;
		return *this;
	}
	//-----------------------------------------------------
	inline TInterval operator+() const
	{
		assert(m_min <= m_max); //  non vuoto
		return *this;
	}
	//-----------------------------------------------------
	inline TInterval operator-() const
	{
		assert(m_min <= m_max); //  non vuoto
		return TInterval(-m_max, -m_min);
	}
	//-----------------------------------------------------
	inline TInterval operator+(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		return TInterval(m_min + w.m_min, m_max + w.m_max);
	}
	//-----------------------------------------------------
	inline TInterval operator-(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		return TInterval(m_min - w.m_max, m_max - w.m_min);
	}
	//-----------------------------------------------------
	inline TInterval operator*(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		double value[4];
		value[0] = m_min * w.m_min;
		value[1] = m_min * w.m_max;
		value[2] = m_max * w.m_min;
		value[3] = m_max * w.m_max;
		double minValue = value[0];
		double maxValue = value[0];
		int i = 1;
		for (i = 1; i <= 3; ++i) {
			if (value[i] < minValue)
				minValue = value[i];
			if (value[i] > maxValue)
				maxValue = value[i];
		}
		return TInterval(minValue, maxValue);
	}
	//-----------------------------------------------------
	inline TInterval operator/(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		assert((0 < w.m_min && 0 < w.m_max) ||
			   (0 > w.m_min && 0 > w.m_max)); //  divisore non nullo
		double value[4];
		value[0] = m_min / w.m_min;
		value[1] = m_min / w.m_max;
		value[2] = m_max / w.m_min;
		value[3] = m_max / w.m_max;
		double minValue = value[0];
		double maxValue = value[0];
		int i = 1;
		for (i = 1; i <= 3; ++i) {
			if (value[i] < minValue)
				minValue = value[i];
			if (value[i] > maxValue)
				maxValue = value[i];
		}
		return TInterval(minValue, maxValue);
	}
	//-----------------------------------------------------
	inline bool operator==(const TInterval &w) const
	{
		assert(w.m_min <= w.m_max ||
			   (w.m_min == 1 && w.m_max == -1)); //  intervallo vuoto
		return (m_min == w.m_min && m_max == w.m_max);
	}
	//-----------------------------------------------------
	/*  la definizione e' discutibile...
  inline bool operator!=(const TInterval &w) const 
  {return (m_min != w.m_min  ||  m_max != w.m_max);}
  */
	//-----------------------------------------------------
	inline bool operator>(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		return (m_min > w.m_max);
	}
	//-----------------------------------------------------
	inline bool operator<(const TInterval &w) const
	{
		assert(m_min <= m_max);		//  non vuoto
		assert(w.m_min <= w.m_max); //  non vuoto
		return (m_max < w.m_min);
	}
	//-----------------------------------------------------
	/*  la definizione e' discutibile...
    //  A >= B  
    inline bool operator>=(const TInterval &w) const {
    assert (m_min <= m_max);  //  non vuoto
    assert (w.m_min <= w.m_max);  //  non vuoto
    return (m_min >= w.m_min && m_max >= w.m_max);}
  //-----------------------------------------------------
    //  A <= B
    inline bool operator<=(const TInterval &w) const {
    assert (m_min <= m_max);  //  non vuoto
    assert (w.m_min <= w.m_max);  //  non vuoto
    return (m_min <= w.m_min  && m_max <= w.m_max);}
  */
	//-----------------------------------------------------
	inline void setMin(double min)
	{
		assert(m_min <= m_max); //  non vuoto
		assert(min <= m_max);   //  non vuoto dopo setMin
		m_min = min;
	}
	//-----------------------------------------------------
	inline void setMax(double max)
	{
		assert(m_min <= m_max); //  non vuoto
		assert(m_min <= max);   //  non vuoto dopo setMax
		m_max = max;
	}
	//-----------------------------------------------------
	inline double getMin() const
	{
		//  isEmpty() => return 1
		return m_min;
	}
	//-----------------------------------------------------
	inline double getMax() const
	{
		//  isEmpty() => return -1
		return m_max;
	}
	//-----------------------------------------------------
	inline double getLength() const { return m_max - m_min; } //  isEmpty() => (getLength() < 0)
	//-----------------------------------------------------
	inline double getCenter() const
	{
		assert(m_min <= m_max); //  non vuoto
		return (m_max + m_min) / 2;
	}
	//-----------------------------------------------------
	inline double getRadius() const
	{
		assert(m_min <= m_max); //  non vuoto
		return (m_max - m_min) / 2;
	}
	//-----------------------------------------------------
	inline bool isEmpty() const
	{
		//  TInterval (m_min = 1, m_max = -1) rappresenta l'intervallo vuoto
		assert(m_min <= m_max ||
			   (m_min == 1 && m_max == -1)); //  intervallo vuoto
		return (m_min > m_max);
	}

	//-----------------------------------------------------
	inline bool isProper() const
	{
		//  isProper() <=> !isEmpty() && m_min < m_max (cioe' non degenere)
		//  TInterval (m_min = 1, m_max = -1) rappresenta l'intervallo vuoto
		assert(m_min <= m_max ||
			   (m_min == 1 && m_max == -1)); //  intervallo vuoto
		return (m_min < m_max);
	}
	//-----------------------------------------------------
	inline bool contain(double t) const
	{
		assert(m_min <= m_max ||
			   (m_min == 1 && m_max == -1)); //  intervallo vuoto
		return (m_min <= t && t <= m_max);
	} //  isEmpty() => return false
	//-----------------------------------------------------
	inline bool include(const TInterval &interval) const
	{
		if (interval.isEmpty())
			return true;
		else if (isEmpty())
			return false;
		else {
			assert(!interval.isEmpty() && !isEmpty());
			return (m_min <= interval.m_min && interval.m_max <= m_max);
		}
	}
	//-----------------------------------------------------
	inline bool isIncluded(const TInterval &interval) const
	{
		if (isEmpty())
			return true;
		else if (interval.isEmpty())
			return false;
		else {
			assert(!isEmpty() && !interval.isEmpty());
			return (interval.m_min <= m_min && m_max <= interval.m_max);
		}
	}
	//-----------------------------------------------------
	// Friend helper function declarations
	friend TInterval operator*(const double s, const TInterval &w);
	friend TInterval intersection(const TInterval &a, const TInterval &b);
	friend TInterval square(const TInterval &w);
	friend TInterval sqrt(const TInterval &w);
};
//---------------------------------------------------------------------------
//friend functions
inline TInterval operator*(const double s, const TInterval &w)
{
	assert(w.m_min <= w.m_max); //  non vuoto
	if (s >= 0)
		return TInterval(s * w.m_min, s * w.m_max);
	else
		return TInterval(s * w.m_max, s * w.m_min);
}
//---------------------------------------------------------------------------
inline TInterval square(const TInterval &w)
{
	//  return w^2
	assert(w.m_min <= w.m_max); //  non vuoto
	double a = w.m_min * w.m_min;
	double b = w.m_max * w.m_max;
	if (0 <= w.m_min)
		return TInterval(a, b); //  return [m_min^2, m_max^2]
	else if (w.m_max <= 0)
		return TInterval(b, a); //  return [m_max^2, m_min^2]
	else {
		assert(w.m_min < 0 && 0 < w.m_max);
		return TInterval(0, tmax(a, b)); //  [0, max(w.m_min^2, w.m_max^2)]
	}
}
//-----------------------------------------------------
inline TInterval sqrt(const TInterval &w)
{
	//  return sqrt(w)
	assert(w.m_min <= w.m_max); //  non vuoto
	assert(0 <= w.m_min);
	return TInterval(sqrt(w.m_min), sqrt(w.m_max));
} //  [sqrt(w.m_min), sqrt(w.m_max)]
//-----------------------------------------------------
//  helper function
inline TInterval intersection(const TInterval &a, const TInterval &b)
{
	//  return a_intersezione_b (insiemistico) se questa e' non vuota, altrimenti
	//  return TInterval() (intervallo vuoto)
	double min = tmax(a.m_min, b.m_min);
	double max = tmin(a.m_max, b.m_max);
	if (min <= max) //  a.isEmpty() || b.isEmpty() => (min >= 1 && max <= -1) => min > max
		return TInterval(min, max);
	else
		return TInterval(); //  intervallo vuoto
}
//-----------------------------------------------------
inline TInterval createTInterval(double center, double radius)
{
	if (radius >= 0)
		return TInterval(center - radius, center + radius);
	else
		return TInterval(); //  intervallo vuoto
}
//-----------------------------------------------------
inline TInterval createErrorTInterval(double center,
									  double minError =
										  (std::numeric_limits<double>::min)())
{
	//  type double standard IEEE (1 bit segno + 11 bit esponente + 52 bit mantissa)
	//  corrisponde ad almeno 15 decimali significativi.
	//  minError serve ad assegnare un errore positivo quando center = 0.
	//  Aumentare 100 volte (da 1e-15 a 1e-13) l'errore relativo serve a compensare
	//  la propagazione degli errori macchina (TInterval non li computa) ed a
	//  stabilizzare il codice relativamente a processori che potrebbero male
	//  implementare l'artimetica double standard IEEE.
	assert(minError >= 0);
	const double relativeDoubleError = 1e-13;
	double error = tmax(fabs(center) * relativeDoubleError, minError);
	return TInterval(center - error, center + error);
}
//-----------------------------------------------------

#endif //  __T_INTERVAL_INCLUDED__