// ============================================================================ // // Copyright (c) 1998,1999 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------------- // // release : // release_date : // // file : include/CGAL/Interval_arithmetic.h // revision : $Revision$ // revision_date : $Date$ // package : Interval Arithmetic // author(s) : Sylvain Pion // // coordinator : INRIA Sophia-Antipolis () // // ============================================================================ #ifndef CGAL_INTERVAL_ARITHMETIC_H #define CGAL_INTERVAL_ARITHMETIC_H // This file contains the description of the two classes: // - Interval_nt_advanced (do the FPU rounding mode changes yourself) // - Interval_nt ("plug-in" version, derived from the other one) // // The differences are: // - The second one is slower. // - The first one supposes the rounding mode is set -> +infinity before // nearly all operations, and might set it -> +infinity when leaving, whereas // the second leaves the rounding -> nearest. #include #include #include // For io_Operator(). #include // For number_type_tag() #include // For is_valid() and is_finite(). #include // Because we overload {sign,compare,abs,min,max} #include // For max and square #include // FPU rounding mode functions. #include // For convert_to<>() CGAL_BEGIN_NAMESPACE struct Interval_nt_advanced { typedef Interval_nt_advanced IA; struct unsafe_comparison{}; // Exception class. static const double min_double, max_double; // Usefull constants. static const IA largest, smallest; protected: double inf, sup; // "inf" stores the OPPOSITE of the lower bound. // "sup" stores the upper bound of the interval. private: int overlap_action() const #ifndef CGAL_IA_NO_EXCEPTION throw (unsafe_comparison) { throw unsafe_comparison(); } #else { #if !defined(CGAL_IA_NO_WARNINGS) && !defined(CGAL_NO_WARNINGS) CGAL_warning_msg(false, " Comparison between overlapping intervals"); #endif return 0; // Return an arbitrary value. } #endif // CGAL_IA_NO_EXCEPTION public: friend IA sqrt (const IA &); friend IA square (const IA &); friend IA abs (const IA &); friend IA min (const IA &, const IA &); friend IA max (const IA &, const IA &); friend IA operator- (const double, const IA &); friend IA operator/ (const double, const IA &); friend double to_double (const IA &); friend bool is_valid (const IA &); friend bool is_finite (const IA &); friend Sign sign (const IA &); friend Comparison_result compare (const IA &, const IA &); // The constructors. Interval_nt_advanced() #ifndef CGAL_NO_ASSERTIONS : inf(-1), sup(-1) // Buggy interval to detect use before definition. #endif {} Interval_nt_advanced(const double d) : inf(-d), sup(d) {} Interval_nt_advanced(const double i, const double s) : inf(-i), sup(s) { CGAL_assertion_msg(i<=s," Variable used before being initialized ?"); } #if 1 // Need to be redefined for non advanced ? // The copy constructors/assignment: useless. // The default ones are ok, but these are faster... Interval_nt_advanced(const IA & d) : inf(d.inf), sup(d.sup) {} IA & operator=(const IA & d) { inf = d.inf; sup = d.sup; return *this; } #endif // The operators. IA operator+(const IA & d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif return IA (-(inf + d.inf), sup + d.sup); } // { return IA (d) += *this; } IA operator-(const IA & d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif return IA (-(inf + d.sup), sup + d.inf); } // Those 2 ones could be made not inlined. IA operator* (const IA & d) const; IA operator/ (const IA & d) const; IA operator-() const { return IA (-(sup), inf); } IA & operator+= (const IA & d); IA & operator-= (const IA & d); IA & operator*= (const IA & d); IA & operator/= (const IA & d); // For speed... IA operator+ (const double d) const { return IA(-(inf-d), sup+d); }; IA operator- (const double d) const { return IA(-(inf+d), sup-d); }; IA operator* (const double d) const; IA operator/ (const double d) const; bool operator< (const IA & d) const { if (sup < -d.inf) return true; if (-inf >= d.sup) return false; return overlap_action(); } bool operator<= (const IA & d) const { if (sup <= -d.inf) return true; if (-inf > d.sup) return false; return overlap_action(); } bool operator== (const IA & d) const { if ((-d.inf > sup) || (d.sup < -inf)) return false; if ((-d.inf == sup) && (d.sup == -inf)) return true; return overlap_action(); } bool operator> (const IA & d) const { return (d < *this); } bool operator>= (const IA & d) const { return (d <= *this); } bool operator!= (const IA & d) const { return !(d == *this); } bool is_same (const IA & d) const { return (inf == d.inf) && (sup == d.sup); } bool is_point() const { return (sup == -inf); } bool overlap (const IA & d) const { return !((-d.inf > sup) || (d.sup < -inf)); } double lower_bound() const { return -inf; } double upper_bound() const { return sup; } // The (join, union, ||) operator. IA operator|| (const IA & d) const { return IA(min(-inf,-d.inf), max(sup,d.sup)); } // The (meet, intersection, &&) operator. Valid if intervals overlap. IA operator&& (const IA & d) const { return IA(max(-inf,-d.inf), min(sup,d.sup)); } }; // Usefull constants. // MIN_DOUBLE (subnormal) const double Interval_nt_advanced::min_double =5e-324; // MAX_DOUBLE const double Interval_nt_advanced::max_double =1.7976931348623157081e+308; // Smallest interval strictly around zero. const Interval_nt_advanced Interval_nt_advanced::smallest (-Interval_nt_advanced::min_double, Interval_nt_advanced::min_double); // [-inf;+inf] const Interval_nt_advanced Interval_nt_advanced::largest (-HUGE_VAL, HUGE_VAL); inline Interval_nt_advanced Interval_nt_advanced::operator* (const Interval_nt_advanced & d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif if (inf<=0) // this>=0 { /* d>=0 return IA (-((-inf)*d.inf), sup*d.sup); * d<=0 return IA (-( sup*d.inf), (-inf)*d.sup); * 0 \in d return IA (-( sup*d.inf), sup*d.sup); */ double a = -inf, b = sup; if (d.inf > 0) { a=b; if (d.sup < 0) b=-inf; } return IA (-(a*d.inf), b*d.sup); } else if (sup<=0) // this<=0 { /* d>=0 return IA (-( inf*d.sup), (-sup)*d.inf); * d<=0 return IA (-((-sup)*d.sup), inf*d.inf); * 0 \in d return IA (-( inf*d.sup), inf*d.inf); */ double a = -sup, b = inf; if (d.inf > 0) { a=b; if (d.sup < 0) b=-sup; } return IA (-(b*d.sup), a*d.inf); } else // 0 \in [inf;sup] { if (d.inf<=0) // d>=0 return IA (-(inf*d.sup), sup*d.sup); if (d.sup<=0) // d<=0 return IA (-(sup*d.inf), inf*d.inf); // 0 \in d double tmp1 = inf*d.sup; double tmp2 = sup*d.inf; double tmp3 = inf*d.inf; double tmp4 = sup*d.sup; return IA (-max(tmp1,tmp2), max(tmp3,tmp4)); }; } inline Interval_nt_advanced Interval_nt_advanced::operator* (const double d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif #if 0 double a = inf*fabs(d); double b = sup*fabs(d); if (d>=0) return IA(-a,b); return IA(-b,a); #else if (d>=0) return IA (-(inf*d), sup*d); return IA (-(sup*(-d)), inf*(-d)); #endif } inline Interval_nt_advanced Interval_nt_advanced::operator/ (const double d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif if (d>0) return IA (-(inf/d), sup/d); if (d<0) return IA (-(sup/(-d)), inf/(-d)); return largest; } inline bool operator< (const double d, const Interval_nt_advanced & t) { return t>d; } inline bool operator<= (const double d, const Interval_nt_advanced & t) { return t>=d; } inline bool operator> (const double d, const Interval_nt_advanced & t) { return t= (const double d, const Interval_nt_advanced & t) { return t<=d; } inline bool operator== (const double d, const Interval_nt_advanced & t) { return t==d; } inline bool operator!= (const double d, const Interval_nt_advanced & t) { return t!=d; } inline Interval_nt_advanced operator+ (const double d, const Interval_nt_advanced & t) { return t+d; } inline Interval_nt_advanced operator- (const double d, const Interval_nt_advanced & t) { return Interval_nt_advanced(-(t.sup-d), t.inf+d); } // { return -(t-d); } inline Interval_nt_advanced operator* (const double d, const Interval_nt_advanced & t) { return t*d; } inline Interval_nt_advanced operator/ (const double t, const Interval_nt_advanced & d) { typedef Interval_nt_advanced IA; if (d.inf<0) // d>0 { if (t>=0) return IA(-((-t)/d.sup), (-t)/d.inf); return IA(-(t/d.inf), t/d.sup); } if (d.sup<0) // d<0 { if (t>=0) return IA(-(t/d.inf), t/d.sup); return IA(-((-t)/d.sup), (-t)/d.inf); } return IA::largest; // 0 \in d } inline Interval_nt_advanced Interval_nt_advanced::operator/ (const Interval_nt_advanced & d) const { #ifdef CGAL_IA_DEBUG CGAL_assertion(FPU_get_rounding_mode() == FPU_PLUS_INFINITY); #endif if (d.inf<0) // d>0 { /* this>=0 return IA (-(inf/d.sup), sup/(-d.inf)); * this<=0 return IA (-(inf/(-d.inf)), sup/d.sup); * 0 \in this return IA (-(inf/(-d.inf)), sup/(-d.inf)); */ double a = d.sup, b = -d.inf; if (inf>0) { a=b; if (sup<0) b=d.sup; }; return IA(-(inf/a), sup/b); } else if (d.sup<0) // d<0 { /* this>=0 return IA (-(sup/(-d.sup)), inf/d.inf); * this<=0 return IA (-(sup/d.inf), inf/(-d.sup)); * 0 \in this return IA (-(sup/(-d.sup)), inf/(-d.sup)); */ double a = -d.sup, b = d.inf; if (inf>0) { a=b; if (sup<0) b=-d.sup; }; return IA(-(sup/a), inf/b); } else // 0 \in d return largest; // IA (-HUGE_VAL, HUGE_VAL); // We could do slightly better -> [0;HUGE_VAL] when d.sup==0, // but is this worth ? } inline Interval_nt_advanced & Interval_nt_advanced::operator+= (const Interval_nt_advanced & d) { return *this = *this + d; } inline Interval_nt_advanced & Interval_nt_advanced::operator-= (const Interval_nt_advanced & d) { return *this = *this - d; } inline Interval_nt_advanced & Interval_nt_advanced::operator*= (const Interval_nt_advanced & d) { return *this = *this * d; } inline Interval_nt_advanced & Interval_nt_advanced::operator/= (const Interval_nt_advanced & d) { return *this = *this / d; } inline Interval_nt_advanced sqrt (const Interval_nt_advanced & d) { FPU_set_rounding_to_minus_infinity(); Interval_nt_advanced tmp; // sqrt([+a,+b]) => [sqrt(+a);sqrt(+b)] // sqrt([-a,+b]) => [0;sqrt(+b)] => assumes roundoff error. // sqrt([-a,-b]) => [0;sqrt(-b)] => assumes user bug (unspecified result). tmp.inf = (d.inf<0) ? -sqrt(-d.inf) : 0; FPU_set_rounding_to_infinity(); tmp.sup = sqrt(d.sup); return tmp; } inline Interval_nt_advanced square (const Interval_nt_advanced & d) { // The first one is slightly slower, but produces shorter code. #if 0 double a = d.inf*fabs(d.inf); double b = d.sup*fabs(d.sup); if (d.inf <= 0) return Interval_nt_advanced(-a,b); if (d.sup <= 0) return Interval_nt_advanced(-b,a); return Interval_nt_advanced(0, max(a,b)); #else if (d.inf<=0) return Interval_nt_advanced(-(d.inf*-d.inf), d.sup*d.sup); if (d.sup<=0) return Interval_nt_advanced(-(d.sup*-d.sup), d.inf*d.inf); return Interval_nt_advanced(0.0, square(max(d.inf, d.sup))); #endif } inline double to_double (const Interval_nt_advanced & d) { return (d.sup-d.inf)*.5; } inline bool is_valid (const Interval_nt_advanced & d) { return is_valid(d.inf) && is_valid(d.sup) && (-d.inf <= d.sup); } inline bool is_finite (const Interval_nt_advanced & d) { return is_finite(d.inf) && is_finite(d.sup); } inline Sign sign (const Interval_nt_advanced & d) { if (d.inf < 0) return POSITIVE; if (d.sup < 0) return NEGATIVE; if (-d.inf == d.sup) return ZERO; return Sign (d.overlap_action()); } inline Comparison_result compare (const Interval_nt_advanced & d, const Interval_nt_advanced & e) { if (-d.inf > e.sup) return LARGER; if (-e.inf > d.sup) return SMALLER; if ( (-e.inf == d.sup) && (-d.inf == e.sup) ) return EQUAL; return Comparison_result (d.overlap_action()); } inline Interval_nt_advanced abs (const Interval_nt_advanced & d) { if (d.inf <= 0) return d; if (d.sup <= 0) return -d; return Interval_nt_advanced(0, max(d.inf,d.sup)); } inline Interval_nt_advanced min (const Interval_nt_advanced & d, const Interval_nt_advanced & e) { return Interval_nt_advanced(-max(d.inf, e.inf), min(d.sup, e.sup)); } inline Interval_nt_advanced max (const Interval_nt_advanced & d, const Interval_nt_advanced & e) { return Interval_nt_advanced(-min(d.inf, e.inf), max(d.sup, e.sup)); } inline ostream & operator<< (ostream & os, const Interval_nt_advanced & d) { return os << "[" << d.lower_bound() << ";" << d.upper_bound() << "]"; } inline istream & operator>> (istream & is, Interval_nt_advanced & ia) { double d; is >> d; ia = d; return is; } // The non-advanced class. struct Interval_nt : public Interval_nt_advanced { typedef Interval_nt IA; // Constructors are identical. Interval_nt() {} Interval_nt(const double d) : Interval_nt_advanced(d) {} Interval_nt(const double a, const double b) : Interval_nt_advanced(a,b) {} // Private constructor for casts. (remade public) Interval_nt(const Interval_nt_advanced &d) : Interval_nt_advanced(d) {} friend IA sqrt (const IA &); friend IA square (const IA &); // How to share those definitions ? friend IA abs (const IA & d) { return abs((Interval_nt_advanced) d); } friend IA min (const IA & d, const IA & e) { return min((Interval_nt_advanced) d, (Interval_nt_advanced) e); } friend IA max (const IA & d, const IA & e) { return max((Interval_nt_advanced) d, (Interval_nt_advanced) e); } // friend IA operator* (const double &, const IA &); friend double to_double (const IA & d) { return to_double((Interval_nt_advanced) d); } friend bool is_valid (const IA & d) { return is_valid((Interval_nt_advanced) d); } friend bool is_finite (const IA & d) { return is_finite((Interval_nt_advanced) d); } friend Sign sign (const IA & d) { return sign((Interval_nt_advanced) d); } friend Comparison_result compare (const IA & d, const IA & e) { return compare((Interval_nt_advanced) d, (Interval_nt_advanced) e); } // This particular one needs to be redefined, a pitty... IA operator-() const { return IA(-(sup), inf); } // The member functions that have to be protected against rounding mode. IA operator+(const IA & d) const ; IA operator-(const IA & d) const ; IA operator*(const IA & d) const ; IA operator/(const IA & d) const ; // For speed... IA operator*(const double d) const; // These have exactly the same code as the advanced class. // How can I avoid duplicating the code ? IA & operator+=(const IA & d) ; IA & operator-=(const IA & d) ; IA & operator*=(const IA & d) ; IA & operator/=(const IA & d) ; }; // Here we use the GNU extension of "Named return value". #ifdef __GNUG__ # define CGAL_NAMED_RETURN_VALUE_OPT_1 return tmp; # define CGAL_NAMED_RETURN_VALUE_OPT_2 # define CGAL_NAMED_RETURN_VALUE_OPT_3 #else # define CGAL_NAMED_RETURN_VALUE_OPT_1 # define CGAL_NAMED_RETURN_VALUE_OPT_2 Interval_nt tmp; # define CGAL_NAMED_RETURN_VALUE_OPT_3 return tmp; #endif inline Interval_nt Interval_nt::operator+ (const Interval_nt & d) const CGAL_NAMED_RETURN_VALUE_OPT_1 { FPU_set_rounding_to_infinity(); CGAL_NAMED_RETURN_VALUE_OPT_2 tmp.inf = inf + d.inf; tmp.sup = sup + d.sup; FPU_set_rounding_to_nearest(); CGAL_NAMED_RETURN_VALUE_OPT_3 } inline Interval_nt Interval_nt::operator- (const Interval_nt & d) const CGAL_NAMED_RETURN_VALUE_OPT_1 { FPU_set_rounding_to_infinity(); CGAL_NAMED_RETURN_VALUE_OPT_2 tmp.inf = inf + d.sup; tmp.sup = sup + d.inf; FPU_set_rounding_to_nearest(); CGAL_NAMED_RETURN_VALUE_OPT_3 } inline Interval_nt Interval_nt::operator* (const Interval_nt & d) const { FPU_set_rounding_to_infinity(); Interval_nt tmp ( Interval_nt_advanced::operator*(d) ); FPU_set_rounding_to_nearest(); return tmp; } inline Interval_nt Interval_nt::operator* (const double d) const CGAL_NAMED_RETURN_VALUE_OPT_1 { FPU_set_rounding_to_infinity(); CGAL_NAMED_RETURN_VALUE_OPT_2 if (d>=0) { tmp.inf = inf*d; tmp.sup = sup*d; } else { tmp.inf = sup*(-d); tmp.sup = inf*(-d); } FPU_set_rounding_to_nearest(); CGAL_NAMED_RETURN_VALUE_OPT_3 } inline Interval_nt operator* (const double d, const Interval_nt & t) { return t*d; } inline Interval_nt Interval_nt::operator/ (const Interval_nt & d) const { FPU_set_rounding_to_infinity(); Interval_nt tmp ( Interval_nt_advanced::operator/(d) ); FPU_set_rounding_to_nearest(); return tmp; } inline Interval_nt & Interval_nt::operator+= (const Interval_nt & d) { return *this = *this + d; } inline Interval_nt & Interval_nt::operator-= (const Interval_nt & d) { return *this = *this - d; } inline Interval_nt & Interval_nt::operator*= (const Interval_nt & d) { return *this = *this * d; } inline Interval_nt & Interval_nt::operator/= (const Interval_nt & d) { return *this = *this / d; } inline Interval_nt sqrt (const Interval_nt & d) { Interval_nt tmp = sqrt( (Interval_nt_advanced) d); FPU_set_rounding_to_nearest(); return tmp; } inline Interval_nt square (const Interval_nt & d) { FPU_set_rounding_to_infinity(); Interval_nt tmp = square( (Interval_nt_advanced) d); FPU_set_rounding_to_nearest(); return tmp; } // The undocumented Tag things... inline io_Operator io_tag (const Interval_nt_advanced &) { return io_Operator(); } inline Number_tag number_type_tag (Interval_nt_advanced) { return Number_tag(); } // Finally we deal with the convert_to(NT) // functions from other NTs, when necessary. // convert_to() is templated below. // // For the builtin types (well, all those that can be casted to double // exactly), the template in misc.h is enough. CGAL_END_NAMESPACE #ifdef CGAL_GMPZ_H #include #endif #ifdef CGAL_BIGFLOAT_H #include #endif #ifdef CGAL_INTEGER_H #include #endif #ifdef CGAL_REAL_H #include #endif #ifdef CGAL_RATIONAL_H #include #endif #ifdef CGAL_FIXED_PRECISION_NT_H #include #endif #ifdef CGAL_QUOTIENT_H #include #endif CGAL_BEGIN_NAMESPACE template inline Interval_nt convert_to (const FT & z) { FPU_set_rounding_to_infinity(); Interval_nt tmp(convert_to(z)); FPU_set_rounding_to_nearest(); return tmp; } CGAL_END_NAMESPACE #endif // CGAL_INTERVAL_ARITHMETIC_H