diff --git a/substrate/primitives/sr-arithmetic/src/fixed64.rs b/substrate/primitives/sr-arithmetic/src/fixed64.rs index bd58e36940..5c68cc5529 100644 --- a/substrate/primitives/sr-arithmetic/src/fixed64.rs +++ b/substrate/primitives/sr-arithmetic/src/fixed64.rs @@ -22,7 +22,7 @@ use codec::{Encode, Decode}; use crate::{ Perbill, traits::{ - SaturatedConversion, CheckedSub, CheckedAdd, Bounded, UniqueSaturatedInto, Saturating + SaturatedConversion, CheckedSub, CheckedAdd, CheckedDiv, Bounded, UniqueSaturatedInto, Saturating } }; @@ -138,6 +138,25 @@ impl ops::Sub for Fixed64 { } } +/// Note that this is a standard, _potentially-panicking_, implementation. Use `CheckedDiv` trait +/// for safe division. +impl ops::Div for Fixed64 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + if rhs.0 == 0 { + let zero = 0; + return Fixed64::from_parts( self.0 / zero); + } + let (n, d) = if rhs.0 < 0 { + (-self.0, rhs.0.abs() as u64) + } else { + (self.0, rhs.0 as u64) + }; + Fixed64::from_rational(n, d) + } +} + impl CheckedSub for Fixed64 { fn checked_sub(&self, rhs: &Self) -> Option { self.0.checked_sub(rhs.0).map(Self) @@ -150,6 +169,16 @@ impl CheckedAdd for Fixed64 { } } +impl CheckedDiv for Fixed64 { + fn checked_div(&self, rhs: &Self) -> Option { + if rhs.0 == 0 { + None + } else { + Some(*self / *rhs) + } + } +} + impl rstd::fmt::Debug for Fixed64 { #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { @@ -241,4 +270,57 @@ mod tests { saturating_mul_acc_test!(u64); saturating_mul_acc_test!(u128); } + + #[test] + fn div_works() { + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_rational(10, 1); + assert_eq!(a / b, Fixed64::from_rational(12, 100)); + + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_rational(1, 100); + assert_eq!(a / b, Fixed64::from_rational(120, 1)); + + let a = Fixed64::from_rational(12, 100); + let b = Fixed64::from_rational(10, 1); + assert_eq!(a / b, Fixed64::from_rational(12, 1000)); + + let a = Fixed64::from_rational(12, 100); + let b = Fixed64::from_rational(1, 100); + assert_eq!(a / b, Fixed64::from_rational(12, 1)); + + let a = Fixed64::from_rational(-12, 10); + let b = Fixed64::from_rational(10, 1); + assert_eq!(a / b, Fixed64::from_rational(-12, 100)); + + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_rational(-10, 1); + assert_eq!(a / b, Fixed64::from_rational(-12, 100)); + + let a = Fixed64::from_rational(-12, 10); + let b = Fixed64::from_rational(-10, 1); + assert_eq!(a / b, Fixed64::from_rational(12, 100)); + } + + #[test] + #[should_panic(expected = "attempt to divide by zero")] + fn div_zero() { + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_natural(0); + let _ = a / b; + } + + #[test] + fn checked_div_zero() { + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_natural(0); + assert_eq!(a.checked_div(&b), None); + } + + #[test] + fn checked_div_non_zero() { + let a = Fixed64::from_rational(12, 10); + let b = Fixed64::from_rational(1, 100); + assert_eq!(a.checked_div(&b), Some(Fixed64::from_rational(120, 1))); + } }