diff --git a/CHANGELOG.md b/CHANGELOG.md index 44baac9c44..bd6ff727a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to - cosmwasm-std: Implement `Rem`/`RemAssign` for `Decimal`/`Decimal256`. - cosmwasm-std: Implement `checked_add`/`_sub`/`_div`/`_rem` for `Decimal`/`Decimal256`. +- cosmwasm-std: Implement `pow`/`saturating_pow` 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 13bc9b8082..cd00a4ccdb 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -212,6 +212,14 @@ impl Decimal { }) } + /// Raises a value to the power of `exp`, panics if an overflow occurred. + pub fn pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => panic!("Multiplication overflow"), + } + } + /// Raises a value to the power of `exp`, returning an `OverflowError` if an overflow occurred. pub fn checked_pow(self, exp: u32) -> Result { // This uses the exponentiation by squaring algorithm: @@ -245,6 +253,14 @@ 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()) } @@ -1835,4 +1851,25 @@ mod tests { Err(DivideByZeroError { .. }) )); } + + #[test] + fn decimal_pow_works() { + assert_eq!(Decimal::percent(200).pow(2), Decimal::percent(400)); + assert_eq!(Decimal::percent(200).pow(10), Decimal::percent(102400)); + } + + #[test] + #[should_panic] + fn decimal_pow_overflow_panics() { + Decimal::MAX.pow(2u32); + } + + #[test] + fn decimal_saturating_pow() { + assert_eq!( + Decimal::percent(400).saturating_pow(2u32), + Decimal::percent(1600) + ); + assert_eq!(Decimal::MAX.saturating_pow(2u32), Decimal::MAX); + } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index c0f9005f8b..508191c6fa 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -225,6 +225,14 @@ impl Decimal256 { }) } + /// Raises a value to the power of `exp`, panics if an overflow occurred. + pub fn pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Ok(value) => value, + Err(_) => panic!("Multiplication overflow"), + } + } + /// Raises a value to the power of `exp`, returning an `OverflowError` if an overflow occurred. pub fn checked_pow(self, exp: u32) -> Result { // This uses the exponentiation by squaring algorithm: @@ -258,6 +266,14 @@ 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()) } @@ -1982,4 +1998,28 @@ mod tests { Err(DivideByZeroError { .. }) )); } + + #[test] + fn decimal256_pow_works() { + assert_eq!(Decimal256::percent(200).pow(2), Decimal256::percent(400)); + assert_eq!( + Decimal256::percent(200).pow(10), + Decimal256::percent(102400) + ); + } + + #[test] + #[should_panic] + fn decimal256_pow_overflow_panics() { + Decimal256::MAX.pow(2u32); + } + + #[test] + fn decimal256_saturating_pow() { + assert_eq!( + Decimal256::percent(400).saturating_pow(2u32), + Decimal256::percent(1600) + ); + assert_eq!(Decimal256::MAX.saturating_pow(2u32), Decimal256::MAX); + } }