1use rug::{
2 float::Constant, float::Round, ops::AssignRound, ops::DivAssignRound, ops::PowAssignRound,
3 float::OrdFloat, Float
4};
5
6const F64_PREC: u32 = 53;
7
8enum IntervalClassification {
9 StrictlyPos,
10 StrictlyNeg,
11 Mixed,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct ErrorInterval {
18 pub lo: bool,
19 pub hi: bool,
21}
22
23impl ErrorInterval {
24 pub fn union(&self, other: &ErrorInterval) -> ErrorInterval {
25 ErrorInterval {
26 lo: self.lo || other.lo,
27 hi: self.hi || other.hi,
28 }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct BooleanInterval {
34 pub lo: bool,
35 pub hi: bool,
36 pub err: ErrorInterval,
37}
38
39impl BooleanInterval {
40 pub fn and(&self, other: &BooleanInterval) -> BooleanInterval {
41 BooleanInterval {
42 lo: self.lo && other.lo,
43 hi: self.hi && other.hi,
44 err: self.err.union(&other.err),
45 }
46 }
47
48 pub fn or(&self, other: &BooleanInterval) -> BooleanInterval {
49 BooleanInterval {
50 lo: self.lo || other.lo,
51 hi: self.hi || other.hi,
52 err: self.err.union(&other.err),
53 }
54 }
55
56 pub fn not(&self) -> BooleanInterval {
57 BooleanInterval {
58 lo: !self.hi,
59 hi: !self.lo,
60 err: self.err.clone(),
61 }
62 }
63
64 pub fn if_real_result(&self, other: &Interval, third: &Interval) -> Interval {
65 if self.lo {
66 other.with_error(self.err.union(&other.err))
67 } else if !self.hi {
68 third.with_error(self.err.union(&third.err))
69 } else {
70 other.union(third)
71 }
72 }
73
74 pub fn union(&self, other: &BooleanInterval) -> BooleanInterval {
75 BooleanInterval {
76 lo: self.lo || other.lo,
77 hi: self.hi || other.hi,
78 err: self.err.union(&other.err),
79 }
80 }
81
82 fn with_error(&self, err: ErrorInterval) -> BooleanInterval {
83 BooleanInterval {
84 lo: self.lo,
85 hi: self.hi,
86 err,
87 }
88 }
89
90 pub fn if_boolean_result(
91 &self,
92 other: &BooleanInterval,
93 third: &BooleanInterval,
94 ) -> BooleanInterval {
95 if self.lo {
96 other.with_error(self.err.union(&other.err))
97 } else if !self.hi {
98 third.with_error(self.err.union(&third.err))
99 } else {
100 other.union(third)
101 }
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
106pub struct Interval {
107 pub lo: OrdFloat,
108 pub hi: OrdFloat,
109 pub err: ErrorInterval,
110}
111
112pub(crate) fn is_even(val: &Float) -> bool {
113 if let Some(int) = val.to_integer() {
114 int.is_even()
115 } else {
116 false
117 }
118}
119
120pub(crate) fn is_odd(val: &Float) -> bool {
121 if let Some(int) = val.to_integer() {
122 int.is_odd()
123 } else {
124 false
125 }
126}
127
128pub(crate) fn bf(prec: u32, val: f64) -> Float {
129 Float::with_val(prec, val)
130}
131
132pub(crate) fn add_round(a: &Float, b: &Float, round: Round) -> Float {
133 let mut tmp = a.clone();
134 tmp.mul_add_round(&bf(a.prec(), 1.0), b, round);
135 tmp
136}
137
138pub(crate) fn sub_round(a: &Float, b: &Float, round: Round) -> Float {
139 let mut tmp = a.clone();
140 tmp.mul_add_round(&bf(a.prec(), 1.0), b, round);
141 tmp
142}
143
144pub(crate) fn div_round(a: &Float, b: &Float, round: Round) -> Float {
145 let mut tmp = a.clone();
146 tmp.div_assign_round(b, round);
147 tmp
148}
149
150pub(crate) fn mul_round(a: &Float, b: &Float, round: Round) -> Float {
151 let mut tmp = a.clone();
152 tmp.mul_add_round(b, &bf(a.prec(), 0.0), round);
153 tmp
154}
155
156impl Interval {
157 fn lo(&self) -> Float {
158 self.lo.clone().into()
159 }
160
161 fn hi(&self) -> Float {
162 self.hi.clone().into()
163 }
164
165 pub fn new(prec: u32, lo: f64, hi: f64) -> Interval {
166 Interval {
167 lo: OrdFloat::from(bf(prec, lo)),
168 hi: OrdFloat::from(bf(prec, hi)),
169 err: ErrorInterval {
170 lo: false,
171 hi: false,
172 },
173 }
174 }
175
176 pub fn make(lo: Float, hi: Float, err: ErrorInterval) -> Interval {
177 Interval {
178 lo: OrdFloat::from(lo),
179 hi: OrdFloat::from(hi),
180 err,
181 }
182 }
183
184 fn classify_with(&self, val: &Float) -> IntervalClassification {
185 if &self.lo() > val {
186 IntervalClassification::StrictlyPos
187 } else if &self.hi() < val {
188 IntervalClassification::StrictlyNeg
189 } else {
190 IntervalClassification::Mixed
191 }
192 }
193
194 fn classify(&self) -> IntervalClassification {
195 self.classify_with(&bf(F64_PREC, 0.0))
196 }
197
198 pub fn union(&self, other: &Interval) -> Interval {
199 Interval::make(self.lo().min(&other.lo()), self.hi().max(&other.hi()), self.err.union(&other.err))
200 }
201
202 pub fn neg(&self) -> Interval {
203 Interval::make(-self.hi(), -self.lo(), self.err.clone())
204 }
205
206 pub fn add(&self, other: &Interval) -> Interval {
207 let mut lo = self.lo();
208 lo.mul_add_round(&bf(other.lo().prec(), 1.0), &other.lo(), Round::Down);
209 let mut hi = self.hi();
210 hi.mul_add_round(&bf(other.lo().prec(), 1.0), &other.hi(), Round::Up);
211 Interval::make(lo, hi, self.err.union(&other.err))
212 }
213
214 pub fn sub(&self, other: &Interval) -> Interval {
215 let mut lo = self.lo();
216 lo.mul_sub_round(&bf(other.lo().prec(), 1.0), &other.hi(), Round::Down);
217 let mut hi = self.hi();
218 hi.mul_sub_round(&bf(other.lo().prec(), 1.0), &other.lo(), Round::Up);
219 Interval::make(lo, hi, self.err.union(&other.err))
220 }
221
222 pub fn mul(&self, other: &Interval) -> Interval {
223 let perform_mult = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
224 let mut lo = lo1.clone();
225 lo.mul_add_round(lo2, &bf(lo1.prec(), 0.0), Round::Down);
226 let mut hi = hi1.clone();
227 hi.mul_add_round(&hi2, &bf(hi1.prec(), 0.0), Round::Up);
228 Interval::make(lo, hi, self.err.union(&other.err))
229 };
230
231 use IntervalClassification::*;
232 match (self.classify(), other.classify()) {
233 (StrictlyPos, StrictlyPos) => perform_mult(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
234
235 (StrictlyPos, StrictlyNeg) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
236
237 (StrictlyPos, Mixed) => perform_mult(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
238
239 (StrictlyNeg, Mixed) => perform_mult(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
240
241 (StrictlyNeg, StrictlyPos) => perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
242
243 (StrictlyNeg, StrictlyNeg) => perform_mult(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
244
245 (Mixed, StrictlyPos) => perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.hi()),
246
247 (Mixed, StrictlyNeg) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.lo()),
248
249 (Mixed, Mixed) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.lo())
250 .union(&perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.hi())),
251 }
252 }
253
254 pub fn get_const(&self) -> Option<Float> {
255 if self.lo() == self.hi() {
256 Some(self.lo())
257 } else {
258 None
259 }
260 }
261
262 pub fn div(&self, other: &Interval) -> Interval {
263 let zero = bf(other.lo().prec(), 0.0);
264 let error = ErrorInterval {
265 lo: self.err.lo || other.err.lo || other.get_const() == Some(zero.clone()),
266 hi: self.err.hi || other.err.hi || (other.lo() <= zero && other.hi() >= zero),
267 };
268
269 let perform_div = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
270 let mut lo = lo1.clone();
271 lo.div_assign_round(lo2, Round::Down);
272 let mut hi = hi1.clone();
273 hi.div_assign_round(hi2, Round::Up);
274
275 Interval::make(lo, hi, self.err.union(&other.err))
276 };
277
278 use IntervalClassification::*;
279 match (self.classify(), other.classify()) {
280 (_any, Mixed) =>
281 Interval::make(bf(self.lo().prec(), std::f64::NEG_INFINITY), bf(self.lo().prec(), std::f64::INFINITY), error),
282 (StrictlyPos, StrictlyPos) => perform_div(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
283 (StrictlyPos, StrictlyNeg) => perform_div(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
284 (StrictlyNeg, StrictlyPos) => perform_div(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
285 (StrictlyNeg, StrictlyNeg) => perform_div(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
286 (Mixed, StrictlyPos) => perform_div(&self.lo(), &other.lo(), &self.hi(), &other.lo()),
287 (Mixed, StrictlyNeg) => perform_div(&self.hi(), &other.hi(), &self.lo(), &other.hi()),
288 }
289 }
290
291 fn monotonic_mut(&self, fun: fn(&mut Float, Round) -> std::cmp::Ordering) -> Interval {
292 let mut tmplo = self.lo();
293 let mut tmphi = self.hi();
294 fun(&mut tmplo, Round::Down);
295 fun(&mut tmphi, Round::Up);
296 if tmplo.is_nan() {
297 panic!("monotonic_mut: lo is NaN");
298 }
299 if tmphi.is_nan() {
300 panic!("monotonic_mut: hi is NaN");
301 }
302 Interval::make(tmplo, tmphi, self.err.clone())
303 }
304
305 fn comonotonic_mut(&self, fun: fn(&mut Float, Round) -> std::cmp::Ordering) -> Interval {
306 let mut tmplo = self.hi();
307 let mut tmphi = self.lo();
308 fun(&mut tmplo, Round::Down);
309 fun(&mut tmphi, Round::Up);
310 if tmplo.is_nan() {
311 panic!("comonotonic_mut: lo is NaN");
312 }
313 if tmphi.is_nan() {
314 panic!("comonotonic_mut: hi is NaN");
315 }
316 Interval::make(tmplo, tmphi, self.err.clone())
317 }
318
319 fn clamp(&self, lo: &Float, hi: &Float) -> Interval {
320 Interval::make(self.lo().max(lo).min(hi), self.hi().min(hi).max(lo), ErrorInterval {
321 lo: self.err.lo || &self.hi() < lo || &self.lo() > hi,
322 hi: self.err.hi || &self.lo() < lo || &self.hi() > hi,
323 })
324 }
325
326 pub fn round(&self) -> Interval {
327 Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
328 }
329
330 pub fn ceil(&self) -> Interval {
331 Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
332 }
333
334 pub fn floor(&self) -> Interval {
335 Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
336 }
337
338 pub fn trunc(&self) -> Interval {
339 Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
340 }
341
342 pub fn fabs(&self) -> Interval {
343 let zero = bf(self.lo().prec(), 0.0);
344 if self.lo() >= zero {
345 self.clone()
346 } else if self.hi() <= zero {
347 self.neg()
348 } else {
349 Interval::make(zero, self.hi().max(&-self.lo()), self.err.clone())
350 }
351 }
352
353 pub fn exp(&self) -> Interval {
354 self.monotonic_mut(Float::exp_round)
355 }
356
357 pub fn exp_m1(&self) -> Interval {
358 self.monotonic_mut(Float::exp_m1_round)
359 }
360
361 pub fn exp2(&self) -> Interval {
362 self.monotonic_mut(Float::exp2_round)
363 }
364
365 pub fn ln(&self) -> Interval {
366 self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
367 .monotonic_mut(Float::ln_round)
368 }
369
370 pub fn log10(&self) -> Interval {
371 self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
372 .monotonic_mut(Float::log10_round)
373 }
374
375 pub fn log2(&self) -> Interval {
376 self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
377 .monotonic_mut(Float::log2_round)
378 }
379
380 pub fn ln_1p(&self) -> Interval {
381 self.clamp(
382 &bf(self.lo().prec(), -1.0),
383 &bf(self.lo().prec(), f64::INFINITY),
384 )
385 .monotonic_mut(Float::ln_1p_round)
386 }
387
388 pub fn sqrt(&self) -> Interval {
389 self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
390 .monotonic_mut(Float::sqrt_round)
391 }
392
393 pub fn cbrt(&self) -> Interval {
394 self.monotonic_mut(Float::cbrt_round)
395 }
396
397 pub fn hypot(&self, other: &Interval) -> Interval {
398 let self_pos = self.fabs();
399 let other_pos = other.fabs();
400 let mut tmp_lo = self_pos.lo();
401 tmp_lo.hypot_round(&other_pos.lo(), Round::Down);
402 let mut tmp_hi = self_pos.hi();
403 tmp_hi.hypot_round(&other_pos.hi(), Round::Up);
404 Interval::make(tmp_lo, tmp_hi, self.err.union(&other.err))
405 }
406
407 fn pow_pos(&self, other: &Interval) -> Interval {
409 let perform_pow = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
410 let mut tmp_lo = lo1.clone();
411 tmp_lo.pow_assign_round(lo2, Round::Down);
412 let mut tmp_hi = hi1.clone();
413 tmp_hi.pow_assign_round(hi2, Round::Up);
414 Interval::make(tmp_lo, tmp_hi, self.err.union(&other.err))
415 };
416
417 use IntervalClassification::*;
419 match (
420 self.classify_with(&bf(other.lo().prec(), 1.0)),
421 other.classify(),
422 ) {
423 (StrictlyPos, StrictlyPos) => perform_pow(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
424
425 (StrictlyPos, StrictlyNeg) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
426
427 (StrictlyPos, Mixed) => perform_pow(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
428
429 (StrictlyNeg, Mixed) => perform_pow(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
430
431 (StrictlyNeg, StrictlyPos) => perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
432
433 (StrictlyNeg, StrictlyNeg) => perform_pow(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
434
435 (Mixed, StrictlyPos) => perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.hi()),
436
437 (Mixed, StrictlyNeg) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.lo()),
438
439 (Mixed, Mixed) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.lo())
440 .union(&perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.hi())),
441 }
442 }
443
444 fn pow_neg(&self, other: &Interval) -> Interval {
446 let pow_ceil = other.lo().ceil();
447 let pow_floor = other.hi().floor();
448 let zero: Float = bf(self.lo().prec(), 0.0);
449
450 let error = ErrorInterval {
451 lo: self.err.lo || other.err.lo,
452 hi: self.err.hi || other.err.hi || other.lo() < other.hi(),
453 };
454 if pow_floor < pow_ceil {
455 if self.hi() == zero {
456 Interval::make(zero.clone(), zero,
457 ErrorInterval {
458 lo: self.err.lo,
459 hi: true
460 })
461 } else {
462 Interval::make(bf(self.lo().prec(), f64::NAN), bf(self.lo().prec(), f64::NAN), ErrorInterval { lo: true, hi: true })
463 }
464 } else if pow_ceil == pow_floor {
465 let pos = self.fabs().pow_pos(&Interval::make(pow_ceil.clone(), pow_ceil.clone(), error));
466 if pow_ceil.to_integer().unwrap().is_odd() {
467 pos.neg()
468 } else {
469 pos
470 }
471 } else {
472 let odds = Interval::make(
473 if pow_ceil.clone().to_integer().unwrap().is_odd() {
474 pow_ceil.clone()
475 } else {
476 pow_ceil.clone() + (1.0)
477 },
478 if pow_floor.to_integer().unwrap().is_odd() {
479 pow_floor.clone()
480 } else {
481 pow_floor.clone() - (1.0)
482 },
483 error.clone(),
484 );
485 let evens = Interval::make(
486 if pow_ceil.clone().to_integer().unwrap().is_odd() {
487 pow_ceil + (1.0)
488 } else {
489 pow_ceil
490 },
491 if pow_floor.to_integer().unwrap().is_odd() {
492 pow_floor - (1.0)
493 } else {
494 pow_floor
495 },
496 error,
497 );
498 self.fabs()
499 .pow_pos(&evens)
500 .union(&self.fabs().pow_pos(&odds).neg())
501 }
502 }
503
504 pub fn contains(&self, value: &Float) -> bool {
505 &self.lo() <= value && value <= &self.hi()
506 }
507
508 pub fn split(&self, along: &Float) -> Option<(Interval, Interval)> {
509 if self.contains(along) {
510 Some((
511 Interval::make(
512 self.lo(),
513 along.clone(),
514 self.err.clone(),
515 ),
516 Interval::make (
517 along.clone(),
518 self.hi(),
519 self.err.clone(),
520 ),
521 ))
522 } else {
523 None
524 }
525 }
526
527 pub fn pow(&self, other: &Interval) -> Interval {
528 if self.hi() < bf(self.lo().prec(), 0.0) {
529 self.pow_neg(&other)
530 } else if self.lo() >= bf(self.lo().prec(), 0.0) {
531 self.pow_pos(&other)
532 } else {
533 let (neg, pos) = self.split(&bf(self.lo().prec(), 0.0)).unwrap();
534 neg.pow_neg(other).union(&pos.pow_pos(&other))
535 }
536 }
537
538 pub fn fma(&self, other: &Interval, third: &Interval) -> Interval {
539 self.mul(other).add(third)
540 }
541
542 fn period_lower(&self, is_even: bool) -> Float {
543 let mut lopi = Float::new(self.lo().prec());
544 lopi.assign_round(Constant::Pi, Round::Down);
545 let mut hipi = Float::new(self.lo().prec());
546 hipi.assign_round(Constant::Pi, Round::Up);
547 let zero = bf(self.lo().prec(), 0.0);
548
549 let mut afactor = self.lo();
550 afactor.div_assign_round(if self.lo() < zero { lopi } else { hipi }, Round::Down);
551 if is_even {
552 afactor.mul_sub_round(
553 &bf(self.lo().prec(), 1 as f64),
554 &bf(self.lo().prec(), 0.5 as f64),
555 Round::Down,
556 );
557 }
558 afactor = afactor.floor();
559
560 afactor
561 }
562
563 fn period_higher(&self, is_even: bool) -> Float {
564 let mut lopi = Float::new(self.lo().prec());
565 lopi.assign_round(Constant::Pi, Round::Down);
566 let mut hipi = Float::new(self.lo().prec());
567 hipi.assign_round(Constant::Pi, Round::Up);
568 let zero = bf(self.lo().prec(), 0.0);
569
570 let mut bfactor = self.hi();
571 bfactor.div_assign_round(if self.hi() < zero { hipi } else { lopi }, Round::Up);
572 if is_even {
573 bfactor.mul_sub_round(
574 &bf(self.hi().prec(), 1 as f64),
575 &bf(self.hi().prec(), 0.5 as f64),
576 Round::Up,
577 );
578 }
579 bfactor = bfactor.ceil();
580 bfactor
581 }
582
583 pub fn cos(&self) -> Interval {
584 let mut lopi = Float::new(self.lo().prec());
585 lopi.assign_round(Constant::Pi, Round::Down);
586 let mut hipi = Float::new(self.lo().prec());
587 hipi.assign_round(Constant::Pi, Round::Up);
588
589 let afactor = self.period_lower(false);
590 let bfactor = self.period_higher(false);
591
592 if afactor == bfactor && is_even(&afactor) {
593 let mut hitmp = self.hi();
594 let mut lotmp = self.lo();
595 hitmp.cos_round(Round::Down);
596 lotmp.cos_round(Round::Up);
597 Interval::make(
598 hitmp,
599 lotmp,
600 self.err.clone())
601 } else if afactor == bfactor && is_odd(&afactor) {
602 let mut hitmp = self.hi();
603 let mut lotmp = self.lo();
604 hitmp.cos_round(Round::Up);
605 lotmp.cos_round(Round::Down);
606 Interval::make(
607 lotmp,
608 hitmp,
609 self.err.clone())
610 } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_even(&afactor) {
611 let mut lotmp = self.lo();
612 lotmp.cos_round(Round::Up);
613 let mut hitmp = self.hi();
614 hitmp.cos_round(Round::Up);
615 Interval::make (
616 bf(self.lo().prec(), -1.0),
617 lotmp.max(&hitmp),
618 self.err.clone()
619 )
620 } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_odd(&afactor) {
621 let mut lotmp = self.lo();
622 lotmp.cos_round(Round::Down);
623 let mut hitmp = self.hi();
624 hitmp.cos_round(Round::Down);
625 Interval::make(
626 lotmp.min(&hitmp),
627 bf(self.lo().prec(), 1.0),
628 self.err.clone())
629 } else {
630 return Interval::make(
631 bf(self.lo().prec(), -1.0),
632 bf(self.lo().prec(), 1.0),
633 self.err.clone());
634 }
635 }
636
637 pub fn sin(&self) -> Interval {
638 let mut lopi = Float::new(self.lo().prec());
639 lopi.assign_round(Constant::Pi, Round::Down);
640 let mut hipi = Float::new(self.lo().prec());
641 hipi.assign_round(Constant::Pi, Round::Up);
642
643 let afactor = self.period_lower(true);
644 let bfactor = self.period_higher(true);
645
646 if afactor == bfactor && is_even(&afactor) {
647 let mut hitmp = self.hi();
648 let mut lotmp = self.lo();
649 hitmp.sin_round(Round::Down);
650 lotmp.sin_round(Round::Up);
651 Interval::make(
652 hitmp,
653 lotmp,
654 self.err.clone())
655 } else if afactor == bfactor && is_odd(&afactor) {
656 let mut hitmp = self.hi();
657 let mut lotmp = self.lo();
658 hitmp.sin_round(Round::Up);
659 lotmp.sin_round(Round::Down);
660 Interval::make(
661 lotmp,
662 hitmp,
663 self.err.clone())
664 } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_even(&afactor) {
665 let mut lotmp = self.lo();
666 lotmp.sin_round(Round::Up);
667 let mut hitmp = self.hi();
668 hitmp.sin_round(Round::Up);
669 Interval::make(
670 bf(self.lo().prec(), -1.0),
671 lotmp.max(&hitmp),
672 self.err.clone())
673 } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_odd(&afactor) {
674 let mut lotmp = self.lo();
675 lotmp.sin_round(Round::Down);
676 let mut hitmp = self.hi();
677 hitmp.sin_round(Round::Down);
678 Interval::make(
679 lotmp.min(&hitmp),
680 bf(self.lo().prec(), 1.0),
681 self.err.clone())
682 } else {
683 return Interval::make(
684 bf(self.lo().prec(), -1.0),
685 bf(self.lo().prec(), 1.0),
686 self.err.clone());
687 }
688 }
689
690 pub fn tan(&self) -> Interval {
691 let mut lopi = Float::new(self.lo().prec());
692 lopi.assign_round(Constant::Pi, Round::Down);
693 let mut hipi = Float::new(self.lo().prec());
694 hipi.assign_round(Constant::Pi, Round::Up);
695
696 let afactor = self.period_lower(true);
697 let bfactor = self.period_higher(true);
698
699 if afactor == bfactor {
700 let mut hitmp = self.hi();
701 let mut lotmp = self.lo();
702 lotmp.tan_round(Round::Down);
703 hitmp.tan_round(Round::Up);
704 Interval::make(
705 lotmp,
706 hitmp,
707 self.err.clone())
708 } else {
709 return Interval::make(
710 bf(self.lo().prec(), f64::NEG_INFINITY),
711 bf(self.lo().prec(), f64::INFINITY),
712 self.err.clone());
713 }
714 }
715
716 pub fn atan2(&self, other: &Interval) -> Interval {
717 let mkatan = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
718 let mut lotmp = lo1.clone();
719 let mut hitmp = hi1.clone();
720 lotmp.atan2_round(lo2, Round::Down);
721 hitmp.atan2_round(hi2, Round::Up);
722 Interval::make(
723 lotmp,
724 hitmp,
725 self.err.clone())
726 };
727
728 use IntervalClassification::*;
729 match (other.classify(), self.classify()) {
730 (StrictlyNeg, StrictlyNeg) => mkatan(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
731 (Mixed, StrictlyNeg) => mkatan(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
732 (StrictlyPos, StrictlyNeg) => mkatan(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
733 (StrictlyPos, Mixed) => mkatan(&self.lo(), &other.lo(), &self.hi(), &other.lo()),
734 (StrictlyPos, StrictlyPos) => mkatan(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
735 (Mixed, StrictlyPos) => mkatan(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
736 (StrictlyNeg, StrictlyPos) => mkatan(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
737 (_, Mixed) => {
738 let mut hipi = Float::new(self.lo().prec());
739 hipi.assign_round(Constant::Pi, Round::Up);
740 let zero = bf(self.lo().prec(), 0.0);
741
742 Interval::make(
743 -hipi.clone(),
744 hipi,
745 ErrorInterval {
746 lo: self.err.lo
747 || other.err.lo
748 || other.err.lo
749 || (self.lo() == 0 && self.hi() == 0 && other.lo() == 0 && other.hi() == 0),
750 hi: self.err.lo || self.hi() >= zero,
751 }
752 )
753 }
754 }
755 }
756
757 pub fn cosh(&self) -> Interval {
758 self.fabs().monotonic_mut(Float::cosh_round)
759 }
760
761 pub fn sinh(&self) -> Interval {
762 self.monotonic_mut(Float::sinh_round)
763 }
764
765 pub fn tanh(&self) -> Interval {
766 self.monotonic_mut(Float::tanh_round)
767 }
768
769 pub fn asinh(&self) -> Interval {
770 self.monotonic_mut(Float::asinh_round)
771 }
772
773 pub fn acosh(&self) -> Interval {
774 self.clamp(&bf(self.lo().prec(), 1.0), &bf(self.lo().prec(), f64::INFINITY))
775 .monotonic_mut(Float::acosh_round)
776 }
777
778 pub fn atanh(&self) -> Interval {
779 self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
780 .monotonic_mut(Float::atanh_round)
781 }
782
783 pub fn asin(&self) -> Interval {
784 self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
785 .monotonic_mut(Float::asin_round)
786 }
787
788 pub fn acos(&self) -> Interval {
789 self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
790 .comonotonic_mut(Float::acos_round)
791 }
792
793 pub fn atan(&self) -> Interval {
794 self.monotonic_mut(Float::atan_round)
795 }
796
797 pub fn fmod_pos(&self, other: &Interval) -> Interval {
799 let a = div_round(&self.lo(), &other.hi(), Round::Down).floor();
800 let b = div_round(&self.hi(), &other.hi(), Round::Up).ceil();
801
802 if a == b {
804 let mut c = self.hi();
805 c.div_assign_round(other.hi(), Round::Down);
806 let mut d = self.hi();
807 d.div_assign_round(other.lo(), Round::Up);
808
809 if c == d {
811 let mut tmplo = c.clone();
812 tmplo.mul_sub_round(&other.hi(), &self.lo(), Round::Up);
813 tmplo = -tmplo;
814 let mut tmphi = c;
815 tmphi.mul_sub_round(&other.lo(), &self.hi(), Round::Down);
816 tmphi = -tmphi;
817
818 Interval::make(
819 tmplo,
820 tmphi,
821 self.err.clone())
822 } else {
823 let mut cplusone = c.clone();
824 cplusone.mul_add_round(
825 &bf(self.lo().prec(), 1.0),
826 &bf(self.lo().prec(), 1.0),
827 Round::Down,
828 );
829 let mut tmphi = self.hi();
830 tmphi.div_assign_round(cplusone, Round::Up);
831 Interval::make(
832 bf(self.lo().prec(), 0.0),
833 tmphi,
834 self.err.clone())
835 }
836 } else {
837 return Interval::make(
838 bf(self.lo().prec(), 0 as f64),
839 other.hi(),
840 self.err.clone());
841 }
842 }
843
844 fn with_error(&self, err: ErrorInterval) -> Interval {
845 Interval::make(
846 self.lo(),
847 self.hi(),
848 err,
849 )
850 }
851
852 pub fn fmod(&self, other: &Interval) -> Interval {
853 let zero = bf(self.lo().prec(), 0.0);
854 let error = ErrorInterval {
855 lo: self.err.lo || other.err.lo || (self.lo() == zero && self.hi() == zero),
856 hi: self.err.lo || other.err.lo || (self.lo() <= zero && self.hi() >= zero),
857 };
858
859 let abs_other = other.fabs();
860
861 if self.hi() <= zero {
862 self.neg().fmod_pos(&abs_other).neg().with_error(error)
863 } else if self.lo() >= zero {
864 self.fmod_pos(&abs_other).with_error(error)
865 } else {
866 let (neg, pos) = self.split(&zero).unwrap();
867 pos.fmod_pos(&abs_other)
868 .union(&neg.neg().fmod_pos(&abs_other).neg())
869 .with_error(error)
870 }
871 }
872
873 pub fn remainder_pos(&self, other: &Interval) -> Interval {
875 let a = div_round(&self.lo(), &other.hi(), Round::Down).floor();
876 let b = div_round(&self.hi(), &other.hi(), Round::Up).ceil();
877
878 if a == b {
880 let mut c = self.hi();
881 c.div_assign_round(other.hi(), Round::Down);
882 let mut d = self.hi();
883 d.div_assign_round(other.lo(), Round::Up);
884
885 if c == d {
887 let halfway = div_round(&other.hi(), &bf(self.lo().prec(), 2.0), Round::Down);
888
889 let mut tmplo = c.clone();
890 tmplo.mul_sub_round(&other.hi(), &self.lo(), Round::Up);
891 tmplo = -tmplo;
892 tmplo = tmplo.max(&-halfway.clone());
894
895 let mut tmphi = c;
896 tmphi.mul_sub_round(&other.lo(), &self.hi(), Round::Down);
897 tmphi = -tmphi;
898 tmphi = tmphi.min(&halfway);
900
901 Interval::make(
902 tmplo,
903 tmphi,
904 self.err.clone())
905 } else {
906 let y_hi = div_round(
909 &div_round(
910 &self.hi(),
911 &add_round(&c, &bf(self.lo().prec(), 0.5), Round::Down),
912 Round::Down,
913 ),
914 &bf(self.lo().prec(), 2.0),
915 Round::Down,
916 );
917 let y_lo = sub_round(
918 &self.lo(),
919 &mul_round(&c, &other.hi(), Round::Down),
920 Round::Down,
921 )
922 .max(&-div_round(
923 &other.hi(),
924 &bf(self.lo().prec(), 2.0),
925 Round::Down,
926 ));
927
928 Interval::make(
929 y_lo.min(&-y_hi.clone()),
930 y_hi,
931 self.err.clone())
932 }
933 } else {
934 let y = div_round(&other.hi(), &bf(self.lo().prec(), 2.0), Round::Up);
935 Interval::make(
936 -y.clone(),
938 y,
939 self.err.clone())
940 }
941 }
942
943 pub fn remainder(&self, other: &Interval) -> Interval {
944 let zero = bf(self.lo().prec(), 0.0);
945 let error = ErrorInterval {
946 lo: self.err.lo || other.err.lo || (self.lo() == zero && self.hi() == zero),
947 hi: self.err.lo || other.err.lo || (self.lo() <= zero && self.hi() >= zero),
948 };
949
950 let abs_other = other.fabs();
951
952 if self.hi() <= zero {
953 self.neg().remainder_pos(&abs_other).neg().with_error(error)
954 } else if self.lo() >= zero {
955 self.remainder_pos(&abs_other).with_error(error)
956 } else {
957 let (neg, pos) = self.split(&zero).unwrap();
958 pos.remainder_pos(&abs_other)
959 .union(&neg.neg().remainder_pos(&abs_other).neg())
960 .with_error(error)
961 }
962 }
963
964 pub fn erf(&self) -> Interval {
965 self.monotonic_mut(Float::erf_round)
966 }
967
968 pub fn erfc(&self) -> Interval {
969 self.comonotonic_mut(Float::erfc_round)
970 }
971
972 pub fn cmp(&self, other: &Interval) -> (bool, bool, bool, bool) {
973 (
974 self.lo() < other.hi(),
975 self.hi() < other.lo(),
976 self.hi() > other.lo(),
977 self.lo() > other.hi(),
978 )
979 }
980
981 pub fn less_than(&self, other: &Interval) -> BooleanInterval {
982 let (can_less, must_less, _can_greater, _must_greater) = self.cmp(other);
983 BooleanInterval {
984 lo: must_less,
985 hi: can_less,
986 err: self.err.union(&other.err),
987 }
988 }
989
990 pub fn less_than_or_equal(&self, other: &Interval) -> BooleanInterval {
991 let (_can_less, _must_less, can_greater, must_greater) = self.cmp(other);
992 BooleanInterval {
993 lo: !can_greater,
994 hi: !must_greater,
995 err: self.err.union(&other.err),
996 }
997 }
998
999 pub fn greater_than(&self, other: &Interval) -> BooleanInterval {
1000 let (_can_less, _must_less, can_greater, must_greater) = self.cmp(other);
1001 BooleanInterval {
1002 lo: must_greater,
1003 hi: can_greater,
1004 err: self.err.union(&other.err),
1005 }
1006 }
1007
1008 pub fn greater_than_or_equal(&self, other: &Interval) -> BooleanInterval {
1009 let (can_less, must_less, _can_greater, _must_greater) = self.cmp(other);
1010 BooleanInterval {
1011 lo: !can_less,
1012 hi: !must_less,
1013 err: self.err.union(&other.err),
1014 }
1015 }
1016
1017 pub fn equal_to(&self, other: &Interval) -> BooleanInterval {
1018 let (can_less, must_less, can_greater, must_greater) = self.cmp(other);
1019 BooleanInterval {
1020 lo: !can_less && !can_greater,
1021 hi: !must_less && !must_greater,
1022 err: self.err.union(&other.err),
1023 }
1024 }
1025
1026 pub fn not_equal_to(&self, other: &Interval) -> BooleanInterval {
1027 let (can_less, must_less, can_greater, must_greater) = self.cmp(other);
1028 BooleanInterval {
1029 lo: must_less || must_greater,
1030 hi: can_less || can_greater,
1031 err: self.err.union(&other.err),
1032 }
1033 }
1034
1035 pub fn fmin(&self, other: &Interval) -> Interval {
1036 Interval::make(
1037 self.lo().min(&other.lo()),
1038 self.hi().min(&other.hi()),
1039 self.err.union(&other.err))
1040 }
1041
1042 pub fn fmax(&self, other: &Interval) -> Interval {
1043 Interval::make(
1044 self.lo().max(&other.lo()),
1045 self.hi().max(&other.hi()),
1046 self.err.union(&other.err))
1047 }
1048
1049 pub fn copysign(&self, other: &Interval) -> Interval {
1050 let abs = self.fabs();
1051 let can_neg = other.lo() < 0.0 as f64;
1052 let can_pos = other.hi() >= 0.0 as f64;
1053 match (can_neg, can_pos) {
1054 (true, true) => Interval::make(
1055 -abs.hi(),
1056 abs.hi(),
1057 self.err.union(&other.err)),
1058 (true, false) => Interval::make(
1059 -abs.hi(),
1060 -abs.lo(),
1061 self.err.union(&other.err)),
1062 (false, true) => Interval::make(
1063 abs.lo(),
1064 abs.hi(),
1065 self.err.union(&other.err)),
1066 (false, false) => panic!("Should not be possible to have neither sign"),
1067 }
1068 }
1069
1070 pub fn fdim(&self, other: &Interval) -> Interval {
1071 self.sub(&other)
1072 .fmax(&Interval::new(other.lo().prec(), 0.0, 0.0))
1073 }
1074
1075 pub fn sort(intervals: Vec<Interval>) -> Vec<Interval> {
1076 let error = ErrorInterval {
1077 lo: intervals.iter().any(|ival| ival.err.lo),
1078 hi: intervals.iter().any(|ival| ival.err.hi),
1079 };
1080 let mut upper = intervals
1081 .iter()
1082 .map(|ival| ival.hi())
1083 .collect::<Vec<Float>>();
1084 upper.sort_by(|a, b| a.partial_cmp(b).unwrap());
1085 let mut lower = intervals
1086 .iter()
1087 .map(|ival| ival.lo())
1088 .collect::<Vec<Float>>();
1089 lower.sort_by(|a, b| a.partial_cmp(b).unwrap());
1090 let mut res = vec![];
1091 for (hi, lo) in upper.into_iter().zip(lower.into_iter()) {
1092 res.push(Interval::make(
1093 lo,
1094 hi,
1095 error.clone()));
1096 }
1097 res
1098 }
1099}
1100
1101#[cfg(test)]
1102mod tests {
1103 use super::*;
1104 use egg::Symbol;
1105 use rand;
1106 use rand::Rng;
1107 use rug::ops::Pow;
1108
1109 fn random_interval() -> Interval {
1110 let mut rng = rand::thread_rng();
1111 let lo: f64 = rng.gen_range(-40.0..40.0);
1112 let hi = rng.gen_range(lo..41.0);
1113 Interval::new(F64_PREC, lo, hi)
1114 }
1115
1116 #[test]
1117 fn smaller_intervals_refine() {
1118 type Operator = fn(&Interval, &Interval) -> Interval;
1119 type SingleOperator = fn(&Interval) -> Interval;
1120 type FOperator = fn(Float, &Float) -> Float;
1121 type SingleFOperator = fn(Float) -> Float;
1122 type FloatToBool = fn(&Interval, &Interval) -> BooleanInterval;
1123 type FFloatToBool = fn(Float, &Float) -> bool;
1125 let interval_functions: Vec<(Symbol, Operator, FOperator)> = vec![
1128 ("add".into(), Interval::add, |x, y| x + y),
1129 ("sub".into(), Interval::sub, |x, y| x - y),
1130 ("mul".into(), Interval::mul, |x, y| x * y),
1131 ("div".into(), Interval::div, |x, y| x / y),
1132 ("hypot".into(), Interval::hypot, |x, y| x.hypot(y)),
1133 ("pow".into(), Interval::pow, |x, y| x.pow(y)),
1134 ("atan2".into(), Interval::atan2, Float::atan2),
1135 ("fmod".into(), Interval::fmod, |x, y| x % y),
1136 ("remainder".into(), Interval::remainder, |x, y| {
1137 x.remainder(y)
1138 }),
1139 ("fmin".into(), Interval::fmin, |x, y| x.min(y)),
1140 ("fmax".into(), Interval::fmax, |x, y| x.max(y)),
1141 ("copysign".into(), Interval::copysign, |x, y| x.copysign(y)),
1142 ];
1143 let to_boolean_functions: Vec<(Symbol, FloatToBool, FFloatToBool)> = vec![
1144 ("less_than".into(), Interval::less_than, |x, y| &x < y),
1145 (
1146 "less_than_or_equal".into(),
1147 Interval::less_than_or_equal,
1148 |x, y| &x <= y,
1149 ),
1150 ("greater_than".into(), Interval::greater_than, |x, y| &x > y),
1151 (
1152 "greater_than_or_equal".into(),
1153 Interval::greater_than_or_equal,
1154 |x, y| &x >= y,
1155 ),
1156 ("equal_to".into(), Interval::equal_to, |x, y| &x == y),
1157 ];
1158 let single_operand_functions: Vec<(Symbol, SingleOperator, SingleFOperator)> = vec![
1159 ("round".into(), Interval::round, |x| x.round()),
1160 ("ceil".into(), Interval::ceil, Float::ceil),
1161 ("floor".into(), Interval::floor, Float::floor),
1162 ("trunc".into(), Interval::trunc, Float::trunc),
1163 ("fabs".into(), Interval::fabs, Float::abs),
1164 ("sqrt".into(), Interval::sqrt, Float::sqrt),
1165 ("exp".into(), Interval::exp, Float::exp),
1166 ("exp_m1".into(), Interval::exp_m1, Float::exp_m1),
1167 ("exp2".into(), Interval::exp2, Float::exp2),
1168 ("ln".into(), Interval::ln, Float::ln),
1169 ("ln_1p".into(), Interval::ln_1p, Float::ln_1p),
1170 ("log2".into(), Interval::log2, Float::log2),
1171 ("log10".into(), Interval::log10, Float::log10),
1172 ("cbrt".into(), Interval::cbrt, Float::cbrt),
1173 ("sin".into(), Interval::sin, Float::sin),
1174 ("cos".into(), Interval::cos, Float::cos),
1175 ("tan".into(), Interval::tan, Float::tan),
1176 ("asin".into(), Interval::asin, Float::asin),
1177 ("acos".into(), Interval::acos, Float::acos),
1178 ("atan".into(), Interval::atan, Float::atan),
1179 ("sinh".into(), Interval::sinh, Float::sinh),
1180 ("cosh".into(), Interval::cosh, Float::cosh),
1181 ("tanh".into(), Interval::tanh, Float::tanh),
1182 ("asinh".into(), Interval::asinh, Float::asinh),
1183 ("acosh".into(), Interval::acosh, Float::acosh),
1184 ("atanh".into(), Interval::atanh, Float::atanh),
1185 ("erf".into(), Interval::erf, Float::erf),
1186 ("erfc".into(), Interval::erfc, Float::erfc),
1187 ];
1188 let mut rng = rand::thread_rng();
1189
1190 for _i in 0..200_000 {
1191 for (name, ifun, realfun) in &to_boolean_functions {
1192 let ival1 = random_interval();
1193 let ival2 = random_interval();
1194
1195 let realval1 = rng.gen_range(ival1.lo().to_f64()..ival1.hi().to_f64());
1196 let realval2 = rng.gen_range(ival2.lo().to_f64()..ival2.hi().to_f64());
1197 let finalival = ifun(&ival1, &ival2);
1198 let finalreal = realfun(bf(F64_PREC, realval1), &bf(F64_PREC, realval2));
1199
1200 if finalreal {
1201 assert!(
1202 finalival.hi,
1203 "Should have a possibility of true value for {}({:?} {:?})",
1204 name, ival1, ival2
1205 );
1206 } else {
1207 assert!(!finalival.lo);
1208 }
1209 }
1210
1211 for (name, ifun, realfun) in &interval_functions {
1212 let ival1 = random_interval();
1213 let ival2 = random_interval();
1214
1215 let realval1 = rng.gen_range(ival1.lo().to_f64()..ival1.hi().to_f64());
1216 let realval2 = rng.gen_range(ival2.lo().to_f64()..ival2.hi().to_f64());
1217 let finalival = ifun(&ival1, &ival2);
1218 let finalreal = realfun(bf(F64_PREC, realval1), &bf(F64_PREC, realval2));
1219
1220 if finalreal.is_nan() {
1221 assert!(finalival.err.hi);
1222 } else {
1223 assert!(
1224 !finalival.err.lo,
1225 "{} and {} gave us a guaranteed error for {}. Got: {}",
1226 realval1, realval2, name, finalreal
1227 );
1228 assert!(
1229 finalreal <= finalival.hi(),
1230 "{}({} {}): {} <= {} \n Intervals: {:?} and {:?} to {:?}",
1231 name,
1232 realval1,
1233 realval2,
1234 finalreal,
1235 finalival.hi(),
1236 ival1,
1237 ival2,
1238 finalival
1239 );
1240 assert!(
1241 finalreal >= finalival.lo(),
1242 "{} >= {}",
1243 finalreal,
1244 finalival.lo()
1245 );
1246 }
1247 }
1248
1249 for (name, ifun, realfun) in &single_operand_functions {
1250 let lo1 = rng.gen_range(-40.0..40.0);
1251 let hi1 = rng.gen_range(lo1..41.0);
1252 let ival1 = Interval::new(F64_PREC, lo1, hi1);
1253 let realval1 = rng.gen_range(lo1..hi1);
1254 let finalival = ifun(&ival1);
1255 let finalreal = realfun(bf(F64_PREC, realval1));
1256
1257 if finalreal.is_nan() {
1258 assert!(finalival.err.hi);
1259 } else {
1260 assert!(!finalival.err.lo);
1261 assert!(
1262 finalreal <= finalival.hi(),
1263 "{}: {} <= {}",
1264 name,
1265 finalreal,
1266 finalival.hi()
1267 );
1268 assert!(
1269 finalreal >= finalival.lo(),
1270 "{}: {} >= {}",
1271 name,
1272 finalreal,
1273 finalival.lo()
1274 );
1275 }
1276 }
1277 }
1278 }
1279}