#![cfg_attr(not(feature = "std"), no_std)]
#[macro_export]
macro_rules! assert_eq_error_rate {
($x:expr, $y:expr, $error:expr $(,)?) => {
assert!(
($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)),
"{:?} != {:?} (with error rate {:?})",
$x,
$y,
$error,
);
};
}
pub mod biguint;
pub mod helpers_128bit;
pub mod traits;
mod per_things;
mod fixed_point;
mod rational128;
pub use fixed_point::{FixedPointNumber, FixedPointOperand, FixedI64, FixedI128, FixedU128};
pub use per_things::{PerThing, InnerOf, Percent, PerU16, Permill, Perbill, Perquintill};
pub use rational128::Rational128;
use sp_std::cmp::Ordering;
pub trait ThresholdOrd<T> {
fn tcmp(&self, other: &T, epsilon: T) -> Ordering;
}
impl<T> ThresholdOrd<T> for T
where
T: Ord + PartialOrd + Copy + Clone + traits::Zero + traits::Saturating,
{
fn tcmp(&self, other: &T, threshold: T) -> Ordering {
if threshold.is_zero() {
return self.cmp(&other)
}
let upper_bound = other.saturating_add(threshold);
let lower_bound = other.saturating_sub(threshold);
if upper_bound <= lower_bound {
self.cmp(&other)
} else {
match (self.cmp(&lower_bound), self.cmp(&upper_bound)) {
(Ordering::Greater, Ordering::Greater) => Ordering::Greater,
(Ordering::Less, Ordering::Less) => Ordering::Less,
_ => Ordering::Equal,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::Saturating;
use sp_std::cmp::Ordering;
#[test]
fn epsilon_ord_works() {
let b = 115u32;
let e = Perbill::from_percent(10).mul_ceil(b);
assert_eq!(103u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(104u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(115u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(120u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(126u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(127u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(128u32.tcmp(&b, e), Ordering::Greater);
assert_eq!(102u32.tcmp(&b, e), Ordering::Less);
}
#[test]
fn epsilon_ord_works_with_small_epc() {
let b = 115u32;
let e = Perbill::from_parts(100) * b;
assert_eq!(103u32.tcmp(&b, e), 103u32.cmp(&b));
assert_eq!(104u32.tcmp(&b, e), 104u32.cmp(&b));
assert_eq!(115u32.tcmp(&b, e), 115u32.cmp(&b));
assert_eq!(120u32.tcmp(&b, e), 120u32.cmp(&b));
assert_eq!(126u32.tcmp(&b, e), 126u32.cmp(&b));
assert_eq!(127u32.tcmp(&b, e), 127u32.cmp(&b));
assert_eq!(128u32.tcmp(&b, e), 128u32.cmp(&b));
assert_eq!(102u32.tcmp(&b, e), 102u32.cmp(&b));
}
#[test]
fn peru16_rational_does_not_overflow() {
let _ = PerU16::from_rational_approximation(17424870u32, 17424870);
}
#[test]
fn saturating_mul_works() {
assert_eq!(Saturating::saturating_mul(2, i32::min_value()), i32::min_value());
assert_eq!(Saturating::saturating_mul(2, i32::max_value()), i32::max_value());
}
#[test]
fn saturating_pow_works() {
assert_eq!(Saturating::saturating_pow(i32::min_value(), 0), 1);
assert_eq!(Saturating::saturating_pow(i32::max_value(), 0), 1);
assert_eq!(Saturating::saturating_pow(i32::min_value(), 3), i32::min_value());
assert_eq!(Saturating::saturating_pow(i32::min_value(), 2), i32::max_value());
assert_eq!(Saturating::saturating_pow(i32::max_value(), 2), i32::max_value());
}
}