diff --git a/README.md b/README.md index 18ec9f1..649b55d 100644 --- a/README.md +++ b/README.md @@ -95,10 +95,18 @@ The conversions supported cover the following cases. * Fixed-point numbers can now be formatted as hexadecimal with [`Debug`] similarly to primitive integers, for example formatting with `{:X?}` will produce upper-case hexadecimal fixed-point numbers. - * The following method was added to all fixed-point numbers, to the + * The following methods were added to all fixed-point numbers, to the [`Fixed`][tf-1-9] trait, and to the [`Wrapping`][w-1-9] and [`Unwrapped`][u-1-9] wrappers: * [`is_zero`][f-iz-1-9] + * [`distance`][f-d-1-9] + * The following methods were added to all fixed-point numbers and to the + [`Fixed`][tf-1-9] trait: + * [`checked_distance`][f-cd-1-9], [`saturating_distance`][f-sd-1-9], + [`wrapping_distance`][f-wd-1-9], [`unwrapped_distance`][f-ud-1-9], + [`overflowing_distance`][f-od-1-9] + * The [`unsigned_distance`][f-ud-1-9] method was added to all signed + fixed-point types and to the [`FixedSigned`][tfs-1-9] trait. * The following associated types were added to the [`Fixed`][tf-1-9] trait: * [`Signed`][tf-s-1-9], [`Unsigned`][tf-u-1-9] * The following traits from the [*bytemuck* crate] were implemented for all @@ -127,7 +135,14 @@ The conversions supported cover the following cases. [bm-p-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.Pod.html [bm-tw-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.TransparentWrapper.html [bm-z-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.Zeroable.html +[f-cd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.checked_distance +[f-d-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.distance [f-iz-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.is_zero +[f-od-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.overflowing_distance +[f-sd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.saturating_distance +[f-ud-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.unwrapped_distance +[f-unsd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.unsigned_distance +[f-wd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.wrapping_distance [fof-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.FixedOptionalFeatures.html [leu128-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.LeEqU128.html [leu16-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.LeEqU16.html @@ -137,6 +152,7 @@ The conversions supported cover the following cases. [tf-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html [tf-s-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html#associatedtype.Signed [tf-u-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html#associatedtype.Unsigned +[tfs-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.FixedSigned.html [u-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.Unwrapped.html [uns-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.Unsigned.html [w-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.Wrapping.html diff --git a/RELEASES.md b/RELEASES.md index e2a618c..b39f15d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,10 +11,18 @@ Version 1.9.0 (unreleased) * Fixed-point numbers can now be formatted as hexadecimal with [`Debug`] similarly to primitive integers, for example formatting with `{:X?}` will produce upper-case hexadecimal fixed-point numbers. - * The following method was added to all fixed-point numbers, to the + * The following methods were added to all fixed-point numbers, to the [`Fixed`][tf-1-9] trait, and to the [`Wrapping`][w-1-9] and [`Unwrapped`][u-1-9] wrappers: * [`is_zero`][f-iz-1-9] + * [`distance`][f-d-1-9] + * The following methods were added to all fixed-point numbers and to the + [`Fixed`][tf-1-9] trait: + * [`checked_distance`][f-cd-1-9], [`saturating_distance`][f-sd-1-9], + [`wrapping_distance`][f-wd-1-9], [`unwrapped_distance`][f-ud-1-9], + [`overflowing_distance`][f-od-1-9] + * The [`unsigned_distance`][f-ud-1-9] method was added to all signed + fixed-point types and to the [`FixedSigned`][tfs-1-9] trait. * The following associated types were added to the [`Fixed`][tf-1-9] trait: * [`Signed`][tf-s-1-9], [`Unsigned`][tf-u-1-9] * The following traits from the [*bytemuck* crate] were implemented for all @@ -43,7 +51,14 @@ Compatibility notes [bm-p-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.Pod.html [bm-tw-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.TransparentWrapper.html [bm-z-1]: https://docs.rs/bytemuck/^1/bytemuck/trait.Zeroable.html +[f-cd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.checked_distance +[f-d-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.distance [f-iz-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.is_zero +[f-od-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.overflowing_distance +[f-sd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.saturating_distance +[f-ud-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.unwrapped_distance +[f-unsd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.unsigned_distance +[f-wd-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.wrapping_distance [fof-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.FixedOptionalFeatures.html [leu128-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.LeEqU128.html [leu16-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.LeEqU16.html @@ -53,6 +68,7 @@ Compatibility notes [tf-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html [tf-s-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html#associatedtype.Signed [tf-u-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.Fixed.html#associatedtype.Unsigned +[tfs-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.FixedSigned.html [u-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.Unwrapped.html [uns-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/types/extra/trait.Unsigned.html [w-1-9]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.Wrapping.html diff --git a/src/macros_no_frac.rs b/src/macros_no_frac.rs index 1ffd44f..0f1ee25 100644 --- a/src/macros_no_frac.rs +++ b/src/macros_no_frac.rs @@ -922,6 +922,114 @@ assert_eq!(Fix::MIN.unsigned_abs(), min_as_unsigned); } } + comment! { + "Returns the distance from `self` to `other`. + +The distance is the absolute value of the difference. + +", + if_signed_else_empty_str! { + $Signedness; + "# Panics + +When debug assertions are enabled, this method panics if the result overflows. +When debug assertions are not enabled, the wrapped value can be returned, but it +is not considered a breaking change if in the future it panics; if wrapping is +required use [`wrapping_distance`] instead. +", + }, + "# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::ONE.distance(Fix::from_num(5)), Fix::from_num(4)); +", + if_signed_else_empty_str! { + $Signedness; + "assert_eq!(Fix::from_num(-1).distance(Fix::from_num(2)), Fix::from_num(3)); +", + }, + "``` +", + if_signed_else_empty_str! { + $Signedness; + " +[`wrapping_distance`]: Self::wrapping_distance +" + }; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn distance(self, other: $Fixed) -> $Fixed { + let s = self.to_bits(); + let o = other.to_bits(); + let d = if s < o { o - s } else { s - o }; + Self::from_bits(d) + } + } + + if_signed! { + $Signedness; + comment! { + "Returns the distance from `self` to `other` using an +unsigned type without any wrapping or panicking. + +The distance is the absolute value of the difference. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, ", ", $s_ufixed, "}; +type Fix = ", $s_fixed, "; +type UFix = ", $s_ufixed, "; +assert_eq!(Fix::from_num(-1).unsigned_distance(Fix::from_num(2)), UFix::from_num(3)); +assert_eq!(Fix::MIN.unsigned_distance(Fix::MAX), UFix::MAX); +``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn unsigned_distance(self, other: $Fixed) -> $UFixed { + let s = self.to_bits(); + let o = other.to_bits(); + let d = if s < o { + o.wrapping_sub(s) + } else { + s.wrapping_sub(o) + }; + $UFixed::from_bits(d as $UInner) + } + } + } + + comment! { + "Returns the mean of `self` and `other`. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::from_num(3).mean(Fix::from_num(4)), Fix::from_num(3.5)); +", + if_signed_else_empty_str! { + $Signedness; + "assert_eq!(Fix::from_num(-3).mean(Fix::from_num(4)), Fix::from_num(0.5)); +", + }, + "``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn mean(self, other: $Fixed) -> $Fixed { + // a & b == common bits + // a ^ b == different bits + // a + b == 2 * (a & b) + (a ^ b) + // (a + b) / 2 = (a & b) + (a ^ b) / 2 + let (a, b) = (self.to_bits(), other.to_bits()); + $Fixed::from_bits((a & b) + ((a ^ b) >> 1)) + } + } + if_unsigned! { $Signedness; comment! { @@ -986,35 +1094,6 @@ assert_eq!(Fix::from_num(6.5).next_power_of_two(), Fix::from_num(8)); } } - comment! { - "Returns the mean of `self` and `other`. - -# Examples - -```rust -use fixed::{types::extra::U4, ", $s_fixed, "}; -type Fix = ", $s_fixed, "; -assert_eq!(Fix::from_num(3).mean(Fix::from_num(4)), Fix::from_num(3.5)); -", - if_signed_else_empty_str! { - $Signedness; - "assert_eq!(Fix::from_num(-3).mean(Fix::from_num(4)), Fix::from_num(0.5)); -", - }, - "``` -"; - #[inline] - #[must_use = "this returns the result of the operation, without modifying the original"] - pub const fn mean(self, other: $Fixed) -> $Fixed { - // a & b == common bits - // a ^ b == different bits - // a + b == 2 * (a & b) + (a ^ b) - // (a + b) / 2 = (a & b) + (a ^ b) / 2 - let (a, b) = (self.to_bits(), other.to_bits()); - $Fixed::from_bits((a & b) + ((a ^ b) >> 1)) - } - } - comment! { "Bitwise NOT. Usable in constant context. @@ -1492,6 +1571,53 @@ assert_eq!(Fix::MIN.checked_abs(), None); } } + comment! { + "Checked distance. Returns the distance from `self` to `other`", + if_signed_else_empty_str! { $Signedness; ", or [`None`] on overflow" }, + ". + +The distance is the absolute value of the difference. + +", + if_unsigned_else_empty_str! { + $Signedness; + "Can never overflow for unsigned types. + +", + }, + "# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::ONE.checked_distance(Fix::from_num(5)), Some(Fix::from_num(4))); +", + if_signed_unsigned!( + $Signedness, + "assert_eq!(Fix::MIN.checked_distance(Fix::ZERO), None);", + "assert_eq!(Fix::ZERO.checked_distance(Fix::MAX), Some(Fix::MAX));", + ), + " +``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn checked_distance(self, other: $Fixed) -> Option<$Fixed> { + if_signed! { + $Signedness; + if self.to_bits() < other.to_bits() { + other.checked_sub(self) + } else { + self.checked_sub(other) + } + } + if_unsigned! { + $Signedness; + Some(self.distance(other)) + } + } + } + if_unsigned! { $Signedness; comment! { @@ -1603,7 +1729,7 @@ type Fix = ", $s_fixed, "; "assert_eq!(Fix::ONE.saturating_sub(Fix::from_num(3)), Fix::from_num(-2)); assert_eq!(Fix::MIN.saturating_sub(Fix::ONE), Fix::MIN);", "assert_eq!(Fix::from_num(5).saturating_sub(Fix::from_num(3)), Fix::from_num(2)); -assert_eq!(Fix::ZERO.saturating_sub(Fix::from_num(1)), Fix::from_num(0));", +assert_eq!(Fix::ZERO.saturating_sub(Fix::ONE), Fix::ZERO);", ), " ``` @@ -1748,6 +1874,52 @@ assert_eq!(Fix::MIN.saturating_abs(), Fix::MAX); } } + comment! { + "Saturating distance. Returns the distance from `self` to `other`", + if_signed_else_empty_str! { $Signedness; ", saturating on overflow" }, + ". + +The distance is the absolute value of the difference. + +", + if_unsigned_else_empty_str! { + $Signedness; + "Can never overflow for unsigned types. + +", + }, + "# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::ONE.saturating_distance(Fix::from_num(5)), Fix::from_num(4)); +", + if_signed_unsigned!( + $Signedness, + "assert_eq!(Fix::MIN.saturating_distance(Fix::MAX), Fix::MAX);", + "assert_eq!(Fix::ZERO.saturating_distance(Fix::MAX), Fix::MAX);", + ), + " +``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn saturating_distance(self, other: $Fixed) -> $Fixed { + if_signed! { + $Signedness; + match self.checked_distance(other) { + None => $Fixed::MAX, + Some(dist) => dist, + } + } + if_unsigned! { + $Signedness; + self.distance(other) + } + } + } + comment! { "Wrapping negation. Returns the negated value, wrapping on overflow. @@ -1995,6 +2167,46 @@ assert_eq!(Fix::MIN.wrapping_abs(), Fix::MIN); } } + comment! { + "Wrapping distance. Returns the distance from `self` to `other`", + if_signed_else_empty_str! { $Signedness; ", wrapping on overflow" }, + ". + +The distance is the absolute value of the difference. + +", + if_unsigned_else_empty_str! { + $Signedness; + "Can never overflow for unsigned types. + +", + }, + "# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::ONE.wrapping_distance(Fix::from_num(5)), Fix::from_num(4)); +", + if_signed_unsigned!( + $Signedness, + "assert_eq!(Fix::MIN.wrapping_distance(Fix::MAX), -Fix::DELTA);", + "assert_eq!(Fix::ZERO.wrapping_distance(Fix::MAX), Fix::MAX);", + ), + " +``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn wrapping_distance(self, other: $Fixed) -> $Fixed { + if_signed_unsigned!( + $Signedness, + self.overflowing_distance(other).0, + self.distance(other), + ) + } + } + if_unsigned! { $Signedness; comment! { @@ -2463,6 +2675,60 @@ let _overflow = Fix::MIN.unwrapped_abs(); } } + comment! { + "Unwrapped distance. Returns the distance from `self` to `other`", + if_signed_else_empty_str! { $Signedness; ", panicking on overflow" }, + ". + +The distance is the absolute value of the difference. + +", + if_signed_unsigned!( + $Signedness, + "# Panics + +Panics if the result does not fit.", + "Can never overflow for unsigned types.", + ), + " + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!(Fix::ONE.unwrapped_distance(Fix::from_num(5)), Fix::from_num(4)); +", + if_unsigned_else_empty_str! { + $Signedness; + "assert_eq!(Fix::ZERO.unwrapped_distance(Fix::MAX), Fix::MAX); +" + }, + "``` +", + if_signed_else_empty_str! { + $Signedness; + " +The following panics because of overflow. + +```should_panic +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +let _overflow = Fix::MIN.unwrapped_distance(Fix::ZERO); +``` +" + }; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn unwrapped_distance(self, other: $Fixed) -> $Fixed { + if_signed_unsigned!( + $Signedness, + self.checked_distance(other).expect("overflow"), + self.distance(other), + ) + } + } + if_unsigned! { $Signedness; comment! { @@ -2810,6 +3076,65 @@ assert_eq!(Fix::MIN.overflowing_abs(), (Fix::MIN, true)); } } } + + comment! { + "Overflowing distance. + +Returns a [tuple] of the distance from `self` to `other` and ", + if_signed_unsigned!( + $Signedness, + "a [`bool`] indicating whether an overflow has +occurred. On overflow, the wrapped value is returned.", + "[`false`], as overflow can never happen for unsigned types.", + ), + " + +The distance is the absolute value of the difference. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::ONE.overflowing_distance(Fix::from_num(5)), + (Fix::from_num(4), false) +); +", + if_signed_unsigned!( + $Signedness, + "assert_eq!( + Fix::MIN.overflowing_distance(Fix::MAX), + (-Fix::DELTA, true) +);", + "assert_eq!( + Fix::ZERO.overflowing_distance(Fix::MAX), + (Fix::MAX, false) +);", + ), + " +``` +"; + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn overflowing_distance( + self, + other: $Fixed, + ) -> ($Fixed, bool) { + if_signed! { + $Signedness; + if self.to_bits() < other.to_bits() { + other.overflowing_sub(self) + } else { + self.overflowing_sub(other) + } + } + if_unsigned! { + $Signedness; + (self.distance(other), false) + } + } + } } }; } diff --git a/src/traits.rs b/src/traits.rs index b1b1c79..a5b34e3 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1199,6 +1199,13 @@ where /// FixedU32::[is\_zero][FixedU32::is_zero]. fn is_zero(self) -> bool; + /// Returns the distance from `self` to `other`. + /// + /// See also FixedI32::[distance][FixedI32::distance] and + /// FixedU32::[distance][FixedU32::distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn distance(self, other: Self) -> Self; + /// Returns the mean of `self` and `other`. /// /// See also FixedI32::[mean][FixedI32::mean] and @@ -1449,6 +1456,16 @@ where #[must_use = "this returns the result of the operation, without modifying the original"] fn checked_shr(self, rhs: u32) -> Option; + /// Checked distance. Returns the distance from `self` to `other`, or + /// [`None`] on overflow. + /// + /// See also + /// FixedI32::[checked\_distance][FixedI32::checked_distance] + /// and + /// FixedU32::[checked\_distance][FixedU32::checked_distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn checked_distance(self, other: Self) -> Option; + /// Saturated negation. Returns the negated value, saturating on overflow. /// /// See also @@ -1571,6 +1588,16 @@ where #[must_use = "this returns the result of the operation, without modifying the original"] fn saturating_rem_euclid_int(self, rhs: Self::Bits) -> Self; + /// Saturating distance. Returns the distance from `self` to `other`, + /// saturating on overflow. + /// + /// See also + /// FixedI32::[saturating\_distance][FixedI32::saturating_distance] + /// and + /// FixedU32::[saturating\_distance][FixedU32::saturating_distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn saturating_distance(self, other: Self) -> Self; + /// Wrapping negation. Returns the negated value, wrapping on overflow. /// /// See also FixedI32::[wrapping\_neg][FixedI32::wrapping_neg] @@ -1720,6 +1747,16 @@ where #[must_use = "this returns the result of the operation, without modifying the original"] fn wrapping_shr(self, rhs: u32) -> Self; + /// Wrapping distance. Returns the distance from `self` to `other`, wrapping + /// on overflow. + /// + /// See also + /// FixedI32::[wrapping\_distance][FixedI32::wrapping_distance] + /// and + /// FixedU32::[wrapping\_distance][FixedU32::wrapping_distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn wrapping_distance(self, other: Self) -> Self; + /// Unwrapped negation. Returns the negated value, panicking on overflow. /// /// See also @@ -1968,6 +2005,20 @@ where #[must_use = "this returns the result of the operation, without modifying the original"] fn unwrapped_shr(self, rhs: u32) -> Self; + /// Unwrapped distance. Returns the distance from `self` to `other`, + /// panicking on overflow. + /// + /// # Panics + /// + /// Panics if the result does not fit. + /// + /// See also + /// FixedI32::[unwrapped\_distance][FixedI32::unwrapped_distance] + /// and + /// FixedU32::[unwrapped\_distance][FixedU32::unwrapped_distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn unwrapped_distance(self, other: Self) -> Self; + /// Overflowing negation. /// /// Returns a [tuple] of the negated value and a [`bool`], @@ -2174,6 +2225,19 @@ where /// FixedU32::[overflowing\_shr][FixedU32::overflowing_shr]. #[must_use = "this returns the result of the operation, without modifying the original"] fn overflowing_shr(self, rhs: u32) -> (Self, bool); + + /// Overflowing distance. + /// + /// Returns a [tuple] of the distance from `self` to `other` and a [`bool`], + /// indicating whether an overflow has occurred. On overflow, the wrapped + /// value is returned. + /// + /// See also + /// FixedI32::[overflowing\_distance][FixedI32::overflowing_distance] + /// and + /// FixedU32::[overflowing\_distance][FixedU32::overflowing_distance]. + #[must_use = "this returns the result of the operation, without modifying the original"] + fn overflowing_distance(self, other: Self) -> (Self, bool); } /// This trait provides methods common to all signed fixed-point numbers. @@ -2214,6 +2278,13 @@ where /// See also FixedI32::[unsigned\_abs][FixedI32::unsigned_abs]. fn unsigned_abs(self) -> Self::Unsigned; + /// Returns the distance from `self` to `other` using an unsigned type + /// without any wrapping or panicking. + /// + /// See also + /// FixedI32::[unsigned\_distance][FixedI32::unsigned_distance]. + fn unsigned_distance(self, other: Self) -> Self::Unsigned; + /// Returns a number representing the sign of `self`. /// /// See also FixedI32::[signum][FixedI32::signum]. @@ -3296,6 +3367,7 @@ macro_rules! impl_fixed { trait_delegate! { fn rotate_left(self, n: u32) -> Self } trait_delegate! { fn rotate_right(self, n: u32) -> Self } trait_delegate! { fn is_zero(self) -> bool } + trait_delegate! { fn distance(self, other: Self) -> Self } trait_delegate! { fn mean(self, other: Self) -> Self } trait_delegate! { fn recip(self) -> Self } trait_delegate! { fn mul_add(self, mul: Self, add: Self) -> Self } @@ -3322,6 +3394,7 @@ macro_rules! impl_fixed { trait_delegate! { fn checked_rem_euclid_int(self, rhs: Self::Bits) -> Option } trait_delegate! { fn checked_shl(self, rhs: u32) -> Option } trait_delegate! { fn checked_shr(self, rhs: u32) -> Option } + trait_delegate! { fn checked_distance(self, other: Self) -> Option } trait_delegate! { fn saturating_neg(self) -> Self } trait_delegate! { fn saturating_add(self, rhs: Self) -> Self } trait_delegate! { fn saturating_sub(self, rhs: Self) -> Self } @@ -3334,6 +3407,7 @@ macro_rules! impl_fixed { trait_delegate! { fn saturating_mul_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn saturating_div_euclid_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn saturating_rem_euclid_int(self, rhs: Self::Bits) -> Self } + trait_delegate! { fn saturating_distance(self, other: Self) -> Self } trait_delegate! { fn wrapping_neg(self) -> Self } trait_delegate! { fn wrapping_add(self, rhs: Self) -> Self } trait_delegate! { fn wrapping_sub(self, rhs: Self) -> Self } @@ -3349,6 +3423,7 @@ macro_rules! impl_fixed { trait_delegate! { fn wrapping_rem_euclid_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn wrapping_shl(self, rhs: u32) -> Self } trait_delegate! { fn wrapping_shr(self, rhs: u32) -> Self } + trait_delegate! { fn wrapping_distance(self, other: Self) -> Self } trait_delegate! { fn unwrapped_neg(self) -> Self } trait_delegate! { fn unwrapped_add(self, rhs: Self) -> Self } trait_delegate! { fn unwrapped_sub(self, rhs: Self) -> Self } @@ -3367,6 +3442,7 @@ macro_rules! impl_fixed { trait_delegate! { fn unwrapped_rem_euclid_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn unwrapped_shl(self, rhs: u32) -> Self } trait_delegate! { fn unwrapped_shr(self, rhs: u32) -> Self } + trait_delegate! { fn unwrapped_distance(self, other: Self) -> Self } trait_delegate! { fn overflowing_neg(self) -> (Self, bool) } trait_delegate! { fn overflowing_add(self, rhs: Self) -> (Self, bool) } trait_delegate! { fn overflowing_sub(self, rhs: Self) -> (Self, bool) } @@ -3382,6 +3458,7 @@ macro_rules! impl_fixed { trait_delegate! { fn overflowing_rem_euclid_int(self, rhs: Self::Bits) -> (Self, bool) } trait_delegate! { fn overflowing_shl(self, rhs: u32) -> (Self, bool) } trait_delegate! { fn overflowing_shr(self, rhs: u32) -> (Self, bool) } + trait_delegate! { fn overflowing_distance(self, other: Self) -> (Self, bool) } } impl FromFixed for $Fixed { @@ -3582,6 +3659,7 @@ macro_rules! impl_fixed { trait_delegate! { fn signed_bits(self) -> u32 } trait_delegate! { fn abs(self) -> Self } trait_delegate! { fn unsigned_abs(self) -> Self::Unsigned } + trait_delegate! { fn unsigned_distance(self, other: Self) -> Self::Unsigned } trait_delegate! { fn signum(self) -> Self } trait_delegate! { fn checked_abs(self) -> Option } trait_delegate! { fn checked_signum(self) -> Option } diff --git a/src/unwrapped.rs b/src/unwrapped.rs index 2c81433..66a3efc 100644 --- a/src/unwrapped.rs +++ b/src/unwrapped.rs @@ -995,6 +995,36 @@ impl Unwrapped { self.0.is_zero() } + /// Returns the distance from `self` to `other`. + /// + /// See also FixedI32::[distance][FixedI32::distance] and + /// FixedU32::[distance][FixedU32::distance]. + /// + /// # Panics + /// + /// Panics on overflow. + /// + /// # Examples + /// + /// ```rust + /// use fixed::{types::I16F16, Unwrapped}; + /// type Unwr = Unwrapped; + /// assert_eq!(Unwr::from_num(-1).distance(Unwr::from_num(4)), Unwr::from_num(5)); + /// ``` + /// + /// The following panics because of overflow. + /// + /// ```should_panic + /// use fixed::{types::I16F16, Unwrapped}; + /// type Unwr = Unwrapped; + /// let _overflow = Unwr::MIN.distance(Unwr::ZERO); + /// ``` + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn distance(self, other: Unwrapped) -> Unwrapped { + Unwrapped(self.0.unwrapped_distance(other.0)) + } + /// Returns the mean of `self` and `other`. /// /// See also FixedI32::[mean][FixedI32::mean] and diff --git a/src/wrapping.rs b/src/wrapping.rs index b4b043c..6200ea2 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -943,6 +943,25 @@ impl Wrapping { self.0.is_zero() } + /// Returns the distance from `self` to `other`. + /// + /// See also FixedI32::[distance][FixedI32::distance] and + /// FixedU32::[distance][FixedU32::distance]. + /// + /// # Examples + /// + /// ```rust + /// use fixed::{types::I16F16, Wrapping}; + /// type Wr = Wrapping; + /// assert_eq!(Wr::from_num(-1).distance(Wr::from_num(4)), Wr::from_num(5)); + /// assert_eq!(Wr::MIN.distance(Wr::MAX), -Wr::DELTA); + /// ``` + #[inline] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn distance(self, other: Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_distance(other.0)) + } + /// Returns the mean of `self` and `other`. /// /// See also FixedI32::[mean][FixedI32::mean] and