honestintervals 0.2.0

Comprehensive, correctly rounding interval arithmetic library.
Documentation
use super::def::{Interval, SignClass};

use fp::Float;
use transc::Transc;

impl<BOUND: Float> Interval<BOUND> {
    fn pow_p_p_multi(self, rhs: Self) -> Vec<Self> {
        assert!(self.sign_class().is_positive());
        assert!(rhs.sign_class().is_positive());

        let precision = self.precision();
        let mut intervals = Vec::<Self>::new();
        let (self_01, self_1i) = self.split(BOUND::one(precision));
        if !self_1i.is_nan() {
            intervals.push(Self::new(
                self_1i.lo.pow_lo(rhs.lo.clone()),
                self_1i.hi.pow_hi(rhs.hi.clone()),
            ));
        }
        if !self_01.is_nan() {
            intervals.push(Self::new(
                self_01.lo.pow_lo(rhs.hi),
                self_01.hi.pow_hi(rhs.lo),
            ));
        }
        intervals
    }

    fn pow_p_n_multi(self, rhs: Self) -> Vec<Self> {
        assert!(self.sign_class().is_positive());
        assert!(rhs.sign_class().is_negative());

        let mut pos_intervals = self.pow_p_p_multi(-rhs);
        let res = pos_intervals.drain(..)
            .flat_map(|i| Interval::one(i.precision()).div_multi(i))
            .collect();
        res
    }

    fn pow_p_a_multi(self, rhs: Self) -> Vec<Self> {
        assert!(self.sign_class().is_positive());

        let mut intervals = Vec::<Self>::new();
        let precision = rhs.precision();
        let (other_n, other_p) = rhs.split(BOUND::zero(precision));
        if !other_p.is_nan() {
            intervals.append(&mut self.clone().pow_p_p_multi(other_p));
        }
        if !other_n.is_nan() {
            intervals.append(&mut self.pow_p_n_multi(other_n));
        }
        intervals
    }

    fn pow_n_a_multi(self, rhs: Self) -> Vec<Self> {
        assert!(self.sign_class().is_negative());

        let mut intervals = Vec::<Self>::new();
        let mut neg_intervals = (-self).pow_p_a_multi(rhs);
        intervals.append(&mut neg_intervals.iter().map(|i| -i.clone()).collect());
        intervals.append(&mut neg_intervals);
        intervals
    }

    /// Computes `self` raised to the power `rhs` and returns a vector of intervals minimally
    /// covering the result.
    pub fn pow_multi(self, rhs: Self) -> Vec<Self> {
        let precision = self.precision();

        if self.is_nan() {
            return vec![]
        }
        if rhs.is_nan() {
            return vec![]
        }
        if rhs.is_zero() {
            return vec![Self::one(precision)];
        }
        if self.is_zero() {
            return vec![self];
        }

        let mut intervals = Vec::<Self>::new();
        let (self_n, self_p) = self.split(BOUND::zero(precision));
        if !self_p.is_nan() {
            intervals.append(&mut self_p.pow_p_a_multi(rhs.clone()));
        }
        if !self_n.is_nan() {
            intervals.append(&mut self_n.pow_n_a_multi(rhs));
        }
        intervals
    }
}

impl<BOUND: Float> Transc for Interval<BOUND> {
    type Output = Self;

    fn log(self) -> Self::Output {
        match self.sign_class() {
            SignClass::Mixed => Self::new(
                BOUND::neg_infinity(self.precision()),
                self.hi.log_hi(),
            ),
            SignClass::Zero => Self::nan(self.precision()),
            SignClass::Positive(has_zero) => if has_zero {
                Self::new(
                    BOUND::neg_infinity(self.precision()),
                    self.hi.log_hi(),
                )
            } else {
                Self::new(
                    self.lo.log_lo(),
                    self.hi.log_hi(),
                )
            },
            SignClass::Negative(_) => Self::nan(self.precision()),
        }
    }

    fn exp(self) -> Self::Output {
        Interval::new(self.lo.exp_lo(), self.hi.exp_hi())
    }

    fn pow(self, rhs: Self) -> Self::Output {
        let precision = self.precision();
        Self::minimal_cover(self.pow_multi(rhs), precision)
    }
}