diff --git a/CHANGELOG.md b/CHANGELOG.md index e4123a67dd..e15bac5a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add `abs` and `unsigned_abs` for `Int{64,128,256,512}` + ([#1854]). + +[#1854]: https://github.com/CosmWasm/cosmwasm/pull/1854 + ## [1.4.0] - 2023-09-04 ### Added diff --git a/packages/std/src/math/int128.rs b/packages/std/src/math/int128.rs index cc0b7c83b5..1eb62c3f10 100644 --- a/packages/std/src/math/int128.rs +++ b/packages/std/src/math/int128.rs @@ -209,6 +209,16 @@ impl Int128 { pub const fn abs_diff(self, other: Self) -> Uint128 { Uint128(self.0.abs_diff(other.0)) } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn abs(self) -> Self { + Self(self.0.abs()) + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn unsigned_abs(self) -> Uint128 { + Uint128(self.0.unsigned_abs()) + } } impl From for Int128 { @@ -1088,6 +1098,37 @@ mod tests { assert_eq!(c.abs_diff(b), Uint128::from(10u32)); } + #[test] + fn int128_abs_works() { + let a = Int128::from(42i32); + assert_eq!(a.abs(), a); + + let b = Int128::from(-42i32); + assert_eq!(b.abs(), a); + + assert_eq!(Int128::zero().abs(), Int128::zero()); + assert_eq!((Int128::MIN + Int128::one()).abs(), Int128::MAX); + } + + #[test] + fn int128_unsigned_abs_works() { + assert_eq!(Int128::zero().unsigned_abs(), Uint128::zero()); + assert_eq!(Int128::one().unsigned_abs(), Uint128::one()); + assert_eq!( + Int128::MIN.unsigned_abs(), + Uint128::new(Int128::MAX.0 as u128) + Uint128::one() + ); + + let v = Int128::from(-42i32); + assert_eq!(v.unsigned_abs(), v.abs_diff(Int128::zero())); + } + + #[test] + #[should_panic = "attempt to negate with overflow"] + fn int128_abs_min_panics() { + _ = Int128::MIN.abs(); + } + #[test] #[should_panic = "attempt to negate with overflow"] fn int128_neg_min_panics() { diff --git a/packages/std/src/math/int256.rs b/packages/std/src/math/int256.rs index 5616fcc2e7..78f9a15af5 100644 --- a/packages/std/src/math/int256.rs +++ b/packages/std/src/math/int256.rs @@ -258,6 +258,16 @@ impl Int256 { pub const fn abs_diff(self, other: Self) -> Uint256 { Uint256(self.0.abs_diff(other.0)) } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn abs(self) -> Self { + Self(self.0.abs()) + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn unsigned_abs(self) -> Uint256 { + Uint256(self.0.unsigned_abs()) + } } impl From for Int256 { @@ -1171,6 +1181,37 @@ mod tests { assert_eq!(c.abs_diff(b), Uint256::from(10u32)); } + #[test] + fn int256_abs_works() { + let a = Int256::from(42i32); + assert_eq!(a.abs(), a); + + let b = Int256::from(-42i32); + assert_eq!(b.abs(), a); + + assert_eq!(Int256::zero().abs(), Int256::zero()); + assert_eq!((Int256::MIN + Int256::one()).abs(), Int256::MAX); + } + + #[test] + fn int256_unsigned_abs_works() { + assert_eq!(Int256::zero().unsigned_abs(), Uint256::zero()); + assert_eq!(Int256::one().unsigned_abs(), Uint256::one()); + assert_eq!( + Int256::MIN.unsigned_abs(), + Uint256::from_be_bytes(Int256::MAX.to_be_bytes()) + Uint256::one() + ); + + let v = Int256::from(-42i32); + assert_eq!(v.unsigned_abs(), v.abs_diff(Int256::zero())); + } + + #[test] + #[should_panic = "attempt to negate with overflow"] + fn int256_abs_min_panics() { + _ = Int256::MIN.abs(); + } + #[test] #[should_panic = "attempt to negate with overflow"] fn int256_neg_min_panics() { diff --git a/packages/std/src/math/int512.rs b/packages/std/src/math/int512.rs index 2b122418e5..6004a6f134 100644 --- a/packages/std/src/math/int512.rs +++ b/packages/std/src/math/int512.rs @@ -294,6 +294,16 @@ impl Int512 { pub const fn abs_diff(self, other: Self) -> Uint512 { Uint512(self.0.abs_diff(other.0)) } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn abs(self) -> Self { + Self(self.0.abs()) + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn unsigned_abs(self) -> Uint512 { + Uint512(self.0.unsigned_abs()) + } } impl From for Int512 { @@ -1224,6 +1234,37 @@ mod tests { assert_eq!(c.abs_diff(b), Uint512::from(10u32)); } + #[test] + fn int512_abs_works() { + let a = Int512::from(42i32); + assert_eq!(a.abs(), a); + + let b = Int512::from(-42i32); + assert_eq!(b.abs(), a); + + assert_eq!(Int512::zero().abs(), Int512::zero()); + assert_eq!((Int512::MIN + Int512::one()).abs(), Int512::MAX); + } + + #[test] + fn int512_unsigned_abs_works() { + assert_eq!(Int512::zero().unsigned_abs(), Uint512::zero()); + assert_eq!(Int512::one().unsigned_abs(), Uint512::one()); + assert_eq!( + Int512::MIN.unsigned_abs(), + Uint512::from_be_bytes(Int512::MAX.to_be_bytes()) + Uint512::one() + ); + + let v = Int512::from(-42i32); + assert_eq!(v.unsigned_abs(), v.abs_diff(Int512::zero())); + } + + #[test] + #[should_panic = "attempt to negate with overflow"] + fn int512_abs_min_panics() { + _ = Int512::MIN.abs(); + } + #[test] #[should_panic = "attempt to negate with overflow"] fn int512_neg_min_panics() { diff --git a/packages/std/src/math/int64.rs b/packages/std/src/math/int64.rs index 2e9ac7f68d..da4bc4f160 100644 --- a/packages/std/src/math/int64.rs +++ b/packages/std/src/math/int64.rs @@ -209,6 +209,16 @@ impl Int64 { pub const fn abs_diff(self, other: Self) -> Uint64 { Uint64(self.0.abs_diff(other.0)) } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn abs(self) -> Self { + Self(self.0.abs()) + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn unsigned_abs(self) -> Uint64 { + Uint64(self.0.unsigned_abs()) + } } impl From for Int64 { @@ -1031,6 +1041,37 @@ mod tests { assert_eq!(c.abs_diff(b), Uint64::from(10u32)); } + #[test] + fn int64_abs_works() { + let a = Int64::from(42i32); + assert_eq!(a.abs(), a); + + let b = Int64::from(-42i32); + assert_eq!(b.abs(), a); + + assert_eq!(Int64::zero().abs(), Int64::zero()); + assert_eq!((Int64::MIN + Int64::one()).abs(), Int64::MAX); + } + + #[test] + fn int64_unsigned_abs_works() { + assert_eq!(Int64::zero().unsigned_abs(), Uint64::zero()); + assert_eq!(Int64::one().unsigned_abs(), Uint64::one()); + assert_eq!( + Int64::MIN.unsigned_abs(), + Uint64::new(Int64::MAX.0 as u64) + Uint64::one() + ); + + let v = Int64::from(-42i32); + assert_eq!(v.unsigned_abs(), v.abs_diff(Int64::zero())); + } + + #[test] + #[should_panic = "attempt to negate with overflow"] + fn int64_abs_min_panics() { + _ = Int64::MIN.abs(); + } + #[test] #[should_panic = "attempt to negate with overflow"] fn int64_neg_min_panics() {