diff --git a/CHANGELOG.md b/CHANGELOG.md index af7a4f1f2c..70c570d7cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to `Decimal`/`Decimal256`. - cosmwasm-std: Implement `pow`/`saturating_pow` for `Decimal`/`Decimal256`. - cosmwasm-std: Implement `ceil`/`floor` for `Decimal`/`Decimal256`. +- cosmwasm-std: Implement `saturating_add`/`sub`/`mul` for + `Decimal`/`Decimal256`. [#1334]: https://github.com/CosmWasm/cosmwasm/pull/1334 diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 3d88fc0f56..826f06d502 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -278,14 +278,6 @@ impl Decimal { }) } - /// Raises a value to the power of `exp`, returns MAX on overflow. - pub fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Ok(value) => value, - Err(_) => Self::MAX, - } - } - pub fn checked_div(self, other: Self) -> Result { Decimal::checked_from_ratio(self.numerator(), other.numerator()) } @@ -332,6 +324,34 @@ impl Decimal { pub const fn abs_diff(self, other: Self) -> Self { Self(self.0.abs_diff(other.0)) } + + pub fn saturating_add(self, other: Self) -> Self { + match self.checked_add(other) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + + pub fn saturating_sub(self, other: Self) -> Self { + match self.checked_sub(other) { + Ok(value) => value, + Err(_) => Self::zero(), + } + } + + pub fn saturating_mul(self, other: Self) -> Self { + match self.checked_mul(other) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } } impl Fraction for Decimal { @@ -1890,7 +1910,31 @@ mod tests { } #[test] - fn decimal_saturating_pow() { + fn decimal_saturating_works() { + assert_eq!( + Decimal::percent(200).saturating_add(Decimal::percent(200)), + Decimal::percent(400) + ); + assert_eq!( + Decimal::MAX.saturating_add(Decimal::percent(200)), + Decimal::MAX + ); + assert_eq!( + Decimal::percent(200).saturating_sub(Decimal::percent(100)), + Decimal::percent(100) + ); + assert_eq!( + Decimal::zero().saturating_sub(Decimal::percent(200)), + Decimal::zero() + ); + assert_eq!( + Decimal::percent(200).saturating_mul(Decimal::percent(50)), + Decimal::percent(100) + ); + assert_eq!( + Decimal::MAX.saturating_mul(Decimal::percent(200)), + Decimal::MAX + ); assert_eq!( Decimal::percent(400).saturating_pow(2u32), Decimal::percent(1600) diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index ede9a0a969..ce76ccb87d 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -291,14 +291,6 @@ impl Decimal256 { }) } - /// Raises a value to the power of `exp`, returns MAX on overflow. - pub fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Ok(value) => value, - Err(_) => Self::MAX, - } - } - pub fn checked_div(self, other: Self) -> Result { Decimal256::checked_from_ratio(self.numerator(), other.numerator()) } @@ -349,6 +341,34 @@ impl Decimal256 { self - other } } + + pub fn saturating_add(self, other: Self) -> Self { + match self.checked_add(other) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + + pub fn saturating_sub(self, other: Self) -> Self { + match self.checked_sub(other) { + Ok(value) => value, + Err(_) => Self::zero(), + } + } + + pub fn saturating_mul(self, other: Self) -> Self { + match self.checked_mul(other) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } } impl Fraction for Decimal256 { @@ -2040,7 +2060,31 @@ mod tests { } #[test] - fn decimal256_saturating_pow() { + fn decimal256_saturating_works() { + assert_eq!( + Decimal256::percent(200).saturating_add(Decimal256::percent(200)), + Decimal256::percent(400) + ); + assert_eq!( + Decimal256::MAX.saturating_add(Decimal256::percent(200)), + Decimal256::MAX + ); + assert_eq!( + Decimal256::percent(200).saturating_sub(Decimal256::percent(100)), + Decimal256::percent(100) + ); + assert_eq!( + Decimal256::zero().saturating_sub(Decimal256::percent(200)), + Decimal256::zero() + ); + assert_eq!( + Decimal256::percent(200).saturating_mul(Decimal256::percent(50)), + Decimal256::percent(100) + ); + assert_eq!( + Decimal256::MAX.saturating_mul(Decimal256::percent(200)), + Decimal256::MAX + ); assert_eq!( Decimal256::percent(400).saturating_pow(2u32), Decimal256::percent(1600) diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 5aee2fc8f6..d2e3cd8e1f 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -205,8 +205,8 @@ impl Uint128 { Self(self.0.saturating_mul(other.0)) } - pub fn saturating_pow(self, other: u32) -> Self { - Self(self.0.saturating_pow(other)) + pub fn saturating_pow(self, exp: u32) -> Self { + Self(self.0.saturating_pow(exp)) } pub const fn abs_diff(self, other: Self) -> Self { diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 9150bed567..57b3b78c13 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -284,6 +284,13 @@ impl Uint256 { Self(self.0.saturating_mul(other.0)) } + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + pub fn abs_diff(self, other: Self) -> Self { if self < other { other - self @@ -1465,6 +1472,11 @@ mod tests { Uint256::MAX.saturating_mul(Uint256::from(2u32)), Uint256::MAX ); + assert_eq!( + Uint256::from(4u32).saturating_pow(2u32), + Uint256::from(16u32) + ); + assert_eq!(Uint256::MAX.saturating_pow(2u32), Uint256::MAX); } #[test] diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index ceeb7b8694..40e2e55ff5 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -259,6 +259,13 @@ impl Uint512 { Self(self.0.saturating_mul(other.0)) } + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => Self::MAX, + } + } + pub fn abs_diff(self, other: Self) -> Self { if self < other { other - self @@ -1100,6 +1107,11 @@ mod tests { Uint512::MAX.saturating_mul(Uint512::from(2u32)), Uint512::MAX ); + assert_eq!( + Uint512::from(4u32).saturating_pow(2u32), + Uint512::from(16u32) + ); + assert_eq!(Uint512::MAX.saturating_pow(2u32), Uint512::MAX); } #[test] diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 6bf19b2c3e..b23e41e70a 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -201,8 +201,8 @@ impl Uint64 { Self(self.0.saturating_mul(other.0)) } - pub fn saturating_pow(self, other: u32) -> Self { - Self(self.0.saturating_pow(other)) + pub fn saturating_pow(self, exp: u32) -> Self { + Self(self.0.saturating_pow(exp)) } pub const fn abs_diff(self, other: Self) -> Self {