Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:04:55

0001 // Boost.Polygon library detail/voronoi_robust_fpt.hpp header file
0002 
0003 //          Copyright Andrii Sydorchuk 2010-2012.
0004 // Distributed under the Boost Software License, Version 1.0.
0005 //    (See accompanying file LICENSE_1_0.txt or copy at
0006 //          http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 // See http://www.boost.org for updates, documentation, and revision history.
0009 
0010 #ifndef BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT
0011 #define BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT
0012 
0013 #include <algorithm>
0014 #include <cmath>
0015 
0016 // Geometry predicates with floating-point variables usually require
0017 // high-precision predicates to retrieve the correct result.
0018 // Epsilon robust predicates give the result within some epsilon relative
0019 // error, but are a lot faster than high-precision predicates.
0020 // To make algorithm robust and efficient epsilon robust predicates are
0021 // used at the first step. In case of the undefined result high-precision
0022 // arithmetic is used to produce required robustness. This approach
0023 // requires exact computation of epsilon intervals within which epsilon
0024 // robust predicates have undefined value.
0025 // There are two ways to measure an error of floating-point calculations:
0026 // relative error and ULPs (units in the last place).
0027 // Let EPS be machine epsilon, then next inequalities have place:
0028 // 1 EPS <= 1 ULP <= 2 EPS (1), 0.5 ULP <= 1 EPS <= 1 ULP (2).
0029 // ULPs are good for measuring rounding errors and comparing values.
0030 // Relative errors are good for computation of general relative
0031 // error of formulas or expressions. So to calculate epsilon
0032 // interval within which epsilon robust predicates have undefined result
0033 // next schema is used:
0034 //     1) Compute rounding errors of initial variables using ULPs;
0035 //     2) Transform ULPs to epsilons using upper bound of the (1);
0036 //     3) Compute relative error of the formula using epsilon arithmetic;
0037 //     4) Transform epsilon to ULPs using upper bound of the (2);
0038 // In case two values are inside undefined ULP range use high-precision
0039 // arithmetic to produce the correct result, else output the result.
0040 // Look at almost_equal function to see how two floating-point variables
0041 // are checked to fit in the ULP range.
0042 // If A has relative error of r(A) and B has relative error of r(B) then:
0043 //     1) r(A + B) <= max(r(A), r(B)), for A * B >= 0;
0044 //     2) r(A - B) <= B*r(A)+A*r(B)/(A-B), for A * B >= 0;
0045 //     2) r(A * B) <= r(A) + r(B);
0046 //     3) r(A / B) <= r(A) + r(B);
0047 // In addition rounding error should be added, that is always equal to
0048 // 0.5 ULP or at most 1 epsilon. As you might see from the above formulas
0049 // subtraction relative error may be extremely large, that's why
0050 // epsilon robust comparator class is used to store floating point values
0051 // and compute subtraction as the final step of the evaluation.
0052 // For further information about relative errors and ULPs try this link:
0053 // http://docs.sun.com/source/806-3568/ncg_goldberg.html
0054 
0055 namespace boost {
0056 namespace polygon {
0057 namespace detail {
0058 
0059 template <typename T>
0060 T get_sqrt(const T& that) {
0061   return (std::sqrt)(that);
0062 }
0063 
0064 template <typename T>
0065 bool is_pos(const T& that) {
0066   return that > 0;
0067 }
0068 
0069 template <typename T>
0070 bool is_neg(const T& that) {
0071   return that < 0;
0072 }
0073 
0074 template <typename T>
0075 bool is_zero(const T& that) {
0076   return that == 0;
0077 }
0078 
0079 template <typename _fpt>
0080 class robust_fpt {
0081  public:
0082   typedef _fpt floating_point_type;
0083   typedef _fpt relative_error_type;
0084 
0085   // Rounding error is at most 1 EPS.
0086   enum {
0087     ROUNDING_ERROR = 1
0088   };
0089 
0090   robust_fpt() : fpv_(0.0), re_(0.0) {}
0091   explicit robust_fpt(floating_point_type fpv) :
0092       fpv_(fpv), re_(0.0) {}
0093   robust_fpt(floating_point_type fpv, relative_error_type error) :
0094       fpv_(fpv), re_(error) {}
0095 
0096   floating_point_type fpv() const { return fpv_; }
0097   relative_error_type re() const { return re_; }
0098   relative_error_type ulp() const { return re_; }
0099 
0100   bool has_pos_value() const {
0101     return is_pos(fpv_);
0102   }
0103 
0104   bool has_neg_value() const {
0105     return is_neg(fpv_);
0106   }
0107 
0108   bool has_zero_value() const {
0109     return is_zero(fpv_);
0110   }
0111 
0112   robust_fpt operator-() const {
0113     return robust_fpt(-fpv_, re_);
0114   }
0115 
0116   robust_fpt& operator+=(const robust_fpt& that) {
0117     floating_point_type fpv = this->fpv_ + that.fpv_;
0118     if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) ||
0119         (!is_pos(this->fpv_) && !is_pos(that.fpv_))) {
0120       this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
0121     } else {
0122       floating_point_type temp =
0123         (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv;
0124       if (is_neg(temp))
0125         temp = -temp;
0126       this->re_ = temp + ROUNDING_ERROR;
0127     }
0128     this->fpv_ = fpv;
0129     return *this;
0130   }
0131 
0132   robust_fpt& operator-=(const robust_fpt& that) {
0133     floating_point_type fpv = this->fpv_ - that.fpv_;
0134     if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) ||
0135         (!is_pos(this->fpv_) && !is_neg(that.fpv_))) {
0136        this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
0137     } else {
0138       floating_point_type temp =
0139         (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv;
0140       if (is_neg(temp))
0141          temp = -temp;
0142       this->re_ = temp + ROUNDING_ERROR;
0143     }
0144     this->fpv_ = fpv;
0145     return *this;
0146   }
0147 
0148   robust_fpt& operator*=(const robust_fpt& that) {
0149     this->re_ += that.re_ + ROUNDING_ERROR;
0150     this->fpv_ *= that.fpv_;
0151     return *this;
0152   }
0153 
0154   robust_fpt& operator/=(const robust_fpt& that) {
0155     this->re_ += that.re_ + ROUNDING_ERROR;
0156     this->fpv_ /= that.fpv_;
0157     return *this;
0158   }
0159 
0160   robust_fpt operator+(const robust_fpt& that) const {
0161     floating_point_type fpv = this->fpv_ + that.fpv_;
0162     relative_error_type re;
0163     if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) ||
0164         (!is_pos(this->fpv_) && !is_pos(that.fpv_))) {
0165       re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
0166     } else {
0167       floating_point_type temp =
0168         (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv;
0169       if (is_neg(temp))
0170         temp = -temp;
0171       re = temp + ROUNDING_ERROR;
0172     }
0173     return robust_fpt(fpv, re);
0174   }
0175 
0176   robust_fpt operator-(const robust_fpt& that) const {
0177     floating_point_type fpv = this->fpv_ - that.fpv_;
0178     relative_error_type re;
0179     if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) ||
0180         (!is_pos(this->fpv_) && !is_neg(that.fpv_))) {
0181       re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
0182     } else {
0183       floating_point_type temp =
0184         (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv;
0185       if (is_neg(temp))
0186         temp = -temp;
0187       re = temp + ROUNDING_ERROR;
0188     }
0189     return robust_fpt(fpv, re);
0190   }
0191 
0192   robust_fpt operator*(const robust_fpt& that) const {
0193     floating_point_type fpv = this->fpv_ * that.fpv_;
0194     relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR;
0195     return robust_fpt(fpv, re);
0196   }
0197 
0198   robust_fpt operator/(const robust_fpt& that) const {
0199     floating_point_type fpv = this->fpv_ / that.fpv_;
0200     relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR;
0201     return robust_fpt(fpv, re);
0202   }
0203 
0204   robust_fpt sqrt() const {
0205     return robust_fpt(get_sqrt(fpv_),
0206                       re_ * static_cast<relative_error_type>(0.5) +
0207                       ROUNDING_ERROR);
0208   }
0209 
0210  private:
0211   floating_point_type fpv_;
0212   relative_error_type re_;
0213 };
0214 
0215 template <typename T>
0216 robust_fpt<T> get_sqrt(const robust_fpt<T>& that) {
0217   return that.sqrt();
0218 }
0219 
0220 template <typename T>
0221 bool is_pos(const robust_fpt<T>& that) {
0222   return that.has_pos_value();
0223 }
0224 
0225 template <typename T>
0226 bool is_neg(const robust_fpt<T>& that) {
0227   return that.has_neg_value();
0228 }
0229 
0230 template <typename T>
0231 bool is_zero(const robust_fpt<T>& that) {
0232   return that.has_zero_value();
0233 }
0234 
0235 // robust_dif consists of two not negative values: value1 and value2.
0236 // The resulting expression is equal to the value1 - value2.
0237 // Subtraction of a positive value is equivalent to the addition to value2
0238 // and subtraction of a negative value is equivalent to the addition to
0239 // value1. The structure implicitly avoids difference computation.
0240 template <typename T>
0241 class robust_dif {
0242  public:
0243   robust_dif() :
0244       positive_sum_(0),
0245       negative_sum_(0) {}
0246 
0247   explicit robust_dif(const T& value) :
0248       positive_sum_((value > 0)?value:0),
0249       negative_sum_((value < 0)?-value:0) {}
0250 
0251   robust_dif(const T& pos, const T& neg) :
0252       positive_sum_(pos),
0253       negative_sum_(neg) {}
0254 
0255   T dif() const {
0256     return positive_sum_ - negative_sum_;
0257   }
0258 
0259   T pos() const {
0260     return positive_sum_;
0261   }
0262 
0263   T neg() const {
0264     return negative_sum_;
0265   }
0266 
0267   robust_dif<T> operator-() const {
0268     return robust_dif(negative_sum_, positive_sum_);
0269   }
0270 
0271   robust_dif<T>& operator+=(const T& val) {
0272     if (!is_neg(val))
0273       positive_sum_ += val;
0274     else
0275       negative_sum_ -= val;
0276     return *this;
0277   }
0278 
0279   robust_dif<T>& operator+=(const robust_dif<T>& that) {
0280     positive_sum_ += that.positive_sum_;
0281     negative_sum_ += that.negative_sum_;
0282     return *this;
0283   }
0284 
0285   robust_dif<T>& operator-=(const T& val) {
0286     if (!is_neg(val))
0287       negative_sum_ += val;
0288     else
0289       positive_sum_ -= val;
0290     return *this;
0291   }
0292 
0293   robust_dif<T>& operator-=(const robust_dif<T>& that) {
0294     positive_sum_ += that.negative_sum_;
0295     negative_sum_ += that.positive_sum_;
0296     return *this;
0297   }
0298 
0299   robust_dif<T>& operator*=(const T& val) {
0300     if (!is_neg(val)) {
0301       positive_sum_ *= val;
0302       negative_sum_ *= val;
0303     } else {
0304       positive_sum_ *= -val;
0305       negative_sum_ *= -val;
0306       swap();
0307     }
0308     return *this;
0309   }
0310 
0311   robust_dif<T>& operator*=(const robust_dif<T>& that) {
0312     T positive_sum = this->positive_sum_ * that.positive_sum_ +
0313                      this->negative_sum_ * that.negative_sum_;
0314     T negative_sum = this->positive_sum_ * that.negative_sum_ +
0315                      this->negative_sum_ * that.positive_sum_;
0316     positive_sum_ = positive_sum;
0317     negative_sum_ = negative_sum;
0318     return *this;
0319   }
0320 
0321   robust_dif<T>& operator/=(const T& val) {
0322     if (!is_neg(val)) {
0323       positive_sum_ /= val;
0324       negative_sum_ /= val;
0325     } else {
0326       positive_sum_ /= -val;
0327       negative_sum_ /= -val;
0328       swap();
0329     }
0330     return *this;
0331   }
0332 
0333  private:
0334   void swap() {
0335     (std::swap)(positive_sum_, negative_sum_);
0336   }
0337 
0338   T positive_sum_;
0339   T negative_sum_;
0340 };
0341 
0342 template<typename T>
0343 robust_dif<T> operator+(const robust_dif<T>& lhs,
0344                         const robust_dif<T>& rhs) {
0345   return robust_dif<T>(lhs.pos() + rhs.pos(), lhs.neg() + rhs.neg());
0346 }
0347 
0348 template<typename T>
0349 robust_dif<T> operator+(const robust_dif<T>& lhs, const T& rhs) {
0350   if (!is_neg(rhs)) {
0351     return robust_dif<T>(lhs.pos() + rhs, lhs.neg());
0352   } else {
0353     return robust_dif<T>(lhs.pos(), lhs.neg() - rhs);
0354   }
0355 }
0356 
0357 template<typename T>
0358 robust_dif<T> operator+(const T& lhs, const robust_dif<T>& rhs) {
0359   if (!is_neg(lhs)) {
0360     return robust_dif<T>(lhs + rhs.pos(), rhs.neg());
0361   } else {
0362     return robust_dif<T>(rhs.pos(), rhs.neg() - lhs);
0363   }
0364 }
0365 
0366 template<typename T>
0367 robust_dif<T> operator-(const robust_dif<T>& lhs,
0368                         const robust_dif<T>& rhs) {
0369   return robust_dif<T>(lhs.pos() + rhs.neg(), lhs.neg() + rhs.pos());
0370 }
0371 
0372 template<typename T>
0373 robust_dif<T> operator-(const robust_dif<T>& lhs, const T& rhs) {
0374   if (!is_neg(rhs)) {
0375     return robust_dif<T>(lhs.pos(), lhs.neg() + rhs);
0376   } else {
0377     return robust_dif<T>(lhs.pos() - rhs, lhs.neg());
0378   }
0379 }
0380 
0381 template<typename T>
0382 robust_dif<T> operator-(const T& lhs, const robust_dif<T>& rhs) {
0383   if (!is_neg(lhs)) {
0384     return robust_dif<T>(lhs + rhs.neg(), rhs.pos());
0385   } else {
0386     return robust_dif<T>(rhs.neg(), rhs.pos() - lhs);
0387   }
0388 }
0389 
0390 template<typename T>
0391 robust_dif<T> operator*(const robust_dif<T>& lhs,
0392                         const robust_dif<T>& rhs) {
0393   T res_pos = lhs.pos() * rhs.pos() + lhs.neg() * rhs.neg();
0394   T res_neg = lhs.pos() * rhs.neg() + lhs.neg() * rhs.pos();
0395   return robust_dif<T>(res_pos, res_neg);
0396 }
0397 
0398 template<typename T>
0399 robust_dif<T> operator*(const robust_dif<T>& lhs, const T& val) {
0400   if (!is_neg(val)) {
0401     return robust_dif<T>(lhs.pos() * val, lhs.neg() * val);
0402   } else {
0403     return robust_dif<T>(-lhs.neg() * val, -lhs.pos() * val);
0404   }
0405 }
0406 
0407 template<typename T>
0408 robust_dif<T> operator*(const T& val, const robust_dif<T>& rhs) {
0409   if (!is_neg(val)) {
0410     return robust_dif<T>(val * rhs.pos(), val * rhs.neg());
0411   } else {
0412     return robust_dif<T>(-val * rhs.neg(), -val * rhs.pos());
0413   }
0414 }
0415 
0416 template<typename T>
0417 robust_dif<T> operator/(const robust_dif<T>& lhs, const T& val) {
0418   if (!is_neg(val)) {
0419     return robust_dif<T>(lhs.pos() / val, lhs.neg() / val);
0420   } else {
0421     return robust_dif<T>(-lhs.neg() / val, -lhs.pos() / val);
0422   }
0423 }
0424 
0425 // Used to compute expressions that operate with sqrts with predefined
0426 // relative error. Evaluates expressions of the next type:
0427 // sum(i = 1 .. n)(A[i] * sqrt(B[i])), 1 <= n <= 4.
0428 template <typename _int, typename _fpt, typename _converter>
0429 class robust_sqrt_expr {
0430  public:
0431   enum MAX_RELATIVE_ERROR {
0432     MAX_RELATIVE_ERROR_EVAL1 = 4,
0433     MAX_RELATIVE_ERROR_EVAL2 = 7,
0434     MAX_RELATIVE_ERROR_EVAL3 = 16,
0435     MAX_RELATIVE_ERROR_EVAL4 = 25
0436   };
0437 
0438   // Evaluates expression (re = 4 EPS):
0439   // A[0] * sqrt(B[0]).
0440   _fpt eval1(_int* A, _int* B) {
0441     _fpt a = convert(A[0]);
0442     _fpt b = convert(B[0]);
0443     return a * get_sqrt(b);
0444   }
0445 
0446   // Evaluates expression (re = 7 EPS):
0447   // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]).
0448   _fpt eval2(_int* A, _int* B) {
0449     _fpt a = eval1(A, B);
0450     _fpt b = eval1(A + 1, B + 1);
0451     if ((!is_neg(a) && !is_neg(b)) ||
0452         (!is_pos(a) && !is_pos(b)))
0453       return a + b;
0454     return convert(A[0] * A[0] * B[0] - A[1] * A[1] * B[1]) / (a - b);
0455   }
0456 
0457   // Evaluates expression (re = 16 EPS):
0458   // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + A[2] * sqrt(B[2]).
0459   _fpt eval3(_int* A, _int* B) {
0460     _fpt a = eval2(A, B);
0461     _fpt b = eval1(A + 2, B + 2);
0462     if ((!is_neg(a) && !is_neg(b)) ||
0463         (!is_pos(a) && !is_pos(b)))
0464       return a + b;
0465     tA[3] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[2];
0466     tB[3] = 1;
0467     tA[4] = A[0] * A[1] * 2;
0468     tB[4] = B[0] * B[1];
0469     return eval2(tA + 3, tB + 3) / (a - b);
0470   }
0471 
0472 
0473   // Evaluates expression (re = 25 EPS):
0474   // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) +
0475   // A[2] * sqrt(B[2]) + A[3] * sqrt(B[3]).
0476   _fpt eval4(_int* A, _int* B) {
0477     _fpt a = eval2(A, B);
0478     _fpt b = eval2(A + 2, B + 2);
0479     if ((!is_neg(a) && !is_neg(b)) ||
0480         (!is_pos(a) && !is_pos(b)))
0481       return a + b;
0482     tA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
0483             A[2] * A[2] * B[2] - A[3] * A[3] * B[3];
0484     tB[0] = 1;
0485     tA[1] = A[0] * A[1] * 2;
0486     tB[1] = B[0] * B[1];
0487     tA[2] = A[2] * A[3] * -2;
0488     tB[2] = B[2] * B[3];
0489     return eval3(tA, tB) / (a - b);
0490   }
0491 
0492  private:
0493   _int tA[5];
0494   _int tB[5];
0495   _converter convert;
0496 };
0497 }  // detail
0498 }  // polygon
0499 }  // boost
0500 
0501 #endif  // BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT