// ============================================================================ // // 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 template struct Interval_nt : public Interval_base { typedef Tag_false Has_gcd; typedef Tag_true Has_division; typedef Tag_true Has_sqrt; typedef Interval_nt IA; Interval_nt() {} Interval_nt(const double d) : Interval_base(d) {} Interval_nt(const double i, const double s) : Interval_base(i,s) {} Interval_nt(const Interval_base & d) : Interval_base(d) {} // 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(); } bool operator< (const IA &d) const { if (sup_ < d.inf_) return true; if (inf_ >= d.sup_) return false; overlap_action(); return false; } bool operator> (const IA &d) const { return d < *this; } bool operator<= (const IA &d) const { if (sup_ <= d.inf_) return true; if (inf_ > d.sup_) return false; overlap_action(); return false; } bool operator>= (const IA &d) const { return d <= *this; } bool operator== (const IA &d) const { if (d.inf_ > sup_ || d.sup_ < inf_) return false; if (d.inf_ == sup_ && d.sup_ == inf_) return true; overlap_action(); return false; } bool operator!= (const IA &d) const { return !(*this == d); } // TODO : Maybe I should suppress these : they are useless. // 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_)); } }; 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 ? } #if 0 // TODO : Do this for the next release, same for is_one() bool is_zero(const NT &n) { if (0 > n.sup_ || 0 < n.inf_) return false; if (0 == n.sup_ && 0 == n.inf_) return true; n.overlap_action(); } #endif 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 namespace NTS { #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 } // namespace NTS inline Interval_base 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_advanced approx ((double) l); FPU_set_cw(CGAL_FE_UPWARD); return approx + Interval_nt_advanced(Interval_base::Smallest); } else #endif return Interval_base(double(l)); } // needed for making the testsuite pass for Intel7 namespace CGALi { extern double zero(); } CGAL_END_NAMESPACE #endif // CGAL_INTERVAL_ARITHMETIC_H