// ============================================================================ // // Copyright (c) 1998,1999,2000,2001,2002 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 following classes: // - Interval_nt It's a number type that needs the FPU rounding mode // to be set to +inf. It is also typedef'd to // Interval_nt_advanced for backward compatibility. // - Interval_nt Same but it does the rounding mode itself so you // don't have to worry about it. But it's slower. // // Note: When rounding is towards +infinity, to make an operation rounded // towards -infinity, it's enough to take the opposite of some of the operand, // and the opposite of the result (see operator+, operator*,...). #include #include #include CGAL_BEGIN_NAMESPACE namespace CGALi { struct Unsafe_comparison {}; // Exception class. const double Huge_val = HUGE_VAL; // Workaround for G++ 2.95 on Linux. } template class Interval_nt { typedef Interval_nt IA; typedef std::pair Pair; public: typedef Tag_false Has_gcd; typedef Tag_true Has_division; typedef Tag_true Has_sqrt; typedef CGALi::Unsafe_comparison unsafe_comparison; static unsigned number_of_failures; // Number of filter failures. Interval_nt() {} Interval_nt(double d) : inf_sup(d, d) {} Interval_nt(double i, double s) : inf_sup(i, s) { // VC++ should use instead : (i<=s) || !is_valid(i) || !is_valid(s) // Or should I use is_valid() ? or is_valid_or_nan() ? CGAL_assertion_msg(!(i>s), " Variable used before being initialized (or CGAL bug)"); } // This copy ctor, normally equivalent to the one created by the compiler, // appears to fix a code generation problem with GCC 3.0.4... // (see test/IA/gcc_3.0.bug.C). Interval_nt(const Interval_nt & i) : inf_sup(i.pair()) {} Interval_nt(const Pair & p) : inf_sup(p) {} // The advantage of non-member operators is that (double * IA) just works... // But is it really useful and wishable in CGAL ? // Probably YES => TODO. IA operator+ (const IA &d) const { Protect_FPU_rounding P; return IA(-CGAL_IA_SUB(-inf(), d.inf()), CGAL_IA_ADD(sup(), d.sup())); } IA operator- (const IA &d) const { Protect_FPU_rounding P; return IA(-CGAL_IA_SUB(d.sup(), inf()), CGAL_IA_SUB(sup(), d.inf())); } IA operator* (const IA &) const; IA operator/ (const IA &) const; IA operator-() const { return IA (-sup(), -inf()); } IA & operator+= (const IA &d) { return *this = *this + d; } IA & operator-= (const IA &d) { return *this = *this - d; } IA & operator*= (const IA &d) { return *this = *this * d; } IA & operator/= (const IA &d) { return *this = *this / d; } static void overlap_action() // throw (unsafe_comparison) { number_of_failures++; throw unsafe_comparison(); } // TODO : Maybe I should suppress these : they are useless and risky. // The (join, union, ||) operator. IA operator|| (const IA & d) const { return IA(std::min(inf(), d.inf()), std::max(sup(), d.sup())); } // The (meet, intersection, &&) operator. Valid if intervals overlap. IA operator&& (const IA & d) const { return IA(std::max(inf(), d.inf()), std::min(sup(), d.sup())); } bool is_point() const { return sup() == inf(); } bool is_same (const IA & d) const { return inf() == d.inf() && sup() == d.sup(); } bool do_overlap (const IA & d) const { return !(d.inf() > sup() || d.sup() < inf()); } double inf() const { return inf_sup.first; } double sup() const { return inf_sup.second; } const std::pair& pair() const { return inf_sup; } static IA largest() { // G++ 2.95 on Linux has problems with HUGE_VAL in template context. // (it's a macro defined by "__extension__ ..." and it gets lost. return IA(-CGALi::Huge_val, CGALi::Huge_val); } static IA smallest() { return IA(-CGAL_IA_MIN_DOUBLE, CGAL_IA_MIN_DOUBLE); } private: Pair inf_sup; }; template unsigned Interval_nt::number_of_failures; template inline bool operator<(const Interval_nt &a, const Interval_nt &b) { if (a.sup() < b.inf()) return true; if (a.inf() >= b.sup()) return false; a.overlap_action(); return false; } template inline bool operator>(const Interval_nt &a, const Interval_nt &b) { return b < a; } template inline bool operator<=(const Interval_nt &a, const Interval_nt &b) { if (a.sup() <= b.inf()) return true; if (a.inf() > b.sup()) return false; a.overlap_action(); return false; } template inline bool operator>=(const Interval_nt &a, const Interval_nt &b) { return b <= a; } template inline bool operator==(const Interval_nt &a, const Interval_nt &b) { if (b.inf() > a.sup() || b.sup() < a.inf()) return false; if (b.inf() == a.sup() && b.sup() == a.inf()) return true; a.overlap_action(); return false; } template inline bool operator!=(const Interval_nt &a, const Interval_nt &b) { return ! (a == b); } // Mixed operators. template inline bool operator<(int a, const Interval_nt &b) { if (a < b.inf()) return true; if (a >= b.sup()) return false; b.overlap_action(); return false; } template inline bool operator>(int a, const Interval_nt &b) { return b < a; } template inline bool operator<=(int a, const Interval_nt &b) { if (a <= b.inf()) return true; if (a > b.sup()) return false; b.overlap_action(); return false; } template inline bool operator>=(int a, const Interval_nt &b) { return b <= a; } template inline bool operator==(int a, const Interval_nt &b) { if (b.inf() > a || b.sup() < a) return false; if (b.inf() == a && b.sup() == a) return true; b.overlap_action(); return false; } template inline bool operator!=(int a, const Interval_nt &b) { return ! (a == b); } template inline bool operator<(const Interval_nt &a, int b) { if (a.sup() < b) return true; if (a.inf() >= b) return false; a.overlap_action(); return false; } template inline bool operator>(const Interval_nt &a, int b) { return b < a; } template inline bool operator<=(const Interval_nt &a, int b) { if (a.sup() <= b) return true; if (a.inf() > b) return false; a.overlap_action(); return false; } template inline bool operator>=(const Interval_nt &a, int b) { return b <= a; } template inline bool operator==(const Interval_nt &a, int b) { if (b > a.sup() || b < a.inf()) return false; if (b == a.sup() && b == a.inf()) return true; a.overlap_action(); return false; } template inline bool operator!=(const Interval_nt &a, int b) { return ! (a == b); } template inline double to_double (const Interval_nt & d) { return (d.sup() + d.inf()) * 0.5; // This may overflow... } template inline const std::pair & to_interval (const Interval_nt & d) { return d.pair(); } template inline bool is_valid (const Interval_nt & d) { #if defined _MSC_VER || defined __sgi || defined __BORLANDC__ return CGAL::is_valid(d.inf()) && CGAL::is_valid(d.sup()) && d.inf() <= d.sup(); #else // The 2 first is_valid() are implicitely done by the 3rd test ;-) return d.inf() <= d.sup(); #endif } template inline bool is_finite (const Interval_nt & d) { return CGAL::is_finite(d.inf()) && CGAL::is_finite(d.sup()); } template inline io_Operator io_tag (const Interval_nt &) { return io_Operator(); } template std::ostream & operator<< (std::ostream &os, const Interval_nt & I ) { return os << "[" << I.inf() << ";" << I.sup() << "]"; } template std::istream & operator>> (std::istream &is, Interval_nt & I) { double d; is >> d; I = d; return is; } typedef Interval_nt Interval_nt_advanced; // for back-compatibility template #ifndef CGAL_IA_NO_INLINE inline #endif Interval_nt Interval_nt::operator* (const Interval_nt & d) const { Protect_FPU_rounding P; if (inf()>=0.0) // e>=0 { // d>=0 [inf()*d.inf(); sup()*d.sup()] // d<=0 [sup()*d.inf(); inf()*d.sup()] // d~=0 [sup()*d.inf(); sup()*d.sup()] double a = inf(), b = sup(); if (d.inf() < 0.0) { a=b; if (d.sup() < 0.0) b=inf(); } return IA(-CGAL_IA_MUL(a, -d.inf()), CGAL_IA_MUL(b, d.sup())); } else if (sup()<=0.0) // e<=0 { // d>=0 [inf()*d.sup(); sup()*d.inf()] // d<=0 [sup()*d.sup(); inf()*d.inf()] // d~=0 [inf()*d.sup(); inf()*d.inf()] double a = sup(), b = inf(); if (d.inf() < 0.0) { a=b; if (d.sup() < 0.0) b=sup(); } return IA(-CGAL_IA_MUL(b, -d.sup()), CGAL_IA_MUL(a, d.inf())); } else // 0 \in [inf();sup()] { if (d.inf()>=0.0) // d>=0 return IA(-CGAL_IA_MUL(-inf(), d.sup()), CGAL_IA_MUL(sup(), d.sup())); if (d.sup()<=0.0) // d<=0 return IA(-CGAL_IA_MUL(sup(), -d.inf()), CGAL_IA_MUL(inf(), d.inf())); // 0 \in d double tmp1 = CGAL_IA_MUL(-inf(), d.sup()); double tmp2 = CGAL_IA_MUL(sup(), -d.inf()); double tmp3 = CGAL_IA_MUL(inf(), d.inf()); double tmp4 = CGAL_IA_MUL(sup(), d.sup()); return IA(-std::max(tmp1,tmp2), std::max(tmp3,tmp4)); }; } template #ifndef CGAL_IA_NO_INLINE inline #endif Interval_nt Interval_nt::operator/ (const Interval_nt & d) const { Protect_FPU_rounding P; if (d.inf()>0.0) // d>0 { // e>=0 [inf()/d.sup(); sup()/d.inf()] // e<=0 [inf()/d.inf(); sup()/d.sup()] // e~=0 [inf()/d.inf(); sup()/d.inf()] double a = d.sup(), b = d.inf(); if (inf()<0.0) { a=b; if (sup()<0.0) b=d.sup(); }; return IA(-CGAL_IA_DIV(-inf(), a), CGAL_IA_DIV(sup(), b)); } else if (d.sup()<0.0) // d<0 { // e>=0 [sup()/d.sup(); inf()/d.inf()] // e<=0 [sup()/d.inf(); inf()/d.sup()] // e~=0 [sup()/d.sup(); inf()/d.sup()] double a = d.sup(), b = d.inf(); if (inf()<0.0) { b=a; if (sup()<0.0) a=d.inf(); }; return IA(-CGAL_IA_DIV(-sup(), a), CGAL_IA_DIV(inf(), b)); } else // d~0 return IA::largest(); // We could do slightly better -> [0;HUGE_VAL] when d.sup()==0, // but is this worth ? } template inline Interval_nt sqrt (const Interval_nt & d) { Protect_FPU_rounding P; // not optimal here. // 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). FPU_set_cw(CGAL_FE_DOWNWARD); double i = (d.inf() > 0.0) ? CGAL_IA_SQRT(d.inf()) : 0.0; FPU_set_cw(CGAL_FE_UPWARD); return Interval_nt(i, CGAL_IA_SQRT(d.sup())); } #ifndef CGAL_CFG_MATCHING_BUG_2 template inline Interval_nt min (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(std::min(d.inf(), e.inf()), std::min(d.sup(), e.sup())); } template inline Interval_nt max (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(std::max(d.inf(), e.inf()), std::max(d.sup(), e.sup())); } #else inline Interval_nt min (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(min(d.inf(), e.inf()),min(d.sup(), e.sup())); } inline Interval_nt max (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(max(d.inf(), e.inf()),max(d.sup(), e.sup())); } inline Interval_nt min (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(min(d.inf(), e.inf()),min(d.sup(), e.sup())); } inline Interval_nt max (const Interval_nt & d, const Interval_nt & e) { return Interval_nt(max(d.inf(), e.inf()),max(d.sup(), e.sup())); } #endif // CGAL_CFG_MATCHING_BUG_2 #ifndef CGAL_CFG_MATCHING_BUG_2 template inline Interval_nt square (const Interval_nt & d) { Protect_FPU_rounding P; if (d.inf()>=0.0) return Interval_nt(-CGAL_IA_MUL(d.inf(), -d.inf()), CGAL_IA_MUL(d.sup(), d.sup())); if (d.sup()<=0.0) return Interval_nt(-CGAL_IA_MUL(d.sup(), -d.sup()), CGAL_IA_MUL(d.inf(), d.inf())); return Interval_nt(0.0, CGAL_IA_SQUARE(std::max(-d.inf(), d.sup()))); } template inline Interval_nt abs (const Interval_nt & d) { if (d.inf() >= 0.0) return d; if (d.sup() <= 0.0) return -d; return Interval_nt(0.0, std::max(-d.inf(), d.sup())); } template inline Sign sign (const Interval_nt & d) { if (d.inf() > 0.0) return POSITIVE; if (d.sup() < 0.0) return NEGATIVE; if (d.inf() == d.sup()) return ZERO; Interval_nt::overlap_action(); return ZERO; } template inline Comparison_result compare (const Interval_nt & d, const Interval_nt & 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; Interval_nt::overlap_action(); return EQUAL; } #else // CGAL_CFG_MATCHING_BUG_2 // For crappy "compilers", we have to define complete overloaded functions. // First we overload for true. inline Interval_nt square (const Interval_nt & d) { Protect_FPU_rounding P; if (d.inf()>=0.0) return Interval_nt(-CGAL_IA_MUL(d.inf(), -d.inf()), CGAL_IA_MUL(d.sup(), d.sup())); if (d.sup()<=0.0) return Interval_nt(-CGAL_IA_MUL(d.sup(), -d.sup()), CGAL_IA_MUL(d.inf(), d.inf())); return Interval_nt(0.0, CGAL_IA_SQUARE(std::max(-d.inf(), d.sup()))); } inline Interval_nt abs (const Interval_nt & d) { if (d.inf() >= 0.0) return d; if (d.sup() <= 0.0) return -d; return Interval_nt(0.0, std::max(-d.inf(), d.sup())); } inline Sign sign (const Interval_nt & d) { if (d.inf() > 0.0) return POSITIVE; if (d.sup() < 0.0) return NEGATIVE; if (d.inf() == d.sup()) return ZERO; Interval_nt::overlap_action(); return ZERO; } inline Comparison_result compare (const Interval_nt & d, const Interval_nt & 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; Interval_nt::overlap_action(); return EQUAL; } // Then we overload for false. inline Interval_nt square (const Interval_nt & d) { Protect_FPU_rounding P; if (d.inf()>=0.0) return Interval_nt(-CGAL_IA_MUL(d.inf(), -d.inf()), CGAL_IA_MUL(d.sup(), d.sup())); if (d.sup()<=0.0) return Interval_nt(-CGAL_IA_MUL(d.sup(), -d.sup()), CGAL_IA_MUL(d.inf(), d.inf())); return Interval_nt(0.0, CGAL_IA_SQUARE(std::max(-d.inf(), d.sup()))); } inline Interval_nt abs (const Interval_nt & d) { if (d.inf() >= 0.0) return d; if (d.sup() <= 0.0) return -d; return Interval_nt(0.0, std::max(-d.inf(), d.sup())); } inline Sign sign (const Interval_nt & d) { if (d.inf() > 0.0) return POSITIVE; if (d.sup() < 0.0) return NEGATIVE; if (d.inf() == d.sup()) return ZERO; Interval_nt::overlap_action(); return ZERO; } inline Comparison_result compare (const Interval_nt & d, const Interval_nt & 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; Interval_nt::overlap_action(); return EQUAL; } #endif // CGAL_CFG_MATCHING_BUG_2 inline std::pair to_interval (const long & l) { #ifndef __BORLANDC__ // The stupid Borland compiler generates warnings... if (sizeof(double) > sizeof(long)) { // On 64bit platforms, a long doesn't fit exactly in a double. // Well, a perfect fix would be to use std::numeric_limits<>, but... Protect_FPU_rounding P(CGAL_FE_TONEAREST); Interval_nt approx ((double) l); FPU_set_cw(CGAL_FE_UPWARD); approx += Interval_nt::smallest(); return approx.pair(); } else #endif return std::pair(l,l); } CGAL_END_NAMESPACE #endif // CGAL_INTERVAL_ARITHMETIC_H