From 0bc87c943c6f9d394b1a6c28ffe53e08ae63e2a8 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Tue, 28 Jun 2022 22:28:27 +0200 Subject: [PATCH 1/5] Decimal: Implement rem/rem_assign --- packages/std/src/math/decimal.rs | 58 +++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 47de1baf48..ec83efbdf5 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -3,7 +3,7 @@ use schemars::JsonSchema; use serde::{de, ser, Deserialize, Deserializer, Serialize}; use std::cmp::Ordering; use std::fmt::{self, Write}; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign}; use std::str::FromStr; use thiserror::Error; @@ -481,6 +481,26 @@ impl DivAssign for Decimal { } } +impl Rem for Decimal { + type Output = Self; + + /// # Panics + /// + /// This operation will panic if `rhs` is zero + #[inline] + fn rem(self, rhs: Self) -> Self { + Self(self.0.rem(rhs.0)) + } +} +forward_ref_binop!(impl Rem, rem for Decimal, Decimal); + +impl RemAssign for Decimal { + fn rem_assign(&mut self, rhs: Decimal) { + *self = *self % rhs; + } +} +forward_ref_op_assign!(impl RemAssign, rem_assign for Decimal, Decimal); + impl std::iter::Sum for Decimal where Self: Add, @@ -1679,4 +1699,40 @@ mod tests { assert_eq!(a.abs_diff(b), expected); assert_eq!(b.abs_diff(a), expected); } + + #[test] + #[allow(clippy::op_ref)] + fn decimal_rem_works() { + // 4.02 % 1.11 = 0.69 + assert_eq!( + Decimal::percent(402) % Decimal::percent(111), + Decimal::percent(69) + ); + + // 15.25 % 4 = 3.25 + assert_eq!( + Decimal::percent(1525) % Decimal::percent(400), + Decimal::percent(325) + ); + + let a = Decimal::percent(318); + let b = Decimal::percent(317); + let expected = Decimal::percent(1); + assert_eq!(a % b, expected); + assert_eq!(a % &b, expected); + assert_eq!(&a % b, expected); + assert_eq!(&a % &b, expected); + } + + #[test] + fn decimal_rem_assign_works() { + let mut a = Decimal::percent(17673); + a %= Decimal::percent(2362); + assert_eq!(a, Decimal::percent(1139)); // 176.73 % 23.62 = 11.39 + + let mut a = Decimal::percent(4262); + let b = Decimal::percent(1270); + a %= &b; + assert_eq!(a, Decimal::percent(452)); // 42.62 % 12.7 = 4.52 + } } From 37724d6fc39a5c905c054b880e6f586dda770197 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Tue, 28 Jun 2022 22:32:12 +0200 Subject: [PATCH 2/5] Decimal256: Implement rem/rem_assign --- packages/std/src/math/decimal256.rs | 58 ++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 4b76f0721a..aee0015a98 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -3,7 +3,7 @@ use schemars::JsonSchema; use serde::{de, ser, Deserialize, Deserializer, Serialize}; use std::cmp::Ordering; use std::fmt::{self, Write}; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign}; use std::str::FromStr; use thiserror::Error; @@ -505,6 +505,26 @@ impl DivAssign for Decimal256 { } } +impl Rem for Decimal256 { + type Output = Self; + + /// # Panics + /// + /// This operation will panic if `rhs` is zero + #[inline] + fn rem(self, rhs: Self) -> Self { + Self(self.0.rem(rhs.0)) + } +} +forward_ref_binop!(impl Rem, rem for Decimal256, Decimal256); + +impl RemAssign for Decimal256 { + fn rem_assign(&mut self, rhs: Decimal256) { + *self = *self % rhs; + } +} +forward_ref_op_assign!(impl RemAssign, rem_assign for Decimal256, Decimal256); + impl std::iter::Sum for Decimal256 where Self: Add, @@ -1825,4 +1845,40 @@ mod tests { assert_eq!(a.abs_diff(b), expected); assert_eq!(b.abs_diff(a), expected); } + + #[test] + #[allow(clippy::op_ref)] + fn decimal256_rem_works() { + // 4.02 % 1.11 = 0.69 + assert_eq!( + Decimal256::percent(402) % Decimal256::percent(111), + Decimal256::percent(69) + ); + + // 15.25 % 4 = 3.25 + assert_eq!( + Decimal256::percent(1525) % Decimal256::percent(400), + Decimal256::percent(325) + ); + + let a = Decimal256::percent(318); + let b = Decimal256::percent(317); + let expected = Decimal256::percent(1); + assert_eq!(a % b, expected); + assert_eq!(a % &b, expected); + assert_eq!(&a % b, expected); + assert_eq!(&a % &b, expected); + } + + #[test] + fn decimal_rem_assign_works() { + let mut a = Decimal256::percent(17673); + a %= Decimal256::percent(2362); + assert_eq!(a, Decimal256::percent(1139)); // 176.73 % 23.62 = 11.39 + + let mut a = Decimal256::percent(4262); + let b = Decimal256::percent(1270); + a %= &b; + assert_eq!(a, Decimal256::percent(452)); // 42.62 % 12.7 = 4.52 + } } From 33faa6cefc5029156b13db96cfd3c77e062b473b Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Tue, 28 Jun 2022 22:33:04 +0200 Subject: [PATCH 3/5] Remove AllImplDecimal --- packages/std/src/math/mod.rs | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/packages/std/src/math/mod.rs b/packages/std/src/math/mod.rs index 031999934e..706d23005d 100644 --- a/packages/std/src/math/mod.rs +++ b/packages/std/src/math/mod.rs @@ -54,37 +54,6 @@ mod tests { impl AllImpl<'_> for Uint128 {} impl AllImpl<'_> for Uint256 {} impl AllImpl<'_> for Uint512 {} - - // TODO: When all implementations are done, extra trait can be removed and - // unified with AllImpl - trait AllImplDecimal<'a>: - Add - + Add<&'a Self> - + AddAssign - + AddAssign<&'a Self> - + Sub - + Sub<&'a Self> - + SubAssign - + SubAssign<&'a Self> - + Mul - + Mul<&'a Self> - + MulAssign - + MulAssign<&'a Self> - + Div - + Div<&'a Self> - + DivAssign - + DivAssign<&'a Self> - // + Rem - // + Rem<&'a Self> - // + RemAssign - // + RemAssign<&'a Self> - + Sized - + Copy - where - Self: 'a, - { - } - - impl AllImplDecimal<'_> for Decimal {} - impl AllImplDecimal<'_> for Decimal256 {} + impl AllImpl<'_> for Decimal {} + impl AllImpl<'_> for Decimal256 {} } From 82a457ca2df52950b739df0ff014005ab042dd12 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Tue, 28 Jun 2022 22:40:03 +0200 Subject: [PATCH 4/5] Decimal/256: Tests for Rem panicking at division by zero --- packages/std/src/math/decimal.rs | 6 ++++++ packages/std/src/math/decimal256.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index ec83efbdf5..ed3284b09b 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -1735,4 +1735,10 @@ mod tests { a %= &b; assert_eq!(a, Decimal::percent(452)); // 42.62 % 12.7 = 4.52 } + + #[test] + #[should_panic(expected = "divisor of zero")] + fn decimal_rem_panics_for_zero() { + let _ = Decimal::percent(777) % Decimal::zero(); + } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index aee0015a98..e98ed8fea5 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -1881,4 +1881,10 @@ mod tests { a %= &b; assert_eq!(a, Decimal256::percent(452)); // 42.62 % 12.7 = 4.52 } + + #[test] + #[should_panic(expected = "division by zero")] + fn decimal256_rem_panics_for_zero() { + let _ = Decimal256::percent(777) % Decimal256::zero(); + } } From d2717a9f7d73d3a43d49ed79a602e4c7750f3247 Mon Sep 17 00:00:00 2001 From: Jakub Bogucki Date: Wed, 29 Jun 2022 10:33:49 +0200 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a816c20757..a41b566e61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to - cosmwasm-std: Add `Uint{64,128,256,512}::abs_diff` and `Decimal{,256}::abs_diff` ([#1334]). - cosmwasm-std: Implement `From for Decimal256`. +- cosmwasm-std: Implement `Rem`/`RemAssign` for `Decimal`/`Decimal256`. [#1334]: https://github.com/CosmWasm/cosmwasm/pull/1334