From for $name {
fn from(p: P) -> Self {
let accuracy = P::ACCURACY.saturated_into();
let value = p.deconstruct().saturated_into();
$name::saturating_from_rational(value, accuracy)
}
}
#[cfg(feature = "std")]
impl sp_std::fmt::Display for $name {
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(feature = "std")]
impl sp_std::str::FromStr for $name {
type Err = &'static str;
fn from_str(s: &str) -> Result {
let inner: ::Inner = s.parse()
.map_err(|_| "invalid string input for fixed point number")?;
Ok(Self::from_inner(inner))
}
}
// Manual impl `Serialize` as serde_json does not support i128.
// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed.
#[cfg(feature = "std")]
impl Serialize for $name {
fn serialize(&self, serializer: S) -> Result
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
// Manual impl `Deserialize` as serde_json does not support i128.
// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed.
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for $name {
fn deserialize(deserializer: D) -> Result
where
D: Deserializer<'de>,
{
use sp_std::str::FromStr;
let s = String::deserialize(deserializer)?;
$name::from_str(&s).map_err(|err_str| de::Error::custom(err_str))
}
}
#[cfg(test)]
mod $test_mod {
use super::*;
use crate::{Perbill, Percent, Permill, Perquintill};
fn max() -> $name {
$name::max_value()
}
fn min() -> $name {
$name::min_value()
}
fn precision() -> usize {
($name::accuracy() as f64).log10() as usize
}
#[test]
fn macro_preconditions() {
assert!($name::DIV > 0);
}
#[test]
fn from_i129_works() {
let a = I129 {
value: 1,
negative: true,
};
// Can't convert negative number to unsigned.
assert_eq!(from_i129::(a), None);
let a = I129 {
value: u128::max_value() - 1,
negative: false,
};
// Max - 1 value fits.
assert_eq!(from_i129::(a), Some(u128::max_value() - 1));
let a = I129 {
value: u128::max_value(),
negative: false,
};
// Max value fits.
assert_eq!(from_i129::(a), Some(u128::max_value()));
let a = I129 {
value: i128::max_value() as u128 + 1,
negative: true,
};
// Min value fits.
assert_eq!(from_i129::(a), Some(i128::min_value()));
let a = I129 {
value: i128::max_value() as u128 + 1,
negative: false,
};
// Max + 1 does not fit.
assert_eq!(from_i129::(a), None);
let a = I129 {
value: i128::max_value() as u128,
negative: false,
};
// Max value fits.
assert_eq!(from_i129::(a), Some(i128::max_value()));
}
#[test]
fn to_bound_works() {
let a = 1i32;
let b = 1i32;
// Pos + Pos => Max.
assert_eq!(to_bound::<_, _, i32>(a, b), i32::max_value());
let a = -1i32;
let b = -1i32;
// Neg + Neg => Max.
assert_eq!(to_bound::<_, _, i32>(a, b), i32::max_value());
let a = 1i32;
let b = -1i32;
// Pos + Neg => Min.
assert_eq!(to_bound::<_, _, i32>(a, b), i32::min_value());
let a = -1i32;
let b = 1i32;
// Neg + Pos => Min.
assert_eq!(to_bound::<_, _, i32>(a, b), i32::min_value());
let a = 1i32;
let b = -1i32;
// Pos + Neg => Min (unsigned).
assert_eq!(to_bound::<_, _, u32>(a, b), 0);
}
#[test]
fn op_neg_works() {
let a = $name::zero();
let b = -a;
// Zero.
assert_eq!(a, b);
if $name::SIGNED {
let a = $name::saturating_from_integer(5);
let b = -a;
// Positive.
assert_eq!($name::saturating_from_integer(-5), b);
let a = $name::saturating_from_integer(-5);
let b = -a;
// Negative
assert_eq!($name::saturating_from_integer(5), b);
let a = $name::max_value();
let b = -a;
// Max.
assert_eq!($name::min_value() + $name::from_inner(1), b);
let a = $name::min_value() + $name::from_inner(1);
let b = -a;
// Min.
assert_eq!($name::max_value(), b);
}
}
#[test]
fn op_checked_add_overflow_works() {
let a = $name::max_value();
let b = 1.into();
assert!(a.checked_add(&b).is_none());
}
#[test]
fn op_add_works() {
let a = $name::saturating_from_rational(5, 2);
let b = $name::saturating_from_rational(1, 2);
// Positive case: 6/2 = 3.
assert_eq!($name::saturating_from_integer(3), a + b);
if $name::SIGNED {
// Negative case: 4/2 = 2.
let b = $name::saturating_from_rational(1, -2);
assert_eq!($name::saturating_from_integer(2), a + b);
}
}
#[test]
fn op_checked_sub_underflow_works() {
let a = $name::min_value();
let b = 1.into();
assert!(a.checked_sub(&b).is_none());
}
#[test]
fn op_sub_works() {
let a = $name::saturating_from_rational(5, 2);
let b = $name::saturating_from_rational(1, 2);
assert_eq!($name::saturating_from_integer(2), a - b);
assert_eq!($name::saturating_from_integer(-2), b.saturating_sub(a));
}
#[test]
fn op_checked_mul_overflow_works() {
let a = $name::max_value();
let b = 2.into();
assert!(a.checked_mul(&b).is_none());
}
#[test]
fn op_mul_works() {
let a = $name::saturating_from_integer(42);
let b = $name::saturating_from_integer(2);
assert_eq!($name::saturating_from_integer(84), a * b);
let a = $name::saturating_from_integer(42);
let b = $name::saturating_from_integer(-2);
assert_eq!($name::saturating_from_integer(-84), a * b);
}
#[test]
#[should_panic(expected = "attempt to divide by zero")]
fn op_div_panics_on_zero_divisor() {
let a = $name::saturating_from_integer(1);
let b = 0.into();
let _c = a / b;
}
#[test]
fn op_checked_div_overflow_works() {
if $name::SIGNED {
let a = $name::min_value();
let b = $name::zero().saturating_sub($name::one());
assert!(a.checked_div(&b).is_none());
}
}
#[test]
fn op_div_works() {
let a = $name::saturating_from_integer(42);
let b = $name::saturating_from_integer(2);
assert_eq!($name::saturating_from_integer(21), a / b);
if $name::SIGNED {
let a = $name::saturating_from_integer(42);
let b = $name::saturating_from_integer(-2);
assert_eq!($name::saturating_from_integer(-21), a / b);
}
}
#[test]
fn saturating_from_integer_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
// Cases where integer fits.
let a = $name::saturating_from_integer(42);
assert_eq!(a.into_inner(), 42 * accuracy);
let a = $name::saturating_from_integer(-42);
assert_eq!(a.into_inner(), 0.saturating_sub(42 * accuracy));
// Max/min integers that fit.
let a = $name::saturating_from_integer(inner_max / accuracy);
assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy);
let a = $name::saturating_from_integer(inner_min / accuracy);
assert_eq!(a.into_inner(), (inner_min / accuracy) * accuracy);
// Cases where integer doesn't fit, so it saturates.
let a = $name::saturating_from_integer(inner_max / accuracy + 1);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_integer((inner_min / accuracy).saturating_sub(1));
assert_eq!(a.into_inner(), inner_min);
}
#[test]
fn checked_from_integer_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
// Case where integer fits.
let a = $name::checked_from_integer(42)
.expect("42 * accuracy <= inner_max; qed");
assert_eq!(a.into_inner(), 42 * accuracy);
// Max integer that fit.
let a = $name::checked_from_integer(inner_max / accuracy)
.expect("(inner_max / accuracy) * accuracy <= inner_max; qed");
assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy);
// Case where integer doesn't fit, so it returns `None`.
let a = $name::checked_from_integer(inner_max / accuracy + 1);
assert_eq!(a, None);
if $name::SIGNED {
// Case where integer fits.
let a = $name::checked_from_integer(0.saturating_sub(42))
.expect("-42 * accuracy >= inner_min; qed");
assert_eq!(a.into_inner(), 0 - 42 * accuracy);
// Min integer that fit.
let a = $name::checked_from_integer(inner_min / accuracy)
.expect("(inner_min / accuracy) * accuracy <= inner_min; qed");
assert_eq!(a.into_inner(), (inner_min / accuracy) * accuracy);
// Case where integer doesn't fit, so it returns `None`.
let a = $name::checked_from_integer(inner_min / accuracy - 1);
assert_eq!(a, None);
}
}
#[test]
fn from_inner_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
assert_eq!(max(), $name::from_inner(inner_max));
assert_eq!(min(), $name::from_inner(inner_min));
}
#[test]
#[should_panic(expected = "attempt to divide by zero")]
fn saturating_from_rational_panics_on_zero_divisor() {
let _ = $name::saturating_from_rational(1, 0);
}
#[test]
fn saturating_from_rational_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
let a = $name::saturating_from_rational(5, 2);
// Positive case: 2.5
assert_eq!(a.into_inner(), 25 * accuracy / 10);
// Max - 1.
let a = $name::saturating_from_rational(inner_max - 1, accuracy);
assert_eq!(a.into_inner(), inner_max - 1);
// Min + 1.
let a = $name::saturating_from_rational(inner_min + 1, accuracy);
assert_eq!(a.into_inner(), inner_min + 1);
// Max.
let a = $name::saturating_from_rational(inner_max, accuracy);
assert_eq!(a.into_inner(), inner_max);
// Min.
let a = $name::saturating_from_rational(inner_min, accuracy);
assert_eq!(a.into_inner(), inner_min);
// Zero.
let a = $name::saturating_from_rational(0, 1);
assert_eq!(a.into_inner(), 0);
if $name::SIGNED {
// Negative case: -2.5
let a = $name::saturating_from_rational(-5, 2);
assert_eq!(a.into_inner(), 0 - 25 * accuracy / 10);
// Other negative case: -2.5
let a = $name::saturating_from_rational(5, -2);
assert_eq!(a.into_inner(), 0 - 25 * accuracy / 10);
// Other positive case: 2.5
let a = $name::saturating_from_rational(-5, -2);
assert_eq!(a.into_inner(), 25 * accuracy / 10);
// Max + 1, saturates.
let a = $name::saturating_from_rational(inner_max as u128 + 1, accuracy);
assert_eq!(a.into_inner(), inner_max);
// Min - 1, saturates.
let a = $name::saturating_from_rational(inner_max as u128 + 2, 0 - accuracy);
assert_eq!(a.into_inner(), inner_min);
let a = $name::saturating_from_rational(inner_max, 0 - accuracy);
assert_eq!(a.into_inner(), 0 - inner_max);
let a = $name::saturating_from_rational(inner_min, 0 - accuracy);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_rational(inner_min + 1, 0 - accuracy);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_rational(inner_min, 0 - 1);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_rational(inner_max, 0 - 1);
assert_eq!(a.into_inner(), inner_min);
let a = $name::saturating_from_rational(inner_max, 0 - inner_max);
assert_eq!(a.into_inner(), 0 - accuracy);
let a = $name::saturating_from_rational(0 - inner_max, inner_max);
assert_eq!(a.into_inner(), 0 - accuracy);
let a = $name::saturating_from_rational(inner_max, 0 - 3 * accuracy);
assert_eq!(a.into_inner(), 0 - inner_max / 3);
let a = $name::saturating_from_rational(inner_min, 0 - accuracy / 3);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_rational(1, 0 - accuracy);
assert_eq!(a.into_inner(), 0.saturating_sub(1));
let a = $name::saturating_from_rational(inner_min, inner_min);
assert_eq!(a.into_inner(), accuracy);
// Out of accuracy.
let a = $name::saturating_from_rational(1, 0 - accuracy - 1);
assert_eq!(a.into_inner(), 0);
}
let a = $name::saturating_from_rational(inner_max - 1, accuracy);
assert_eq!(a.into_inner(), inner_max - 1);
let a = $name::saturating_from_rational(inner_min + 1, accuracy);
assert_eq!(a.into_inner(), inner_min + 1);
let a = $name::saturating_from_rational(inner_max, 1);
assert_eq!(a.into_inner(), inner_max);
let a = $name::saturating_from_rational(inner_min, 1);
assert_eq!(a.into_inner(), inner_min);
let a = $name::saturating_from_rational(inner_max, inner_max);
assert_eq!(a.into_inner(), accuracy);
let a = $name::saturating_from_rational(inner_max, 3 * accuracy);
assert_eq!(a.into_inner(), inner_max / 3);
let a = $name::saturating_from_rational(inner_min, 2 * accuracy);
assert_eq!(a.into_inner(), inner_min / 2);
let a = $name::saturating_from_rational(inner_min, accuracy / 3);
assert_eq!(a.into_inner(), inner_min);
let a = $name::saturating_from_rational(1, accuracy);
assert_eq!(a.into_inner(), 1);
// Out of accuracy.
let a = $name::saturating_from_rational(1, accuracy + 1);
assert_eq!(a.into_inner(), 0);
}
#[test]
fn checked_from_rational_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
// Divide by zero => None.
let a = $name::checked_from_rational(1, 0);
assert_eq!(a, None);
// Max - 1.
let a = $name::checked_from_rational(inner_max - 1, accuracy).unwrap();
assert_eq!(a.into_inner(), inner_max - 1);
// Min + 1.
let a = $name::checked_from_rational(inner_min + 1, accuracy).unwrap();
assert_eq!(a.into_inner(), inner_min + 1);
// Max.
let a = $name::checked_from_rational(inner_max, accuracy).unwrap();
assert_eq!(a.into_inner(), inner_max);
// Min.
let a = $name::checked_from_rational(inner_min, accuracy).unwrap();
assert_eq!(a.into_inner(), inner_min);
// Max + 1 => Overflow => None.
let a = $name::checked_from_rational(inner_min, 0.saturating_sub(accuracy));
assert_eq!(a, None);
if $name::SIGNED {
// Min - 1 => Underflow => None.
let a = $name::checked_from_rational(inner_max as u128 + 2, 0.saturating_sub(accuracy));
assert_eq!(a, None);
let a = $name::checked_from_rational(inner_max, 0 - 3 * accuracy).unwrap();
assert_eq!(a.into_inner(), 0 - inner_max / 3);
let a = $name::checked_from_rational(inner_min, 0 - accuracy / 3);
assert_eq!(a, None);
let a = $name::checked_from_rational(1, 0 - accuracy).unwrap();
assert_eq!(a.into_inner(), 0.saturating_sub(1));
let a = $name::checked_from_rational(1, 0 - accuracy - 1).unwrap();
assert_eq!(a.into_inner(), 0);
let a = $name::checked_from_rational(inner_min, accuracy / 3);
assert_eq!(a, None);
}
let a = $name::checked_from_rational(inner_max, 3 * accuracy).unwrap();
assert_eq!(a.into_inner(), inner_max / 3);
let a = $name::checked_from_rational(inner_min, 2 * accuracy).unwrap();
assert_eq!(a.into_inner(), inner_min / 2);
let a = $name::checked_from_rational(1, accuracy).unwrap();
assert_eq!(a.into_inner(), 1);
let a = $name::checked_from_rational(1, accuracy + 1).unwrap();
assert_eq!(a.into_inner(), 0);
}
#[test]
fn checked_mul_int_works() {
let a = $name::saturating_from_integer(2);
// Max - 1.
assert_eq!(a.checked_mul_int((i128::max_value() - 1) / 2), Some(i128::max_value() - 1));
// Max.
assert_eq!(a.checked_mul_int(i128::max_value() / 2), Some(i128::max_value() - 1));
// Max + 1 => None.
assert_eq!(a.checked_mul_int(i128::max_value() / 2 + 1), None);
if $name::SIGNED {
// Min - 1.
assert_eq!(a.checked_mul_int((i128::min_value() + 1) / 2), Some(i128::min_value() + 2));
// Min.
assert_eq!(a.checked_mul_int(i128::min_value() / 2), Some(i128::min_value()));
// Min + 1 => None.
assert_eq!(a.checked_mul_int(i128::min_value() / 2 - 1), None);
let b = $name::saturating_from_rational(1, -2);
assert_eq!(b.checked_mul_int(42i128), Some(-21));
assert_eq!(b.checked_mul_int(u128::max_value()), None);
assert_eq!(b.checked_mul_int(i128::max_value()), Some(i128::max_value() / -2));
assert_eq!(b.checked_mul_int(i128::min_value()), Some(i128::min_value() / -2));
}
let a = $name::saturating_from_rational(1, 2);
assert_eq!(a.checked_mul_int(42i128), Some(21));
assert_eq!(a.checked_mul_int(i128::max_value()), Some(i128::max_value() / 2));
assert_eq!(a.checked_mul_int(i128::min_value()), Some(i128::min_value() / 2));
let c = $name::saturating_from_integer(255);
assert_eq!(c.checked_mul_int(2i8), None);
assert_eq!(c.checked_mul_int(2i128), Some(510));
assert_eq!(c.checked_mul_int(i128::max_value()), None);
assert_eq!(c.checked_mul_int(i128::min_value()), None);
}
#[test]
fn saturating_mul_int_works() {
let a = $name::saturating_from_integer(2);
// Max - 1.
assert_eq!(a.saturating_mul_int((i128::max_value() - 1) / 2), i128::max_value() - 1);
// Max.
assert_eq!(a.saturating_mul_int(i128::max_value() / 2), i128::max_value() - 1);
// Max + 1 => saturates to max.
assert_eq!(a.saturating_mul_int(i128::max_value() / 2 + 1), i128::max_value());
// Min - 1.
assert_eq!(a.saturating_mul_int((i128::min_value() + 1) / 2), i128::min_value() + 2);
// Min.
assert_eq!(a.saturating_mul_int(i128::min_value() / 2), i128::min_value());
// Min + 1 => saturates to min.
assert_eq!(a.saturating_mul_int(i128::min_value() / 2 - 1), i128::min_value());
if $name::SIGNED {
let b = $name::saturating_from_rational(1, -2);
assert_eq!(b.saturating_mul_int(42i32), -21);
assert_eq!(b.saturating_mul_int(i128::max_value()), i128::max_value() / -2);
assert_eq!(b.saturating_mul_int(i128::min_value()), i128::min_value() / -2);
assert_eq!(b.saturating_mul_int(u128::max_value()), u128::min_value());
}
let a = $name::saturating_from_rational(1, 2);
assert_eq!(a.saturating_mul_int(42i32), 21);
assert_eq!(a.saturating_mul_int(i128::max_value()), i128::max_value() / 2);
assert_eq!(a.saturating_mul_int(i128::min_value()), i128::min_value() / 2);
let c = $name::saturating_from_integer(255);
assert_eq!(c.saturating_mul_int(2i8), i8::max_value());
assert_eq!(c.saturating_mul_int(-2i8), i8::min_value());
assert_eq!(c.saturating_mul_int(i128::max_value()), i128::max_value());
assert_eq!(c.saturating_mul_int(i128::min_value()), i128::min_value());
}
#[test]
fn checked_mul_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let a = $name::saturating_from_integer(2);
// Max - 1.
let b = $name::from_inner(inner_max - 1);
assert_eq!(a.checked_mul(&(b/2.into())), Some(b));
// Max.
let c = $name::from_inner(inner_max);
assert_eq!(a.checked_mul(&(c/2.into())), Some(b));
// Max + 1 => None.
let e = $name::from_inner(1);
assert_eq!(a.checked_mul(&(c/2.into()+e)), None);
if $name::SIGNED {
// Min + 1.
let b = $name::from_inner(inner_min + 1) / 2.into();
let c = $name::from_inner(inner_min + 2);
assert_eq!(a.checked_mul(&b), Some(c));
// Min.
let b = $name::from_inner(inner_min) / 2.into();
let c = $name::from_inner(inner_min);
assert_eq!(a.checked_mul(&b), Some(c));
// Min - 1 => None.
let b = $name::from_inner(inner_min) / 2.into() - $name::from_inner(1);
assert_eq!(a.checked_mul(&b), None);
let c = $name::saturating_from_integer(255);
let b = $name::saturating_from_rational(1, -2);
assert_eq!(b.checked_mul(&42.into()), Some(0.saturating_sub(21).into()));
assert_eq!(b.checked_mul(&$name::max_value()), $name::max_value().checked_div(&0.saturating_sub(2).into()));
assert_eq!(b.checked_mul(&$name::min_value()), $name::min_value().checked_div(&0.saturating_sub(2).into()));
assert_eq!(c.checked_mul(&$name::min_value()), None);
}
let a = $name::saturating_from_rational(1, 2);
let c = $name::saturating_from_integer(255);
assert_eq!(a.checked_mul(&42.into()), Some(21.into()));
assert_eq!(c.checked_mul(&2.into()), Some(510.into()));
assert_eq!(c.checked_mul(&$name::max_value()), None);
assert_eq!(a.checked_mul(&$name::max_value()), $name::max_value().checked_div(&2.into()));
assert_eq!(a.checked_mul(&$name::min_value()), $name::min_value().checked_div(&2.into()));
}
#[test]
fn checked_div_int_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
let a = $name::from_inner(inner_max);
let b = $name::from_inner(inner_min);
let c = $name::zero();
let d = $name::one();
let e = $name::saturating_from_integer(6);
let f = $name::saturating_from_integer(5);
assert_eq!(e.checked_div_int(2.into()), Some(3));
assert_eq!(f.checked_div_int(2.into()), Some(2));
assert_eq!(a.checked_div_int(i128::max_value()), Some(0));
assert_eq!(a.checked_div_int(2), Some(inner_max / (2 * accuracy)));
assert_eq!(a.checked_div_int(inner_max / accuracy), Some(1));
assert_eq!(a.checked_div_int(1i8), None);
if b < c {
// Not executed by unsigned inners.
assert_eq!(a.checked_div_int(0.saturating_sub(2)), Some(0.saturating_sub(inner_max / (2 * accuracy))));
assert_eq!(a.checked_div_int(0.saturating_sub(inner_max / accuracy)), Some(0.saturating_sub(1)));
assert_eq!(b.checked_div_int(i128::min_value()), Some(0));
assert_eq!(b.checked_div_int(inner_min / accuracy), Some(1));
assert_eq!(b.checked_div_int(1i8), None);
assert_eq!(b.checked_div_int(0.saturating_sub(2)), Some(0.saturating_sub(inner_min / (2 * accuracy))));
assert_eq!(b.checked_div_int(0.saturating_sub(inner_min / accuracy)), Some(0.saturating_sub(1)));
assert_eq!(c.checked_div_int(i128::min_value()), Some(0));
assert_eq!(d.checked_div_int(i32::min_value()), Some(0));
}
assert_eq!(b.checked_div_int(2), Some(inner_min / (2 * accuracy)));
assert_eq!(c.checked_div_int(1), Some(0));
assert_eq!(c.checked_div_int(i128::max_value()), Some(0));
assert_eq!(c.checked_div_int(1i8), Some(0));
assert_eq!(d.checked_div_int(1), Some(1));
assert_eq!(d.checked_div_int(i32::max_value()), Some(0));
assert_eq!(d.checked_div_int(1i8), Some(1));
assert_eq!(a.checked_div_int(0), None);
assert_eq!(b.checked_div_int(0), None);
assert_eq!(c.checked_div_int(0), None);
assert_eq!(d.checked_div_int(0), None);
}
#[test]
#[should_panic(expected = "attempt to divide by zero")]
fn saturating_div_int_panics_when_divisor_is_zero() {
let _ = $name::one().saturating_div_int(0);
}
#[test]
fn saturating_div_int_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let accuracy = $name::accuracy();
let a = $name::saturating_from_integer(5);
assert_eq!(a.saturating_div_int(2), 2);
let a = $name::min_value();
assert_eq!(a.saturating_div_int(1i128), (inner_min / accuracy) as i128);
if $name::SIGNED {
let a = $name::saturating_from_integer(5);
assert_eq!(a.saturating_div_int(-2), -2);
let a = $name::min_value();
assert_eq!(a.saturating_div_int(-1i128), (inner_max / accuracy) as i128);
}
}
#[test]
fn saturating_abs_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
assert_eq!($name::from_inner(inner_max).saturating_abs(), $name::max_value());
assert_eq!($name::zero().saturating_abs(), 0.into());
if $name::SIGNED {
assert_eq!($name::from_inner(inner_min).saturating_abs(), $name::max_value());
assert_eq!($name::saturating_from_rational(-1, 2).saturating_abs(), (1, 2).into());
}
}
#[test]
fn saturating_mul_acc_int_works() {
assert_eq!($name::zero().saturating_mul_acc_int(42i8), 42i8);
assert_eq!($name::one().saturating_mul_acc_int(42i8), 2 * 42i8);
assert_eq!($name::one().saturating_mul_acc_int(i128::max_value()), i128::max_value());
assert_eq!($name::one().saturating_mul_acc_int(i128::min_value()), i128::min_value());
assert_eq!($name::one().saturating_mul_acc_int(u128::max_value() / 2), u128::max_value() - 1);
assert_eq!($name::one().saturating_mul_acc_int(u128::min_value()), u128::min_value());
if $name::SIGNED {
let a = $name::saturating_from_rational(-1, 2);
assert_eq!(a.saturating_mul_acc_int(42i8), 21i8);
assert_eq!(a.saturating_mul_acc_int(42u8), 21u8);
assert_eq!(a.saturating_mul_acc_int(u128::max_value() - 1), u128::max_value() / 2);
}
}
#[test]
fn saturating_pow_should_work() {
assert_eq!($name::saturating_from_integer(2).saturating_pow(0), $name::saturating_from_integer(1));
assert_eq!($name::saturating_from_integer(2).saturating_pow(1), $name::saturating_from_integer(2));
assert_eq!($name::saturating_from_integer(2).saturating_pow(2), $name::saturating_from_integer(4));
assert_eq!($name::saturating_from_integer(2).saturating_pow(3), $name::saturating_from_integer(8));
assert_eq!($name::saturating_from_integer(2).saturating_pow(50),
$name::saturating_from_integer(1125899906842624i64));
assert_eq!($name::saturating_from_integer(1).saturating_pow(1000), (1).into());
assert_eq!($name::saturating_from_integer(1).saturating_pow(usize::max_value()), (1).into());
if $name::SIGNED {
// Saturating.
assert_eq!($name::saturating_from_integer(2).saturating_pow(68), $name::max_value());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(1000), (1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(1001), 0.saturating_sub(1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(usize::max_value()), 0.saturating_sub(1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(usize::max_value() - 1), (1).into());
}
assert_eq!($name::saturating_from_integer(114209).saturating_pow(5), $name::max_value());
assert_eq!($name::saturating_from_integer(1).saturating_pow(usize::max_value()), (1).into());
assert_eq!($name::saturating_from_integer(0).saturating_pow(usize::max_value()), (0).into());
assert_eq!($name::saturating_from_integer(2).saturating_pow(usize::max_value()), $name::max_value());
}
#[test]
fn checked_div_works() {
let inner_max = <$name as FixedPointNumber>::Inner::max_value();
let inner_min = <$name as FixedPointNumber>::Inner::min_value();
let a = $name::from_inner(inner_max);
let b = $name::from_inner(inner_min);
let c = $name::zero();
let d = $name::one();
let e = $name::saturating_from_integer(6);
let f = $name::saturating_from_integer(5);
assert_eq!(e.checked_div(&2.into()), Some(3.into()));
assert_eq!(f.checked_div(&2.into()), Some((5, 2).into()));
assert_eq!(a.checked_div(&inner_max.into()), Some(1.into()));
assert_eq!(a.checked_div(&2.into()), Some($name::from_inner(inner_max / 2)));
assert_eq!(a.checked_div(&$name::max_value()), Some(1.into()));
assert_eq!(a.checked_div(&d), Some(a));
if b < c {
// Not executed by unsigned inners.
assert_eq!(a.checked_div(&0.saturating_sub(2).into()), Some($name::from_inner(0.saturating_sub(inner_max / 2))));
assert_eq!(a.checked_div(&-$name::max_value()), Some(0.saturating_sub(1).into()));
assert_eq!(b.checked_div(&0.saturating_sub(2).into()), Some($name::from_inner(0.saturating_sub(inner_min / 2))));
assert_eq!(c.checked_div(&$name::max_value()), Some(0.into()));
assert_eq!(b.checked_div(&b), Some($name::one()));
}
assert_eq!(b.checked_div(&2.into()), Some($name::from_inner(inner_min / 2)));
assert_eq!(b.checked_div(&a), Some(0.saturating_sub(1).into()));
assert_eq!(c.checked_div(&1.into()), Some(0.into()));
assert_eq!(d.checked_div(&1.into()), Some(1.into()));
assert_eq!(a.checked_div(&$name::one()), Some(a));
assert_eq!(b.checked_div(&$name::one()), Some(b));
assert_eq!(c.checked_div(&$name::one()), Some(c));
assert_eq!(d.checked_div(&$name::one()), Some(d));
assert_eq!(a.checked_div(&$name::zero()), None);
assert_eq!(b.checked_div(&$name::zero()), None);
assert_eq!(c.checked_div(&$name::zero()), None);
assert_eq!(d.checked_div(&$name::zero()), None);
}
#[test]
fn is_positive_negative_works() {
let one = $name::one();
assert!(one.is_positive());
assert!(!one.is_negative());
let zero = $name::zero();
assert!(!zero.is_positive());
assert!(!zero.is_negative());
if $signed {
let minus_one = $name::saturating_from_integer(-1);
assert!(minus_one.is_negative());
assert!(!minus_one.is_positive());
}
}
#[test]
fn trunc_works() {
let n = $name::saturating_from_rational(5, 2).trunc();
assert_eq!(n, $name::saturating_from_integer(2));
if $name::SIGNED {
let n = $name::saturating_from_rational(-5, 2).trunc();
assert_eq!(n, $name::saturating_from_integer(-2));
}
}
#[test]
fn frac_works() {
let n = $name::saturating_from_rational(5, 2);
let i = n.trunc();
let f = n.frac();
assert_eq!(n, i + f);
let n = $name::saturating_from_rational(5, 2)
.frac()
.saturating_mul(10.into());
assert_eq!(n, 5.into());
let n = $name::saturating_from_rational(1, 2)
.frac()
.saturating_mul(10.into());
assert_eq!(n, 5.into());
if $name::SIGNED {
let n = $name::saturating_from_rational(-5, 2);
let i = n.trunc();
let f = n.frac();
assert_eq!(n, i - f);
// The sign is attached to the integer part unless it is zero.
let n = $name::saturating_from_rational(-5, 2)
.frac()
.saturating_mul(10.into());
assert_eq!(n, 5.into());
let n = $name::saturating_from_rational(-1, 2)
.frac()
.saturating_mul(10.into());
assert_eq!(n, 0.saturating_sub(5).into());
}
}
#[test]
fn ceil_works() {
let n = $name::saturating_from_rational(5, 2);
assert_eq!(n.ceil(), 3.into());
let n = $name::saturating_from_rational(-5, 2);
assert_eq!(n.ceil(), 0.saturating_sub(2).into());
// On the limits:
let n = $name::max_value();
assert_eq!(n.ceil(), n.trunc());
let n = $name::min_value();
assert_eq!(n.ceil(), n.trunc());
}
#[test]
fn floor_works() {
let n = $name::saturating_from_rational(5, 2);
assert_eq!(n.floor(), 2.into());
let n = $name::saturating_from_rational(-5, 2);
assert_eq!(n.floor(), 0.saturating_sub(3).into());
// On the limits:
let n = $name::max_value();
assert_eq!(n.floor(), n.trunc());
let n = $name::min_value();
assert_eq!(n.floor(), n.trunc());
}
#[test]
fn round_works() {
let n = $name::zero();
assert_eq!(n.round(), n);
let n = $name::one();
assert_eq!(n.round(), n);
let n = $name::saturating_from_rational(5, 2);
assert_eq!(n.round(), 3.into());
let n = $name::saturating_from_rational(-5, 2);
assert_eq!(n.round(), 0.saturating_sub(3).into());
// Saturating:
let n = $name::max_value();
assert_eq!(n.round(), n.trunc());
let n = $name::min_value();
assert_eq!(n.round(), n.trunc());
// On the limit:
// floor(max - 1) + 0.33..
let n = $name::max_value()
.saturating_sub(1.into())
.trunc()
.saturating_add((1, 3).into());
assert_eq!(n.round(), ($name::max_value() - 1.into()).trunc());
// floor(max - 1) + 0.5
let n = $name::max_value()
.saturating_sub(1.into())
.trunc()
.saturating_add((1, 2).into());
assert_eq!(n.round(), $name::max_value().trunc());
if $name::SIGNED {
// floor(min + 1) - 0.33..
let n = $name::min_value()
.saturating_add(1.into())
.trunc()
.saturating_sub((1, 3).into());
assert_eq!(n.round(), ($name::min_value() + 1.into()).trunc());
// floor(min + 1) - 0.5
let n = $name::min_value()
.saturating_add(1.into())
.trunc()
.saturating_sub((1, 2).into());
assert_eq!(n.round(), $name::min_value().trunc());
}
}
#[test]
fn perthing_into_works() {
let ten_percent_percent: $name = Percent::from_percent(10).into();
assert_eq!(ten_percent_percent.into_inner(), $name::accuracy() / 10);
let ten_percent_permill: $name = Permill::from_percent(10).into();
assert_eq!(ten_percent_permill.into_inner(), $name::accuracy() / 10);
let ten_percent_perbill: $name = Perbill::from_percent(10).into();
assert_eq!(ten_percent_perbill.into_inner(), $name::accuracy() / 10);
let ten_percent_perquintill: $name = Perquintill::from_percent(10).into();
assert_eq!(ten_percent_perquintill.into_inner(), $name::accuracy() / 10);
}
#[test]
fn fmt_should_work() {
let zero = $name::zero();
assert_eq!(format!("{:?}", zero), format!("{}(0.{:0>weight$})", stringify!($name), 0, weight=precision()));
let one = $name::one();
assert_eq!(format!("{:?}", one), format!("{}(1.{:0>weight$})", stringify!($name), 0, weight=precision()));
let frac = $name::saturating_from_rational(1, 2);
assert_eq!(format!("{:?}", frac), format!("{}(0.{:0weight$})", stringify!($name), 0, weight=precision()));
let frac = $name::saturating_from_rational(-314, 100);
assert_eq!(format!("{:?}", frac), format!("{}(-3.{:0