GCC Code Coverage Report


Directory: ./
File: lib/geogram/numerics/interval_nt.h
Date: 2026-09-07 02:25:23
Exec Total Coverage
Lines: 101 110 91.8%
Functions: 9 9 100.0%
Branches: 58 88 65.9%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEO_INTERVAL_NT
41 #define GEO_INTERVAL_NT
42
43 #include <geogram/numerics/expansion_nt.h>
44 #include <geogram/basic/vechg.h>
45 #include <iomanip>
46 #include <limits>
47 #include <cmath>
48
49 #ifdef __SSE__
50 #include <xmmintrin.h>
51 #else
52 #include <fenv.h>
53 #endif
54
55 // Uncomment to activate checks (keeps an arbitrary precision
56 // representation of the number and checks that the interval
57 // contains it).
58 // #define INTERVAL_CHECK
59
60 // Uncomment to deactivate all interval filters in geogram
61 // (used for debugging and performance tests)
62 // #define GEO_NO_INTERVALS
63
64 namespace GEO {
65
66 /**
67 * \brief Base class for interval arithmetics.
68 * \details Has the verification mechanics
69 * (define INTERVAL_CHECK to activate it). Verification
70 * stores an additional expansion_nt and checks
71 * that this expansion_nt is contained by the
72 * interval.
73 */
74 class intervalBase {
75 public:
76
77 static void set_FPU_round_to_nearest() {
78 #ifdef __SSE__
79 _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
80 #else
81 fesetround(FE_TONEAREST);
82 #endif
83 }
84
85 static void set_FPU_round_to_upper() {
86 #ifdef __SSE__
87 _MM_SET_ROUNDING_MODE(_MM_ROUND_UP);
88 #else
89 fesetround(FE_UPWARD);
90 #endif
91 }
92
93 enum Sign2 {
94 SIGN2_ERROR = -1,
95 SIGN2_ZERO = 0,
96 SIGN2_NP,
97 SIGN2_PP,
98 SIGN2_ZP,
99 SIGN2_NN,
100 SIGN2_NZ
101 };
102
103 static bool sign_is_determined(Sign2 s) {
104 return
105 s == SIGN2_ZERO ||
106 s == SIGN2_NN ||
107 s == SIGN2_PP ;
108 }
109
110 static bool sign_is_non_zero(Sign2 s) {
111 return
112 1462052 s == SIGN2_NN ||
113
10/16
✓ Branch 0 taken 341932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 341932 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 341932 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 305895 times.
✓ Branch 7 taken 36037 times.
✓ Branch 8 taken 23581 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23581 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23581 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 16069 times.
✓ Branch 15 taken 7512 times.
707445 s == SIGN2_PP ;
114 }
115
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5989583 times.
5989583 static Sign convert_sign(Sign2 s) {
117 geo_assert(sign_is_determined(s));
118
2/2
✓ Branch 0 taken 3127254 times.
✓ Branch 1 taken 2862329 times.
5989583 if(s == SIGN2_NN) {
119 return NEGATIVE;
120 }
121
1/2
✓ Branch 0 taken 3127254 times.
✗ Branch 1 not taken.
3127254 if(s == SIGN2_PP) {
122 3127254 return POSITIVE;
123 }
124 return ZERO;
125 }
126
127 intervalBase() {
128 control_set(0);
129 }
130
131 intervalBase(double x) {
132 control_set(x);
133 }
134
135 intervalBase(const intervalBase& rhs) = default;
136
137 intervalBase& operator=(const intervalBase& rhs) = default;
138
139 protected:
140 #ifdef INTERVAL_CHECK
141 void control_set(const expansion_nt& x) {
142 control_ = x;
143 }
144 void control_set(const intervalBase& x) {
145 control_ = x.control_;
146 }
147 void control_set(double x) {
148 control_ = expansion_nt(x);
149 }
150 void control_negate() {
151 control_.rep().negate();
152 }
153 void control_add(const intervalBase& x) {
154 control_ += x.control_;
155 }
156 void control_sub(const intervalBase& x) {
157 control_ -= x.control_;
158 }
159 void control_mul(const intervalBase& x) {
160 control_ *= x.control_;
161 }
162 void control_check(double inf, double sup) {
163 typedef std::numeric_limits< double > dbl;
164 if(inf > sup) {
165 std::cerr.precision(dbl::max_digits10);
166 std::cerr << "inf() > sup() !!" << std::endl;
167 std::cerr << "inf()=" << inf << std::endl;
168 std::cerr << "sup()=" << sup << std::endl;
169 geo_assert_not_reached;
170 }
171 if(control_ < inf || control_ > sup) {
172 std::cerr.precision(dbl::max_digits10);
173 std::cerr << "[" << inf << "," << sup << "]"
174 << " " << control_.estimate() << ":"
175 << control_.rep().length()
176 << std::endl;
177 geo_assert_not_reached;
178 }
179 }
180 expansion_nt control_; /**< exact represented value, for tests */
181 #else
182 void control_set(double x) {
183 geo_argused(x);
184 }
185 void control_set(const expansion_nt& x) {
186 geo_argused(x);
187 }
188 void control_set(const intervalBase& x) {
189 geo_argused(x);
190 }
191 void control_negate() {
192 }
193 void control_add(const intervalBase& x) {
194 geo_argused(x);
195 }
196 void control_sub(const intervalBase& x) {
197 geo_argused(x);
198 }
199 void control_mul(const intervalBase& x) {
200 geo_argused(x);
201 }
202 void control_check(double inf, double sup) {
203 geo_argused(inf);
204 geo_argused(sup);
205 }
206 #endif
207 };
208
209
210 /*******************************************************************/
211
212 /**
213 * \brief Interval arithmetics in round to upper (RU) mode.
214 */
215 class intervalRU : public intervalBase {
216 public:
217
218 /**
219 * \brief Sets FPU rounding mode for using this type of interval.
220 * \details Declare one instance at the beginning of a function or
221 * bloc of code that uses intervalRU. Do not mix other floating
222 * point operations in the bloc.
223 * \code
224 * {
225 * intervalRU::Rounding rounding;
226 * ... do some computations with intervalRU
227 * }
228 * \endcode
229 */
230 struct Rounding {
231 Rounding() {
232 set_FPU_round_to_upper();
233 }
234 ~Rounding() {
235 set_FPU_round_to_nearest();
236 }
237 };
238
239 intervalRU() :
240 intervalBase(),
241 ln_(0.0),
242 u_(0.0)
243 {
244 control_check();
245 }
246
247 intervalRU(double x) :
248 intervalBase(x),
249 ln_(-x),
250 u_(x)
251 {
252 control_check();
253 }
254
255 intervalRU(double l, double u) : ln_(-l), u_(u) {
256 // note: we cannot control check here.
257 }
258
259 intervalRU(const intervalRU& rhs) = default;
260
261 intervalRU(const expansion_nt& rhs) {
262 *this = rhs;
263 }
264
265 intervalRU& operator=(const intervalRU& rhs) = default;
266
267 intervalRU& operator=(double rhs) {
268 ln_ = -rhs;
269 u_ = rhs;
270 control_set(rhs);
271 control_check();
272 return *this;
273 }
274
275 intervalRU& operator=(const expansion_nt& rhs) {
276
277 // Optimized expansion-to-interval conversion:
278 //
279 // Add components starting from the one of largest magnitude
280 // Stop as soon as next component is smaller than ulp (and then
281 // expand interval by ulp).
282
283 index_t l = rhs.length();
284 ln_ = -rhs.component(l-1);
285 u_ = rhs.component(l-1);
286
287 for(int comp_idx=int(l)-2; comp_idx>=0; --comp_idx) {
288 double comp = rhs.component(index_t(comp_idx));
289 u_ += comp;
290 ln_ -= comp;
291 if(comp > 0) {
292 double new_u = u_ + comp;
293 if(new_u == u_) {
294 u_ = std::nextafter(
295 u_, std::numeric_limits<double>::infinity()
296 );
297 break;
298 } else {
299 u_ = new_u;
300 }
301 } else {
302 // If we stored l, we would write:
303 // new_l = l + comp
304 // But we store ln = -l, so we write:
305 // -new_ln = -ln + comp
306 // Which means:
307 // new_ln = ln - comp
308
309 double new_ln = ln_ - comp;
310 if(new_ln == ln_) {
311 ln_ = std::nextafter(
312 ln_, std::numeric_limits<double>::infinity()
313 );
314 break;
315 } else {
316 ln_ = new_ln;
317 }
318 }
319 }
320
321 control_set(rhs);
322 control_check();
323 return *this;
324 }
325
326 double inf() const {
327 return -ln_;
328 }
329
330 double sup() const {
331 return u_;
332 }
333
334 double estimate() const {
335 // 0.5*(lb+ub) ->
336 return 0.5*(-ln_+u_);
337 }
338
339 bool is_nan() const {
340 return !(ln_==ln_) || !(u_==u_);
341 }
342
343 Sign2 sign() const {
344 // Branchless
345 int lz = int(ln_ == 0);
346 int ln = int(ln_ > 0); // inverted, it is ln_ !!!
347 int lp = int(ln_ < 0); // inverted, it is ln_ !!!
348 int uz = int(u_ == 0);
349 int un = int(u_ < 0);
350 int up = int(u_ > 0);
351 Sign2 result = Sign2(
352 ln*up*SIGN2_NP+
353 lp*up*SIGN2_PP+
354 lz*up*SIGN2_ZP+
355 ln*un*SIGN2_NN+
356 ln*uz*SIGN2_NZ
357 );
358 result = Sign2(
359 int(result) +
360 int(result==SIGN2_ZERO && !(lz&&uz)) * SIGN2_ERROR
361 );
362 return result;
363 }
364
365 intervalRU& negate() {
366 std::swap(ln_, u_);
367 control_negate();
368 control_check();
369 return *this;
370 }
371
372 intervalRU& operator+=(const intervalRU &x) {
373 // lb += x.lb -> -lbn += -x.lbn -> lbn += x.lbn
374 ln_ += x.ln_;
375 u_ += x.u_;
376 control_add(x);
377 control_check();
378 return *this;
379 }
380
381 intervalRU& operator-=(const intervalRU &x) {
382 // +=(x.negate()) ->
383 ln_ += x.u_;
384 u_ += x.ln_;
385 control_sub(x);
386 control_check();
387 return *this;
388 }
389
390
391 intervalRU& operator*=(const intervalRU &b) {
392 // get bounds of both operands
393 double aln = ln_;
394 double au = u_;
395 double bln = b.ln_;
396 double bu = b.u_;
397
398 // negated bounds round to upper
399 // (equivalent to bounds round to lower)
400 double lln = (-aln)*bln;
401 double lun = aln*bu;
402 double uln = au*bln;
403 double uun = (-au)*bu;
404
405 // bounds round to upper
406 double ll = aln*bln;
407 double lu = (-aln)*bu;
408 double ul = au*(-bln);
409 double uu = au*bu;
410
411 ln_ = std::max(std::max(lln,lun),std::max(uln,uun));
412 u_ = std::max(std::max(ll,lu),std::max(ul,uu));
413
414 control_mul(b);
415 control_check();
416 return *this;
417 }
418
419 protected:
420
421 #ifdef INTERVAL_CHECK
422 void control_check() {
423 // expansion_nt used in control_check() operates
424 // in round to nearest mode !!
425 set_FPU_round_to_nearest();
426 intervalBase::control_check(inf(),sup());
427 set_FPU_round_to_upper();
428 }
429 #else
430 void control_check() {
431 }
432 #endif
433 double ln_;
434 double u_;
435 };
436
437
438 inline intervalRU operator+(const intervalRU& a, const intervalRU& b) {
439 intervalRU result = a;
440 return result += b;
441 }
442
443 inline intervalRU operator-(const intervalRU& a, const intervalRU& b) {
444 intervalRU result = a;
445 return result -= b;
446 }
447
448 inline intervalRU operator*(const intervalRU& a, const intervalRU& b) {
449 intervalRU result = a;
450 return result *= b;
451 }
452
453 /*************************************************************************/
454
455 /**
456 * \brief Number type for interval arithmetics
457 * \details Interval class in "round to nearest" mode, by Richard Harris:
458 * https://accu.org/journals/overload/19/103/harris_1974/
459 * Propagates proportional errors at a rate of 1+/-0.5eps
460 * Handles denormals properly (as a special case).
461 */
462 class intervalRN : public intervalBase {
463 public:
464
465 // operates in default rounding mode
466 // (so Rounding subclass does nothing)
467 struct Rounding {
468 Rounding() {
469 }
470 ~Rounding() {
471 }
472 };
473
474 intervalRN() :
475 intervalBase(),
476 lb_(0.0),
477 ub_(0.0)
478 {
479 control_check();
480 }
481
482 1066264 intervalRN(double x) :
483 intervalBase(x),
484 1066264 lb_(x),
485
2/2
✓ Branch 0 taken 196995 times.
✓ Branch 1 taken 527337 times.
1066264 ub_(x)
486 {
487 control_check();
488 }
489
490 intervalRN(double l, double u) : lb_(l), ub_(u) {
491 // note: we cannot control check here.
492 }
493
494
495 intervalRN(const intervalRN& rhs) = default;
496
497 47757115 intervalRN(const expansion_nt& rhs) {
498 6270567 *this = rhs;
499 }
500
501 intervalRN& operator=(const intervalRN& rhs) = default;
502
503 intervalRN& operator=(double rhs) {
504 lb_ = rhs;
505 ub_ = rhs;
506 control_set(rhs);
507 control_check();
508 return *this;
509 }
510
511 47757115 intervalRN& operator=(const expansion_nt& rhs) {
512
513 // Optimized expansion-to-interval conversion:
514 //
515 // Add components starting from the one of largest magnitude
516 // Stop as soon as next component is smaller than ulp (and then
517 // expand interval by ulp).
518
519 index_t l = rhs.length();
520 47757115 lb_ = rhs.component(l-1);
521 47757115 ub_ = rhs.component(l-1);
522
523
2/2
✓ Branch 0 taken 35006131 times.
✓ Branch 1 taken 12750984 times.
47757115 for(int comp_idx=int(l)-2; comp_idx>=0; --comp_idx) {
524
2/2
✓ Branch 0 taken 17507121 times.
✓ Branch 1 taken 17499010 times.
35006131 double comp = rhs.component(index_t(comp_idx));
525
2/2
✓ Branch 0 taken 17507121 times.
✓ Branch 1 taken 17499010 times.
35006131 if(comp > 0) {
526 17507121 double nub = ub_ + comp;
527
1/2
✓ Branch 0 taken 17507121 times.
✗ Branch 1 not taken.
17507121 if(nub == ub_) {
528 17507121 ub_ = std::nextafter(
529 ub_, std::numeric_limits<double>::infinity()
530 );
531 17507121 break;
532 } else {
533 ub_ = nub;
534 adjust();
535 }
536 } else {
537 17499010 double nlb = lb_ + comp;
538
1/2
✓ Branch 0 taken 17499010 times.
✗ Branch 1 not taken.
17499010 if(nlb == lb_) {
539 17499010 lb_ = std::nextafter(
540 lb_, -std::numeric_limits<double>::infinity()
541 );
542 17499010 break;
543 } else {
544 lb_ = nlb;
545 adjust();
546 }
547 }
548 }
549 control_set(rhs);
550 control_check();
551 47757115 return *this;
552 }
553
554 double inf() const {
555 return lb_;
556 }
557
558 double sup() const {
559 return ub_;
560 }
561
562 double estimate() const {
563 return 0.5*(lb_ + ub_);
564 }
565
566 bool is_nan() const {
567
4/8
✓ Branch 0 taken 57562221 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57562221 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57562221 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8835293 times.
✗ Branch 7 not taken.
66397514 return !(lb_==lb_) || !(ub_==ub_);
568 }
569
570
1/2
✓ Branch 0 taken 8835293 times.
✗ Branch 1 not taken.
8835293 Sign2 sign() const {
571 if(is_nan()) {
572 return SIGN2_ERROR;
573 }
574 // Branchless (not sure it is super though...)
575 8835293 int lz = int(lb_ == 0);
576 8835293 int ln = int(lb_ < 0);
577 8835293 int lp = int(lb_ > 0);
578 8835293 int uz = int(ub_ == 0);
579 8835293 int un = int(ub_ < 0);
580 8835293 int up = int(ub_ > 0);
581 8835293 Sign2 result = Sign2(
582 8835293 ln*up*SIGN2_NP+
583 8835293 lp*up*SIGN2_PP+
584 8835293 lz*up*SIGN2_ZP+
585 8835293 ln*un*SIGN2_NN+
586 8835293 ln*uz*SIGN2_NZ
587 );
588 8835293 result = Sign2(
589 int(result) +
590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8835293 times.
8835293 int(result==SIGN2_ZERO && !(lz&&uz)) * SIGN2_ERROR
591 );
592 8835293 return result;
593 }
594
595 intervalRN& negate() {
596 212813 lb_ = -lb_;
597 212813 ub_ = -ub_;
598 std::swap(lb_, ub_);
599 control_negate();
600 control_check();
601 212813 return *this;
602 }
603
604 intervalRN& operator+=(const intervalRN &x) {
605 5174028 lb_ += x.lb_;
606 5174028 ub_ += x.ub_;
607 5174028 adjust();
608 control_add(x);
609 control_check();
610 return *this;
611 }
612
613 intervalRN& operator-=(const intervalRN &x) {
614 30896447 lb_ -= x.ub_;
615 30896447 ub_ -= x.lb_;
616 30896447 adjust();
617 control_sub(x);
618 control_check();
619 return *this;
620 }
621
622
1/2
✓ Branch 0 taken 57562221 times.
✗ Branch 1 not taken.
57562221 intervalRN& operator*=(const intervalRN &x) {
623 if(!is_nan() && !x.is_nan()) {
624 57562221 double ll = lb_*x.lb_;
625 57562221 double lu = lb_*x.ub_;
626 57562221 double ul = ub_*x.lb_;
627 57562221 double uu = ub_*x.ub_;
628
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57562221 times.
57562221 if(!(ll==ll)) ll = 0.0;
630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57562221 times.
57562221 if(!(lu==lu)) lu = 0.0;
631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57562221 times.
57562221 if(!(ul==ul)) ul = 0.0;
632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57562221 times.
57562221 if(!(uu==uu)) uu = 0.0;
633
634
2/2
✓ Branch 0 taken 20846213 times.
✓ Branch 1 taken 36716008 times.
57562221 if(lu<ll) std::swap(lu, ll);
635
2/2
✓ Branch 0 taken 11075132 times.
✓ Branch 1 taken 46487089 times.
57562221 if(ul<ll) std::swap(ul, ll);
636
2/2
✓ Branch 0 taken 8087304 times.
✓ Branch 1 taken 49474917 times.
57562221 if(uu<ll) std::swap(uu, ll);
637
638 if(lu>uu) uu = lu;
639 if(ul>uu) uu = ul;
640
641 57562221 lb_ = ll;
642 57562221 ub_ = uu;
643
644 57562221 adjust();
645 } else {
646 lb_ = std::numeric_limits<double>::quiet_NaN();
647 ub_ = std::numeric_limits<double>::quiet_NaN();
648 }
649 control_mul(x);
650 control_check();
651 57562221 return *this;
652 }
653
654 protected:
655
656 93632696 void adjust() {
657 static constexpr double i = std::numeric_limits<double>::infinity();
658 static constexpr double e = std::numeric_limits<double>::epsilon();
659 // e = nextafter(1.0) - 1.0
660 static constexpr double m = std::numeric_limits<double>::min();
661 // m = smallest normalized
662 static constexpr double l = 1.0-e;
663 static constexpr double u = 1.0+e;
664 static constexpr double em = e*m;
665
666
6/10
✓ Branch 0 taken 93632696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93632696 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13948935 times.
✓ Branch 5 taken 79683761 times.
✓ Branch 6 taken 13948935 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13948935 times.
✗ Branch 9 not taken.
93632696 if(lb_==lb_ && ub_==ub_ && (lb_!=ub_ || (lb_!=i && lb_!=-i))) {
667
668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93632696 times.
93632696 if(lb_>ub_) {
669 std::swap(lb_, ub_);
670 }
671
672
2/2
✓ Branch 0 taken 42385177 times.
✓ Branch 1 taken 51247519 times.
93632696 if(lb_>m) {
673 42385177 lb_ *= l;
674
2/2
✓ Branch 0 taken 45374311 times.
✓ Branch 1 taken 5873208 times.
51247519 } else if(lb_<-m) {
675 45374311 lb_ *= u;
676 } else {
677 5873208 lb_ -= em;
678 }
679
680
2/2
✓ Branch 0 taken 45867942 times.
✓ Branch 1 taken 47764754 times.
93632696 if(ub_>m) {
681 45867942 ub_ *= u;
682
2/2
✓ Branch 0 taken 41891800 times.
✓ Branch 1 taken 5872954 times.
47764754 } else if(ub_<-m) {
683 41891800 ub_ *= l;
684 } else {
685 5872954 ub_ += em;
686 }
687 } else {
688 lb_ = std::numeric_limits<double>::quiet_NaN();
689 ub_ = std::numeric_limits<double>::quiet_NaN();
690 }
691 93632696 }
692
693 #ifdef INTERVAL_CHECK
694 void control_check() {
695 intervalBase::control_check(inf(),sup());
696 }
697 #else
698 void control_check() {
699 }
700 #endif
701
702 private:
703 double lb_; /**< lower bound */
704 double ub_; /**< upper bound */
705 };
706
707 5174028 inline intervalRN operator+(const intervalRN& a, const intervalRN& b) {
708 5174028 intervalRN result = a;
709 5174028 return result += b;
710 }
711
712 30896447 inline intervalRN operator-(const intervalRN& a, const intervalRN& b) {
713 30896447 intervalRN result = a;
714 30896447 return result -= b;
715 }
716
717 inline intervalRN operator*(const intervalRN& a, const intervalRN& b) {
718 25474861 intervalRN result = a;
719
2/2
✓ Branch 11 taken 305895 times.
✓ Branch 12 taken 36037 times.
25132929 return result *= b;
720 }
721
722 /**********************************************************************/
723
724 /**
725 * \brief Dummy interval class, that does not compute anything and that
726 * always says that sign is undetermined.
727 * \details Used for performance testing and for debugging.
728 */
729 class intervalDummy : public intervalBase {
730 public:
731 struct Rounding {
732 Rounding() {
733 geo_argused(this); // silence a warning in predicate filters.
734 }
735 };
736
737 intervalDummy() {
738 }
739
740 intervalDummy(double x) {
741 geo_argused(x);
742 }
743
744 intervalDummy(double l, double u) {
745 geo_argused(l);
746 geo_argused(u);
747 }
748
749 intervalDummy(const intervalDummy& rhs) = default;
750
751 intervalDummy(const expansion_nt& rhs) {
752 geo_argused(rhs);
753 }
754
755 intervalDummy& operator=(const intervalDummy& rhs) = default;
756
757 intervalDummy& operator=(double rhs) {
758 geo_argused(rhs);
759 return *this;
760 }
761
762 intervalDummy& operator=(const expansion_nt& rhs) {
763 geo_argused(rhs);
764 return *this;
765 }
766
767 double inf() const {
768 return -std::numeric_limits<double>::infinity();
769 }
770
771 double sup() const {
772 return std::numeric_limits<double>::infinity();
773 }
774
775 double estimate() const {
776 return std::numeric_limits<double>::quiet_NaN();
777 }
778
779 bool is_nan() const {
780 return true;
781 }
782
783 Sign2 sign() const {
784 return SIGN2_NP;
785 }
786
787 intervalDummy& negate() {
788 return *this;
789 }
790
791 intervalDummy& operator+=(const intervalDummy &x) {
792 geo_argused(x);
793 return *this;
794 }
795
796 intervalDummy& operator-=(const intervalDummy &x) {
797 geo_argused(x);
798 return *this;
799 }
800
801 intervalDummy& operator*=(const intervalDummy &x) {
802 geo_argused(x);
803 return *this;
804 }
805 };
806
807 inline intervalDummy operator+(
808 const intervalDummy& a, const intervalDummy& b
809 ) {
810 intervalDummy result = a;
811 return result += b;
812 }
813
814 inline intervalDummy operator-(
815 const intervalDummy& a, const intervalDummy& b
816 ) {
817 intervalDummy result = a;
818 return result -= b;
819 }
820
821 inline intervalDummy operator*(
822 const intervalDummy& a, const intervalDummy& b
823 ) {
824 intervalDummy result = a;
825 return result *= b;
826 }
827
828 /**********************************************************************/
829
830 #ifdef GEO_NO_INTERVALS
831 typedef intervalDummy interval_nt;
832 #else
833 // interval_nt uses round to nearet (RN)
834 typedef intervalRN interval_nt;
835
836 // one could use round to upper (RU) instead, supposed to be slightly faster
837 // but we chose not to use it because:
838 // - does not seem to be significantly faster
839 // - makes the code more complicated, needs to change rounding mode)
840 // (but it is handled properly with the Rounding class provided that
841 // client code does not forget to declare one)
842 // - needs the compilation flag -frounding-math (disable compiler
843 // optimizations that suppose "round to nearest" mode)
844 // typedef intervalRU interval_nt;
845 #endif
846
847
848 /** \brief Specialization of GEO::is_scalar */
849 template <> struct is_scalar<interval_nt> {
850 typedef interval_nt type;
851 static constexpr bool value = true;
852 };
853
854 /**
855 * \brief Specialization of 2d homogeneous-coord vector difference
856 * for interval_nt coordinates
857 * \details We cannot check for p1.w and p2.w equality (since they
858 * might be in the same interval without being equal), so we always
859 * reduce to the same denominator.
860 */
861 1025796 template <> inline vec2Hg<interval_nt> operator-(
862 const vec2Hg<interval_nt>& p1, const vec2Hg<interval_nt>& p2
863 ) {
864 return vec2Hg<interval_nt>(
865 1025796 det2x2(p1.x,p1.w,p2.x,p2.w),
866 1025796 det2x2(p1.y,p1.w,p2.y,p2.w),
867 1025796 p1.w*p2.w
868 1025796 );
869 }
870
871
872 /**
873 * \brief Specialization of 3d homogeneous-coord vector difference
874 * for interval_nt coordinates
875 * \details We cannot check for p1.w and p2.w equality (since they
876 * might be in the same interval without being equal), so we always
877 * reduce to the same denominator.
878 */
879 70743 template <> inline vec3Hg<interval_nt> operator-(
880 const vec3Hg<interval_nt>& p1, const vec3Hg<interval_nt>& p2
881 ) {
882 return vec3Hg<interval_nt>(
883 70743 det2x2(p1.x,p1.w,p2.x,p2.w),
884 70743 det2x2(p1.y,p1.w,p2.y,p2.w),
885 70743 det2x2(p1.z,p1.w,p2.z,p2.w),
886 70743 p1.w * p2.w
887 70743 );
888 }
889 }
890
891 #endif
892