un_algebra 0.9.0

Simple implementations of selected abstract algebraic structures--including groups, rings, and fields. Intended for self-study of abstract algebra concepts and not for production use.
//!
//! Numeric ordering tests.
//!
//! Traits and implementations of _numeric_ _ordering_--that is,
//! ordering with an "epsilon" or error term. Usually, this means
//! ordering of floating point values.
//!
use super::equal::*;
use crate::helpers::*;


///
/// Numeric ordering predicates.
///
pub trait NumOrd: PartialOrd + NumEq {

  /// Are two values _numerically_ ordered, within `eps`?
  fn num_lt(&self, other: &Self, eps: &Self::Eps) -> bool {
    self.num_ne(other, eps) && self < other
  }


  /// Are two values _numerically_ ordered or equal, within `eps`?
  fn num_le(&self, other: &Self, eps: &Self::Eps) -> bool {
    self.num_eq(other, eps) || self < other
  }


  /// Are two values _numerically_ un-ordered, within `eps`?
  fn num_gt(&self, other: &Self, eps: &Self::Eps) -> bool {
    self.num_ne(other, eps) && self > other
  }


  /// Are two values _numerically_ un-ordered or equal, within `eps`?
  fn num_ge(&self, other: &Self, eps: &Self::Eps) -> bool {
    self.num_eq(other, eps) || self > other
  }
}


///
/// Define `NumOrd` implementations for floating point types. Probably
/// not needed if Rust had a `Float` super-trait.
///
macro_rules! float_num_order {
  ($type:ty) => {
    impl NumOrd for $type {}
  };
}


// 32 and 64 bit IEEE floating point ordering.
float_num_order! {f32}
float_num_order! {f64}


///
/// Define `NumOrd` implementations for homogeneous tuple types (T,),
/// (T, T), etc.
///
macro_rules! tuple_num_order {
  ($tuple:ty) => {
    impl<T: NumOrd> NumOrd for $tuple {

      /// Numeric order is by matching element.
      fn num_gt(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_gt(y, eps))
      }


      /// Numeric order-equality is by matching element.
      fn num_ge(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_ge(y, eps))
      }


      /// Numeric un-order is by matching element.
      fn num_lt(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_lt(y, eps))
      }


      /// Numeric un-order-equality is by matching element.
      fn num_le(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_le(y, eps))
      }
    }
  };

  ($tuple:ty, $($others:ty),+) => {
    tuple_num_order! {$tuple}
    tuple_num_order! {$($others),+}
  };
}


// Tuple numeric ordering implementations.
tuple_num_order! {(T, ), (T, T), (T, T, T), (T, T, T, T)}


///
/// Define `NumOrd` implementations for arrays. This macro may not
/// needed if Rust had _const_ _generics_.
///
macro_rules! array_num_order {
  ($size:expr) => {
    impl<T: NumOrd + Copy> NumOrd for [T; $size] {

      /// Numeric order is by matching element.
      fn num_gt(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_gt(y, eps))
      }


      /// Numeric order-equality is by matching element.
      fn num_ge(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_ge(y, eps))
      }


      /// Numeric un-order is by matching element.
      fn num_lt(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_lt(y, eps))
      }


      /// Numeric un-order-equality is by matching element.
      fn num_le(&self, other: &Self, eps: &Self::Eps) -> bool {
        self.all_with(other, &|x, y| x.num_le(y, eps))
      }
    }
  };

  ($size:expr, $($others:expr),+) => {
    array_num_order! {$size}
    array_num_order! {$($others),+}
  };
}


// Array numeric ordering implementations.
array_num_order! {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
}