Chris@16
|
1 // Boost.Polygon library detail/voronoi_robust_fpt.hpp header file
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright Andrii Sydorchuk 2010-2012.
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
5 // (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7
|
Chris@16
|
8 // See http://www.boost.org for updates, documentation, and revision history.
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT
|
Chris@16
|
11 #define BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT
|
Chris@16
|
12
|
Chris@101
|
13 #include <algorithm>
|
Chris@16
|
14 #include <cmath>
|
Chris@16
|
15
|
Chris@16
|
16 // Geometry predicates with floating-point variables usually require
|
Chris@16
|
17 // high-precision predicates to retrieve the correct result.
|
Chris@16
|
18 // Epsilon robust predicates give the result within some epsilon relative
|
Chris@16
|
19 // error, but are a lot faster than high-precision predicates.
|
Chris@16
|
20 // To make algorithm robust and efficient epsilon robust predicates are
|
Chris@16
|
21 // used at the first step. In case of the undefined result high-precision
|
Chris@16
|
22 // arithmetic is used to produce required robustness. This approach
|
Chris@16
|
23 // requires exact computation of epsilon intervals within which epsilon
|
Chris@16
|
24 // robust predicates have undefined value.
|
Chris@16
|
25 // There are two ways to measure an error of floating-point calculations:
|
Chris@16
|
26 // relative error and ULPs (units in the last place).
|
Chris@16
|
27 // Let EPS be machine epsilon, then next inequalities have place:
|
Chris@16
|
28 // 1 EPS <= 1 ULP <= 2 EPS (1), 0.5 ULP <= 1 EPS <= 1 ULP (2).
|
Chris@16
|
29 // ULPs are good for measuring rounding errors and comparing values.
|
Chris@16
|
30 // Relative errors are good for computation of general relative
|
Chris@16
|
31 // error of formulas or expressions. So to calculate epsilon
|
Chris@16
|
32 // interval within which epsilon robust predicates have undefined result
|
Chris@16
|
33 // next schema is used:
|
Chris@16
|
34 // 1) Compute rounding errors of initial variables using ULPs;
|
Chris@16
|
35 // 2) Transform ULPs to epsilons using upper bound of the (1);
|
Chris@16
|
36 // 3) Compute relative error of the formula using epsilon arithmetic;
|
Chris@16
|
37 // 4) Transform epsilon to ULPs using upper bound of the (2);
|
Chris@16
|
38 // In case two values are inside undefined ULP range use high-precision
|
Chris@16
|
39 // arithmetic to produce the correct result, else output the result.
|
Chris@16
|
40 // Look at almost_equal function to see how two floating-point variables
|
Chris@16
|
41 // are checked to fit in the ULP range.
|
Chris@16
|
42 // If A has relative error of r(A) and B has relative error of r(B) then:
|
Chris@16
|
43 // 1) r(A + B) <= max(r(A), r(B)), for A * B >= 0;
|
Chris@16
|
44 // 2) r(A - B) <= B*r(A)+A*r(B)/(A-B), for A * B >= 0;
|
Chris@16
|
45 // 2) r(A * B) <= r(A) + r(B);
|
Chris@16
|
46 // 3) r(A / B) <= r(A) + r(B);
|
Chris@16
|
47 // In addition rounding error should be added, that is always equal to
|
Chris@16
|
48 // 0.5 ULP or at most 1 epsilon. As you might see from the above formulas
|
Chris@16
|
49 // subtraction relative error may be extremely large, that's why
|
Chris@16
|
50 // epsilon robust comparator class is used to store floating point values
|
Chris@16
|
51 // and compute subtraction as the final step of the evaluation.
|
Chris@16
|
52 // For further information about relative errors and ULPs try this link:
|
Chris@16
|
53 // http://docs.sun.com/source/806-3568/ncg_goldberg.html
|
Chris@16
|
54
|
Chris@16
|
55 namespace boost {
|
Chris@16
|
56 namespace polygon {
|
Chris@16
|
57 namespace detail {
|
Chris@16
|
58
|
Chris@16
|
59 template <typename T>
|
Chris@16
|
60 T get_sqrt(const T& that) {
|
Chris@16
|
61 return (std::sqrt)(that);
|
Chris@16
|
62 }
|
Chris@16
|
63
|
Chris@16
|
64 template <typename T>
|
Chris@16
|
65 bool is_pos(const T& that) {
|
Chris@16
|
66 return that > 0;
|
Chris@16
|
67 }
|
Chris@16
|
68
|
Chris@16
|
69 template <typename T>
|
Chris@16
|
70 bool is_neg(const T& that) {
|
Chris@16
|
71 return that < 0;
|
Chris@16
|
72 }
|
Chris@16
|
73
|
Chris@16
|
74 template <typename T>
|
Chris@16
|
75 bool is_zero(const T& that) {
|
Chris@16
|
76 return that == 0;
|
Chris@16
|
77 }
|
Chris@16
|
78
|
Chris@16
|
79 template <typename _fpt>
|
Chris@16
|
80 class robust_fpt {
|
Chris@16
|
81 public:
|
Chris@16
|
82 typedef _fpt floating_point_type;
|
Chris@16
|
83 typedef _fpt relative_error_type;
|
Chris@16
|
84
|
Chris@16
|
85 // Rounding error is at most 1 EPS.
|
Chris@16
|
86 enum {
|
Chris@16
|
87 ROUNDING_ERROR = 1
|
Chris@16
|
88 };
|
Chris@16
|
89
|
Chris@16
|
90 robust_fpt() : fpv_(0.0), re_(0.0) {}
|
Chris@16
|
91 explicit robust_fpt(floating_point_type fpv) :
|
Chris@16
|
92 fpv_(fpv), re_(0.0) {}
|
Chris@16
|
93 robust_fpt(floating_point_type fpv, relative_error_type error) :
|
Chris@16
|
94 fpv_(fpv), re_(error) {}
|
Chris@16
|
95
|
Chris@16
|
96 floating_point_type fpv() const { return fpv_; }
|
Chris@16
|
97 relative_error_type re() const { return re_; }
|
Chris@16
|
98 relative_error_type ulp() const { return re_; }
|
Chris@16
|
99
|
Chris@16
|
100 robust_fpt& operator=(const robust_fpt& that) {
|
Chris@16
|
101 this->fpv_ = that.fpv_;
|
Chris@16
|
102 this->re_ = that.re_;
|
Chris@16
|
103 return *this;
|
Chris@16
|
104 }
|
Chris@16
|
105
|
Chris@16
|
106 bool has_pos_value() const {
|
Chris@16
|
107 return is_pos(fpv_);
|
Chris@16
|
108 }
|
Chris@16
|
109
|
Chris@16
|
110 bool has_neg_value() const {
|
Chris@16
|
111 return is_neg(fpv_);
|
Chris@16
|
112 }
|
Chris@16
|
113
|
Chris@16
|
114 bool has_zero_value() const {
|
Chris@16
|
115 return is_zero(fpv_);
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 robust_fpt operator-() const {
|
Chris@16
|
119 return robust_fpt(-fpv_, re_);
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 robust_fpt& operator+=(const robust_fpt& that) {
|
Chris@16
|
123 floating_point_type fpv = this->fpv_ + that.fpv_;
|
Chris@16
|
124 if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) ||
|
Chris@16
|
125 (!is_pos(this->fpv_) && !is_pos(that.fpv_))) {
|
Chris@16
|
126 this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
|
Chris@16
|
127 } else {
|
Chris@16
|
128 floating_point_type temp =
|
Chris@16
|
129 (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv;
|
Chris@16
|
130 if (is_neg(temp))
|
Chris@16
|
131 temp = -temp;
|
Chris@16
|
132 this->re_ = temp + ROUNDING_ERROR;
|
Chris@16
|
133 }
|
Chris@16
|
134 this->fpv_ = fpv;
|
Chris@16
|
135 return *this;
|
Chris@16
|
136 }
|
Chris@16
|
137
|
Chris@16
|
138 robust_fpt& operator-=(const robust_fpt& that) {
|
Chris@16
|
139 floating_point_type fpv = this->fpv_ - that.fpv_;
|
Chris@16
|
140 if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) ||
|
Chris@16
|
141 (!is_pos(this->fpv_) && !is_neg(that.fpv_))) {
|
Chris@16
|
142 this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
|
Chris@16
|
143 } else {
|
Chris@16
|
144 floating_point_type temp =
|
Chris@16
|
145 (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv;
|
Chris@16
|
146 if (is_neg(temp))
|
Chris@16
|
147 temp = -temp;
|
Chris@16
|
148 this->re_ = temp + ROUNDING_ERROR;
|
Chris@16
|
149 }
|
Chris@16
|
150 this->fpv_ = fpv;
|
Chris@16
|
151 return *this;
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154 robust_fpt& operator*=(const robust_fpt& that) {
|
Chris@16
|
155 this->re_ += that.re_ + ROUNDING_ERROR;
|
Chris@16
|
156 this->fpv_ *= that.fpv_;
|
Chris@16
|
157 return *this;
|
Chris@16
|
158 }
|
Chris@16
|
159
|
Chris@16
|
160 robust_fpt& operator/=(const robust_fpt& that) {
|
Chris@16
|
161 this->re_ += that.re_ + ROUNDING_ERROR;
|
Chris@16
|
162 this->fpv_ /= that.fpv_;
|
Chris@16
|
163 return *this;
|
Chris@16
|
164 }
|
Chris@16
|
165
|
Chris@16
|
166 robust_fpt operator+(const robust_fpt& that) const {
|
Chris@16
|
167 floating_point_type fpv = this->fpv_ + that.fpv_;
|
Chris@16
|
168 relative_error_type re;
|
Chris@16
|
169 if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) ||
|
Chris@16
|
170 (!is_pos(this->fpv_) && !is_pos(that.fpv_))) {
|
Chris@16
|
171 re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
|
Chris@16
|
172 } else {
|
Chris@16
|
173 floating_point_type temp =
|
Chris@16
|
174 (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv;
|
Chris@16
|
175 if (is_neg(temp))
|
Chris@16
|
176 temp = -temp;
|
Chris@16
|
177 re = temp + ROUNDING_ERROR;
|
Chris@16
|
178 }
|
Chris@16
|
179 return robust_fpt(fpv, re);
|
Chris@16
|
180 }
|
Chris@16
|
181
|
Chris@16
|
182 robust_fpt operator-(const robust_fpt& that) const {
|
Chris@16
|
183 floating_point_type fpv = this->fpv_ - that.fpv_;
|
Chris@16
|
184 relative_error_type re;
|
Chris@16
|
185 if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) ||
|
Chris@16
|
186 (!is_pos(this->fpv_) && !is_neg(that.fpv_))) {
|
Chris@16
|
187 re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR;
|
Chris@16
|
188 } else {
|
Chris@16
|
189 floating_point_type temp =
|
Chris@16
|
190 (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv;
|
Chris@16
|
191 if (is_neg(temp))
|
Chris@16
|
192 temp = -temp;
|
Chris@16
|
193 re = temp + ROUNDING_ERROR;
|
Chris@16
|
194 }
|
Chris@16
|
195 return robust_fpt(fpv, re);
|
Chris@16
|
196 }
|
Chris@16
|
197
|
Chris@16
|
198 robust_fpt operator*(const robust_fpt& that) const {
|
Chris@16
|
199 floating_point_type fpv = this->fpv_ * that.fpv_;
|
Chris@16
|
200 relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR;
|
Chris@16
|
201 return robust_fpt(fpv, re);
|
Chris@16
|
202 }
|
Chris@16
|
203
|
Chris@16
|
204 robust_fpt operator/(const robust_fpt& that) const {
|
Chris@16
|
205 floating_point_type fpv = this->fpv_ / that.fpv_;
|
Chris@16
|
206 relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR;
|
Chris@16
|
207 return robust_fpt(fpv, re);
|
Chris@16
|
208 }
|
Chris@16
|
209
|
Chris@16
|
210 robust_fpt sqrt() const {
|
Chris@16
|
211 return robust_fpt(get_sqrt(fpv_),
|
Chris@16
|
212 re_ * static_cast<relative_error_type>(0.5) +
|
Chris@16
|
213 ROUNDING_ERROR);
|
Chris@16
|
214 }
|
Chris@16
|
215
|
Chris@16
|
216 private:
|
Chris@16
|
217 floating_point_type fpv_;
|
Chris@16
|
218 relative_error_type re_;
|
Chris@16
|
219 };
|
Chris@16
|
220
|
Chris@16
|
221 template <typename T>
|
Chris@16
|
222 robust_fpt<T> get_sqrt(const robust_fpt<T>& that) {
|
Chris@16
|
223 return that.sqrt();
|
Chris@16
|
224 }
|
Chris@16
|
225
|
Chris@16
|
226 template <typename T>
|
Chris@16
|
227 bool is_pos(const robust_fpt<T>& that) {
|
Chris@16
|
228 return that.has_pos_value();
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 template <typename T>
|
Chris@16
|
232 bool is_neg(const robust_fpt<T>& that) {
|
Chris@16
|
233 return that.has_neg_value();
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 template <typename T>
|
Chris@16
|
237 bool is_zero(const robust_fpt<T>& that) {
|
Chris@16
|
238 return that.has_zero_value();
|
Chris@16
|
239 }
|
Chris@16
|
240
|
Chris@16
|
241 // robust_dif consists of two not negative values: value1 and value2.
|
Chris@16
|
242 // The resulting expression is equal to the value1 - value2.
|
Chris@16
|
243 // Subtraction of a positive value is equivalent to the addition to value2
|
Chris@16
|
244 // and subtraction of a negative value is equivalent to the addition to
|
Chris@16
|
245 // value1. The structure implicitly avoids difference computation.
|
Chris@16
|
246 template <typename T>
|
Chris@16
|
247 class robust_dif {
|
Chris@16
|
248 public:
|
Chris@16
|
249 robust_dif() :
|
Chris@16
|
250 positive_sum_(0),
|
Chris@16
|
251 negative_sum_(0) {}
|
Chris@16
|
252
|
Chris@16
|
253 explicit robust_dif(const T& value) :
|
Chris@16
|
254 positive_sum_((value > 0)?value:0),
|
Chris@16
|
255 negative_sum_((value < 0)?-value:0) {}
|
Chris@16
|
256
|
Chris@16
|
257 robust_dif(const T& pos, const T& neg) :
|
Chris@16
|
258 positive_sum_(pos),
|
Chris@16
|
259 negative_sum_(neg) {}
|
Chris@16
|
260
|
Chris@16
|
261 T dif() const {
|
Chris@16
|
262 return positive_sum_ - negative_sum_;
|
Chris@16
|
263 }
|
Chris@16
|
264
|
Chris@16
|
265 T pos() const {
|
Chris@16
|
266 return positive_sum_;
|
Chris@16
|
267 }
|
Chris@16
|
268
|
Chris@16
|
269 T neg() const {
|
Chris@16
|
270 return negative_sum_;
|
Chris@16
|
271 }
|
Chris@16
|
272
|
Chris@16
|
273 robust_dif<T> operator-() const {
|
Chris@16
|
274 return robust_dif(negative_sum_, positive_sum_);
|
Chris@16
|
275 }
|
Chris@16
|
276
|
Chris@16
|
277 robust_dif<T>& operator+=(const T& val) {
|
Chris@16
|
278 if (!is_neg(val))
|
Chris@16
|
279 positive_sum_ += val;
|
Chris@16
|
280 else
|
Chris@16
|
281 negative_sum_ -= val;
|
Chris@16
|
282 return *this;
|
Chris@16
|
283 }
|
Chris@16
|
284
|
Chris@16
|
285 robust_dif<T>& operator+=(const robust_dif<T>& that) {
|
Chris@16
|
286 positive_sum_ += that.positive_sum_;
|
Chris@16
|
287 negative_sum_ += that.negative_sum_;
|
Chris@16
|
288 return *this;
|
Chris@16
|
289 }
|
Chris@16
|
290
|
Chris@16
|
291 robust_dif<T>& operator-=(const T& val) {
|
Chris@16
|
292 if (!is_neg(val))
|
Chris@16
|
293 negative_sum_ += val;
|
Chris@16
|
294 else
|
Chris@16
|
295 positive_sum_ -= val;
|
Chris@16
|
296 return *this;
|
Chris@16
|
297 }
|
Chris@16
|
298
|
Chris@16
|
299 robust_dif<T>& operator-=(const robust_dif<T>& that) {
|
Chris@16
|
300 positive_sum_ += that.negative_sum_;
|
Chris@16
|
301 negative_sum_ += that.positive_sum_;
|
Chris@16
|
302 return *this;
|
Chris@16
|
303 }
|
Chris@16
|
304
|
Chris@16
|
305 robust_dif<T>& operator*=(const T& val) {
|
Chris@16
|
306 if (!is_neg(val)) {
|
Chris@16
|
307 positive_sum_ *= val;
|
Chris@16
|
308 negative_sum_ *= val;
|
Chris@16
|
309 } else {
|
Chris@16
|
310 positive_sum_ *= -val;
|
Chris@16
|
311 negative_sum_ *= -val;
|
Chris@16
|
312 swap();
|
Chris@16
|
313 }
|
Chris@16
|
314 return *this;
|
Chris@16
|
315 }
|
Chris@16
|
316
|
Chris@16
|
317 robust_dif<T>& operator*=(const robust_dif<T>& that) {
|
Chris@16
|
318 T positive_sum = this->positive_sum_ * that.positive_sum_ +
|
Chris@16
|
319 this->negative_sum_ * that.negative_sum_;
|
Chris@16
|
320 T negative_sum = this->positive_sum_ * that.negative_sum_ +
|
Chris@16
|
321 this->negative_sum_ * that.positive_sum_;
|
Chris@16
|
322 positive_sum_ = positive_sum;
|
Chris@16
|
323 negative_sum_ = negative_sum;
|
Chris@16
|
324 return *this;
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 robust_dif<T>& operator/=(const T& val) {
|
Chris@16
|
328 if (!is_neg(val)) {
|
Chris@16
|
329 positive_sum_ /= val;
|
Chris@16
|
330 negative_sum_ /= val;
|
Chris@16
|
331 } else {
|
Chris@16
|
332 positive_sum_ /= -val;
|
Chris@16
|
333 negative_sum_ /= -val;
|
Chris@16
|
334 swap();
|
Chris@16
|
335 }
|
Chris@16
|
336 return *this;
|
Chris@16
|
337 }
|
Chris@16
|
338
|
Chris@16
|
339 private:
|
Chris@16
|
340 void swap() {
|
Chris@16
|
341 (std::swap)(positive_sum_, negative_sum_);
|
Chris@16
|
342 }
|
Chris@16
|
343
|
Chris@16
|
344 T positive_sum_;
|
Chris@16
|
345 T negative_sum_;
|
Chris@16
|
346 };
|
Chris@16
|
347
|
Chris@16
|
348 template<typename T>
|
Chris@16
|
349 robust_dif<T> operator+(const robust_dif<T>& lhs,
|
Chris@16
|
350 const robust_dif<T>& rhs) {
|
Chris@16
|
351 return robust_dif<T>(lhs.pos() + rhs.pos(), lhs.neg() + rhs.neg());
|
Chris@16
|
352 }
|
Chris@16
|
353
|
Chris@16
|
354 template<typename T>
|
Chris@16
|
355 robust_dif<T> operator+(const robust_dif<T>& lhs, const T& rhs) {
|
Chris@16
|
356 if (!is_neg(rhs)) {
|
Chris@16
|
357 return robust_dif<T>(lhs.pos() + rhs, lhs.neg());
|
Chris@16
|
358 } else {
|
Chris@16
|
359 return robust_dif<T>(lhs.pos(), lhs.neg() - rhs);
|
Chris@16
|
360 }
|
Chris@16
|
361 }
|
Chris@16
|
362
|
Chris@16
|
363 template<typename T>
|
Chris@16
|
364 robust_dif<T> operator+(const T& lhs, const robust_dif<T>& rhs) {
|
Chris@16
|
365 if (!is_neg(lhs)) {
|
Chris@16
|
366 return robust_dif<T>(lhs + rhs.pos(), rhs.neg());
|
Chris@16
|
367 } else {
|
Chris@16
|
368 return robust_dif<T>(rhs.pos(), rhs.neg() - lhs);
|
Chris@16
|
369 }
|
Chris@16
|
370 }
|
Chris@16
|
371
|
Chris@16
|
372 template<typename T>
|
Chris@16
|
373 robust_dif<T> operator-(const robust_dif<T>& lhs,
|
Chris@16
|
374 const robust_dif<T>& rhs) {
|
Chris@16
|
375 return robust_dif<T>(lhs.pos() + rhs.neg(), lhs.neg() + rhs.pos());
|
Chris@16
|
376 }
|
Chris@16
|
377
|
Chris@16
|
378 template<typename T>
|
Chris@16
|
379 robust_dif<T> operator-(const robust_dif<T>& lhs, const T& rhs) {
|
Chris@16
|
380 if (!is_neg(rhs)) {
|
Chris@16
|
381 return robust_dif<T>(lhs.pos(), lhs.neg() + rhs);
|
Chris@16
|
382 } else {
|
Chris@16
|
383 return robust_dif<T>(lhs.pos() - rhs, lhs.neg());
|
Chris@16
|
384 }
|
Chris@16
|
385 }
|
Chris@16
|
386
|
Chris@16
|
387 template<typename T>
|
Chris@16
|
388 robust_dif<T> operator-(const T& lhs, const robust_dif<T>& rhs) {
|
Chris@16
|
389 if (!is_neg(lhs)) {
|
Chris@16
|
390 return robust_dif<T>(lhs + rhs.neg(), rhs.pos());
|
Chris@16
|
391 } else {
|
Chris@16
|
392 return robust_dif<T>(rhs.neg(), rhs.pos() - lhs);
|
Chris@16
|
393 }
|
Chris@16
|
394 }
|
Chris@16
|
395
|
Chris@16
|
396 template<typename T>
|
Chris@16
|
397 robust_dif<T> operator*(const robust_dif<T>& lhs,
|
Chris@16
|
398 const robust_dif<T>& rhs) {
|
Chris@16
|
399 T res_pos = lhs.pos() * rhs.pos() + lhs.neg() * rhs.neg();
|
Chris@16
|
400 T res_neg = lhs.pos() * rhs.neg() + lhs.neg() * rhs.pos();
|
Chris@16
|
401 return robust_dif<T>(res_pos, res_neg);
|
Chris@16
|
402 }
|
Chris@16
|
403
|
Chris@16
|
404 template<typename T>
|
Chris@16
|
405 robust_dif<T> operator*(const robust_dif<T>& lhs, const T& val) {
|
Chris@16
|
406 if (!is_neg(val)) {
|
Chris@16
|
407 return robust_dif<T>(lhs.pos() * val, lhs.neg() * val);
|
Chris@16
|
408 } else {
|
Chris@16
|
409 return robust_dif<T>(-lhs.neg() * val, -lhs.pos() * val);
|
Chris@16
|
410 }
|
Chris@16
|
411 }
|
Chris@16
|
412
|
Chris@16
|
413 template<typename T>
|
Chris@16
|
414 robust_dif<T> operator*(const T& val, const robust_dif<T>& rhs) {
|
Chris@16
|
415 if (!is_neg(val)) {
|
Chris@16
|
416 return robust_dif<T>(val * rhs.pos(), val * rhs.neg());
|
Chris@16
|
417 } else {
|
Chris@16
|
418 return robust_dif<T>(-val * rhs.neg(), -val * rhs.pos());
|
Chris@16
|
419 }
|
Chris@16
|
420 }
|
Chris@16
|
421
|
Chris@16
|
422 template<typename T>
|
Chris@16
|
423 robust_dif<T> operator/(const robust_dif<T>& lhs, const T& val) {
|
Chris@16
|
424 if (!is_neg(val)) {
|
Chris@16
|
425 return robust_dif<T>(lhs.pos() / val, lhs.neg() / val);
|
Chris@16
|
426 } else {
|
Chris@16
|
427 return robust_dif<T>(-lhs.neg() / val, -lhs.pos() / val);
|
Chris@16
|
428 }
|
Chris@16
|
429 }
|
Chris@16
|
430
|
Chris@16
|
431 // Used to compute expressions that operate with sqrts with predefined
|
Chris@16
|
432 // relative error. Evaluates expressions of the next type:
|
Chris@16
|
433 // sum(i = 1 .. n)(A[i] * sqrt(B[i])), 1 <= n <= 4.
|
Chris@16
|
434 template <typename _int, typename _fpt, typename _converter>
|
Chris@16
|
435 class robust_sqrt_expr {
|
Chris@16
|
436 public:
|
Chris@16
|
437 enum MAX_RELATIVE_ERROR {
|
Chris@16
|
438 MAX_RELATIVE_ERROR_EVAL1 = 4,
|
Chris@16
|
439 MAX_RELATIVE_ERROR_EVAL2 = 7,
|
Chris@16
|
440 MAX_RELATIVE_ERROR_EVAL3 = 16,
|
Chris@16
|
441 MAX_RELATIVE_ERROR_EVAL4 = 25
|
Chris@16
|
442 };
|
Chris@16
|
443
|
Chris@16
|
444 // Evaluates expression (re = 4 EPS):
|
Chris@16
|
445 // A[0] * sqrt(B[0]).
|
Chris@16
|
446 _fpt eval1(_int* A, _int* B) {
|
Chris@16
|
447 _fpt a = convert(A[0]);
|
Chris@16
|
448 _fpt b = convert(B[0]);
|
Chris@16
|
449 return a * get_sqrt(b);
|
Chris@16
|
450 }
|
Chris@16
|
451
|
Chris@16
|
452 // Evaluates expression (re = 7 EPS):
|
Chris@16
|
453 // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]).
|
Chris@16
|
454 _fpt eval2(_int* A, _int* B) {
|
Chris@16
|
455 _fpt a = eval1(A, B);
|
Chris@16
|
456 _fpt b = eval1(A + 1, B + 1);
|
Chris@16
|
457 if ((!is_neg(a) && !is_neg(b)) ||
|
Chris@16
|
458 (!is_pos(a) && !is_pos(b)))
|
Chris@16
|
459 return a + b;
|
Chris@16
|
460 return convert(A[0] * A[0] * B[0] - A[1] * A[1] * B[1]) / (a - b);
|
Chris@16
|
461 }
|
Chris@16
|
462
|
Chris@16
|
463 // Evaluates expression (re = 16 EPS):
|
Chris@16
|
464 // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + A[2] * sqrt(B[2]).
|
Chris@16
|
465 _fpt eval3(_int* A, _int* B) {
|
Chris@16
|
466 _fpt a = eval2(A, B);
|
Chris@16
|
467 _fpt b = eval1(A + 2, B + 2);
|
Chris@16
|
468 if ((!is_neg(a) && !is_neg(b)) ||
|
Chris@16
|
469 (!is_pos(a) && !is_pos(b)))
|
Chris@16
|
470 return a + b;
|
Chris@16
|
471 tA[3] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[2];
|
Chris@16
|
472 tB[3] = 1;
|
Chris@16
|
473 tA[4] = A[0] * A[1] * 2;
|
Chris@16
|
474 tB[4] = B[0] * B[1];
|
Chris@16
|
475 return eval2(tA + 3, tB + 3) / (a - b);
|
Chris@16
|
476 }
|
Chris@16
|
477
|
Chris@16
|
478
|
Chris@16
|
479 // Evaluates expression (re = 25 EPS):
|
Chris@16
|
480 // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) +
|
Chris@16
|
481 // A[2] * sqrt(B[2]) + A[3] * sqrt(B[3]).
|
Chris@16
|
482 _fpt eval4(_int* A, _int* B) {
|
Chris@16
|
483 _fpt a = eval2(A, B);
|
Chris@16
|
484 _fpt b = eval2(A + 2, B + 2);
|
Chris@16
|
485 if ((!is_neg(a) && !is_neg(b)) ||
|
Chris@16
|
486 (!is_pos(a) && !is_pos(b)))
|
Chris@16
|
487 return a + b;
|
Chris@16
|
488 tA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
|
Chris@16
|
489 A[2] * A[2] * B[2] - A[3] * A[3] * B[3];
|
Chris@16
|
490 tB[0] = 1;
|
Chris@16
|
491 tA[1] = A[0] * A[1] * 2;
|
Chris@16
|
492 tB[1] = B[0] * B[1];
|
Chris@16
|
493 tA[2] = A[2] * A[3] * -2;
|
Chris@16
|
494 tB[2] = B[2] * B[3];
|
Chris@16
|
495 return eval3(tA, tB) / (a - b);
|
Chris@16
|
496 }
|
Chris@16
|
497
|
Chris@16
|
498 private:
|
Chris@16
|
499 _int tA[5];
|
Chris@16
|
500 _int tB[5];
|
Chris@16
|
501 _converter convert;
|
Chris@16
|
502 };
|
Chris@16
|
503 } // detail
|
Chris@16
|
504 } // polygon
|
Chris@16
|
505 } // boost
|
Chris@16
|
506
|
Chris@16
|
507 #endif // BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT
|