From 66c645a7fb6e78bebde5ab0b336307b55b80f6d4 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Fri, 8 Jul 2022 15:55:01 +0200 Subject: [PATCH 1/5] Decimal/256: Implement saturating_pow --- packages/std/src/math/decimal.rs | 8 ++++++++ packages/std/src/math/decimal256.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 3d88fc0f56..5aa3d72fab 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -297,6 +297,14 @@ impl Decimal { .map_err(|_| DivideByZeroError::new(self)) } + /// 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, + } + } + /// Returns the approximate square root as a Decimal. /// /// This should not overflow or panic. diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index ede9a0a969..130f30abc6 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -310,6 +310,14 @@ impl Decimal256 { .map_err(|_| DivideByZeroError::new(self)) } + /// 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, + } + } + /// Returns the approximate square root as a Decimal256. /// /// This should not overflow or panic. From 189d9a3a3b026609c9ea3db5486441f4418ac352 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Fri, 8 Jul 2022 16:29:44 +0200 Subject: [PATCH 2/5] Decimal/256: Implement saturating_add/sub/mul --- packages/std/src/math/decimal.rs | 58 +++++++++++++++++++---------- packages/std/src/math/decimal256.rs | 58 +++++++++++++++++++---------- 2 files changed, 78 insertions(+), 38 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 5aa3d72fab..9de42e9d53 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()) } @@ -297,14 +289,6 @@ impl Decimal { .map_err(|_| DivideByZeroError::new(self)) } - /// 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, - } - } - /// Returns the approximate square root as a Decimal. /// /// This should not overflow or panic. @@ -340,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 { @@ -1898,10 +1910,18 @@ mod tests { } #[test] - fn decimal_saturating_pow() { + fn decimal_saturating_works() { assert_eq!( - Decimal::percent(400).saturating_pow(2u32), - Decimal::percent(1600) + Decimal::MAX.saturating_add(Decimal::percent(200)), + Decimal::MAX + ); + assert_eq!( + Decimal::zero().saturating_sub(Decimal::percent(200)), + Decimal::zero() + ); + assert_eq!( + Decimal::MAX.saturating_mul(Decimal::percent(200)), + Decimal::MAX ); 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 130f30abc6..fa4e1b0cd6 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()) } @@ -310,14 +302,6 @@ impl Decimal256 { .map_err(|_| DivideByZeroError::new(self)) } - /// 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, - } - } - /// Returns the approximate square root as a Decimal256. /// /// This should not overflow or panic. @@ -357,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 { @@ -2048,10 +2060,18 @@ mod tests { } #[test] - fn decimal256_saturating_pow() { + fn decimal256_saturating_works() { assert_eq!( - Decimal256::percent(400).saturating_pow(2u32), - Decimal256::percent(1600) + Decimal256::MAX.saturating_add(Decimal256::percent(200)), + Decimal256::MAX + ); + assert_eq!( + Decimal256::zero().saturating_sub(Decimal256::percent(200)), + Decimal256::zero() + ); + assert_eq!( + Decimal256::MAX.saturating_mul(Decimal256::percent(200)), + Decimal256::MAX ); assert_eq!(Decimal256::MAX.saturating_pow(2u32), Decimal256::MAX); } From df379636bed70024e8d56e795e90346a4c4f285e Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Fri, 8 Jul 2022 16:37:41 +0200 Subject: [PATCH 3/5] Uint256/512: Implement saturating_pow --- packages/std/src/math/uint128.rs | 4 ++-- packages/std/src/math/uint256.rs | 8 ++++++++ packages/std/src/math/uint512.rs | 8 ++++++++ packages/std/src/math/uint64.rs | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) 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..14a0504c54 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,7 @@ mod tests { Uint256::MAX.saturating_mul(Uint256::from(2u32)), Uint256::MAX ); + 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..bb7211367d 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,7 @@ mod tests { Uint512::MAX.saturating_mul(Uint512::from(2u32)), Uint512::MAX ); + 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 { From a2d98971a3fbe086c55993895594eb61b36140dd Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Fri, 8 Jul 2022 16:40:39 +0200 Subject: [PATCH 4/5] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af7a4f1f2c..ae9f3659a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ 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 From 5bfe2d1f64a702db2309fbab960c4c12021f29b8 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Fri, 8 Jul 2022 16:53:25 +0200 Subject: [PATCH 5/5] Fix formatting in CHANGELOG; add more cases to saturating_ tests to increase coverage --- CHANGELOG.md | 3 ++- packages/std/src/math/decimal.rs | 16 ++++++++++++++++ packages/std/src/math/decimal256.rs | 16 ++++++++++++++++ packages/std/src/math/uint256.rs | 4 ++++ packages/std/src/math/uint512.rs | 4 ++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae9f3659a5..70c570d7cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +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`. +- 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 9de42e9d53..826f06d502 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -1911,18 +1911,34 @@ mod tests { #[test] 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) + ); 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 fa4e1b0cd6..ce76ccb87d 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -2061,18 +2061,34 @@ mod tests { #[test] 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) + ); assert_eq!(Decimal256::MAX.saturating_pow(2u32), Decimal256::MAX); } diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 14a0504c54..57b3b78c13 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -1472,6 +1472,10 @@ 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); } diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index bb7211367d..40e2e55ff5 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -1107,6 +1107,10 @@ 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); }