diff --git a/README.md b/README.md index 61fabda..fbacaa3 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,21 @@ The conversions supported cover the following cases. ### Version 1.3.0 news (unreleased) + * The following methods were added to all fixed-point types and to + the `Fixed` trait: + * [`mul_add`][f-ma-1-3], [`checked_mul_add`][f-cma-1-3], + [`saturating_mul_add`][f-sma-1-3], + [`wrapping_mul_add`][f-wma-1-3], + [`overflowing_mul_add`][f-oma-1-3] * The new experimental feature [`unwrapped`][feat-un-1-3] was added, providing arithmetic methods that panic on overflow even when debug assertions are disabled. +[f-cma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.checked_mul_add +[f-ma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.mul_add +[f-oma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.overflowing_mul_add +[f-sma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.saturating_mul_add +[f-wma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.wrapping_mul_add [feat-un-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/#experimental-optional-features ### Version 1.2.0 news (2020-09-02) diff --git a/RELEASES.md b/RELEASES.md index 46d9fbd..db5d2d2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,10 +8,21 @@ as-is, without any warranty. --> Version 1.3.0 (unreleased) ========================== + * The following methods were added to all fixed-point types and to + the `Fixed` trait: + * [`mul_add`][f-ma-1-3], [`checked_mul_add`][f-cma-1-3], + [`saturating_mul_add`][f-sma-1-3], + [`wrapping_mul_add`][f-wma-1-3], + [`overflowing_mul_add`][f-oma-1-3] * The new experimental feature [`unwrapped`][feat-un-1-3] was added, providing arithmetic methods that panic on overflow even when debug assertions are disabled. +[f-cma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.checked_mul_add +[f-ma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.mul_add +[f-oma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.overflowing_mul_add +[f-sma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.saturating_mul_add +[f-wma-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.wrapping_mul_add [feat-un-1-3]: https://tspiteri.gitlab.io/fixed/dev/fixed/#experimental-optional-features Version 1.2.0 (2020-09-02) diff --git a/src/arith.rs b/src/arith.rs index b3021d0..2d4caaa 100644 --- a/src/arith.rs +++ b/src/arith.rs @@ -457,6 +457,7 @@ fixed_arith! { FixedI128(i128, LeEqU128, 128), Signed } pub(crate) trait MulDivOverflow: Sized { fn mul_overflow(self, rhs: Self, frac_nbits: u32) -> (Self, bool); + fn mul_add_overflow(self, mul: Self, add: Self, frac_nbits: u32) -> (Self, bool); fn div_overflow(self, rhs: Self, frac_nbits: u32) -> (Self, bool); } @@ -473,6 +474,41 @@ macro_rules! mul_div_widen { ((prod2 >> NBITS) as $Single, overflow) } + #[inline] + fn mul_add_overflow( + self, + mul: $Single, + add: $Single, + frac_nbits: u32, + ) -> ($Single, bool) { + type Unsigned = <$Single as IntHelper>::Unsigned; + const NBITS: u32 = <$Single>::NBITS; + let self2 = <$Double>::from(self); + let mul2 = <$Double>::from(mul); + let prod2 = self2 * mul2; + let lo = (prod2 >> frac_nbits) as Unsigned; + let hi = (prod2 >> frac_nbits >> NBITS) as $Single; + if_signed_unsigned! { + $Signedness, + { + let (uns, carry) = lo.overflowing_add(add as Unsigned); + let ans = uns as $Single; + let mut expected_hi = if ans < 0 { -1 } else { 0 }; + if add < 0 { + expected_hi += 1; + } + if carry { + expected_hi -= 1; + } + (ans, hi != expected_hi) + }, + { + let (ans, overflow) = lo.overflowing_add(add); + (ans, overflow || hi != 0) + }, + } + } + #[inline] fn div_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) { const NBITS: u32 = <$Single>::NBITS; @@ -497,6 +533,7 @@ trait FallbackHelper: Sized { fn shift_lo_up(self) -> Self; fn shift_lo_up_unsigned(self) -> Self::Unsigned; fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> (Self, bool); + fn combine_lo_then_shl_add(self, lo: Self::Unsigned, shift: u32, add: Self) -> (Self, bool); fn carrying_add(self, other: Self) -> (Self, Self); } @@ -532,6 +569,21 @@ impl FallbackHelper for u128 { } } + #[inline] + fn combine_lo_then_shl_add(self, lo: u128, shift: u32, add: u128) -> (u128, bool) { + let (combine, overflow1) = if shift == 128 { + (self, false) + } else if shift == 0 { + (lo, self != 0) + } else { + let lo = lo >> shift; + let hi = self << (128 - shift); + (lo | hi, self >> shift != 0) + }; + let (ans, overflow2) = combine.overflowing_add(add); + (ans, overflow1 || overflow2) + } + #[inline] fn carrying_add(self, rhs: u128) -> (u128, u128) { let (sum, overflow) = self.overflowing_add(rhs); @@ -574,6 +626,30 @@ impl FallbackHelper for i128 { } } + #[inline] + fn combine_lo_then_shl_add(self, lo: u128, shift: u32, add: i128) -> (i128, bool) { + let (combine_lo, combine_hi) = if shift == 128 { + (self as u128, if self < 0 { -1 } else { 0 }) + } else if shift == 0 { + (lo, self) + } else { + ( + (lo >> shift) | (self << (128 - shift)) as u128, + self >> shift, + ) + }; + let (uns, carry) = combine_lo.overflowing_add(add as u128); + let ans = uns as i128; + let mut expected_hi = if ans < 0 { -1 } else { 0 }; + if add < 0 { + expected_hi += 1; + } + if carry { + expected_hi -= 1; + } + (ans, combine_hi != expected_hi) + } + #[inline] fn carrying_add(self, rhs: i128) -> (i128, i128) { let (sum, overflow) = self.overflowing_add(rhs); @@ -616,6 +692,31 @@ macro_rules! mul_div_fallback { } } + #[inline] + fn mul_add_overflow( + self, + mul: $Single, + add: $Single, + frac_nbits: u32, + ) -> ($Single, bool) { + // l * r + a + let (lh, ll) = self.hi_lo(); + let (rh, rl) = mul.hi_lo(); + let ll_rl = ll.wrapping_mul(rl); + let lh_rl = lh.wrapping_mul(rl); + let ll_rh = ll.wrapping_mul(rh); + let lh_rh = lh.wrapping_mul(rh); + + let col01 = ll_rl as <$Single as FallbackHelper>::Unsigned; + let (col01_hi, col01_lo) = col01.hi_lo(); + let partial_col12 = lh_rl + col01_hi as $Single; + let (col12, carry_col3) = partial_col12.carrying_add(ll_rh); + let (col12_hi, col12_lo) = col12.hi_lo(); + let ans01 = col12_lo.shift_lo_up_unsigned() + col01_lo; + let ans23 = lh_rh + col12_hi + carry_col3.shift_lo_up(); + ans23.combine_lo_then_shl_add(ans01, frac_nbits, add) + } + #[inline] fn div_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) { if frac_nbits == 0 { diff --git a/src/lib.rs b/src/lib.rs index b3a33e3..29964bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -444,7 +444,7 @@ assert_eq!(two_point_75.to_string(), \"2.8\"); // inherent methods that do not require Frac bounds, some of which can thus be const fixed_no_frac! { - $Fixed[$s_fixed]($Inner[$s_inner], $s_nbits), + $Fixed[$s_fixed]($Inner[$s_inner], $LeEqU, $s_nbits), $nbytes, $bytes_val, $be_bytes, $le_bytes, $UInner, $Signedness } diff --git a/src/macros_no_frac.rs b/src/macros_no_frac.rs index d4e6672..41d615c 100644 --- a/src/macros_no_frac.rs +++ b/src/macros_no_frac.rs @@ -15,7 +15,7 @@ macro_rules! fixed_no_frac { ( - $Fixed:ident[$s_fixed:expr]($Inner:ty[$s_inner:expr], $s_nbits:expr), + $Fixed:ident[$s_fixed:expr]($Inner:ty[$s_inner:expr], $LeEqU:tt, $s_nbits:expr), $nbytes:expr, $bytes_val:expr, $be_bytes:expr, $le_bytes:expr, $UInner:ty, $Signedness:tt ) => { @@ -458,6 +458,66 @@ assert!(half.is_power_of_two()); } } + comment! { + "Multiply and add. Returns `self` × `mul` + `add`. + +", + if_signed_else_empty_str! { + $Signedness, + "The product `self` × `mul` does not need to be +representable for a valid computation: if the product would overflow +but the final result would not overflow, this method still returns the +correct result. + +", + }, + "The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +# 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_mul_add`] +instead. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::from_num(4).mul_add(Fix::from_num(0.5), Fix::from_num(3)), + Fix::from_num(5) +); +", + if_signed_else_empty_str! { + $Signedness, + "// MAX × 1.5 − MAX = MAX / 2, which does not overflow +assert_eq!(Fix::MAX.mul_add(Fix::from_num(1.5), -Fix::MAX), Fix::MAX / 2); +" + }, + "``` + +[`wrapping_mul_add`]: #method.wrapping_mul_add +"; + #[inline] + pub fn mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> $Fixed { + let (ans, overflow) = self.to_bits().mul_add_overflow( + mul.to_bits(), + add.to_bits(), + MulFrac::U32, + ); + debug_assert!(!overflow, "overflow"); + Self::from_bits(ans) + } + } + comment! { "Remainder for Euclidean division. @@ -654,6 +714,62 @@ assert_eq!(Fix::from_num(1.5).checked_rem(Fix::from_num(0)), None); } } + comment! { + "Checked multiply and add. +Returns `self` × `mul` + `add`, or [`None`] on overflow. + +", + if_signed_else_empty_str! { + $Signedness, + "The product `self` × `mul` does not need to be +representable for a valid computation: if the product would overflow +but the final result would not overflow, this method still returns the +correct result. + +", + }, + "The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::from_num(4).checked_mul_add(Fix::from_num(0.5), Fix::from_num(3)), + Some(Fix::from_num(5)) +); +assert_eq!(Fix::MAX.checked_mul_add(Fix::from_num(1), Fix::from_num(0)), Some(Fix::MAX)); +assert_eq!(Fix::MAX.checked_mul_add(Fix::from_num(1), Fix::from_bits(1)), None); +", + if_signed_else_empty_str! { + $Signedness, + "// MAX × 1.5 − MAX = MAX / 2, which does not overflow +assert_eq!(Fix::MAX.checked_mul_add(Fix::from_num(1.5), -Fix::MAX), Some(Fix::MAX / 2)); +" + }, + "``` + +[`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None +"; + #[inline] + pub fn checked_mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> Option<$Fixed> { + match self.to_bits().mul_add_overflow( + mul.to_bits(), + add.to_bits(), + MulFrac::U32, + ) { + (ans, false) => Some(Self::from_bits(ans)), + (_, true) => None, + } + } + } + comment! { "Checked multiplication by an integer. Returns the product, or [`None`] on overflow. @@ -946,6 +1062,72 @@ assert_eq!(Fix::from_num(0).saturating_sub(Fix::from_num(1)), Fix::from_num(0)); } } + comment! { + "Saturating multiply and add. +Returns `self` × `mul` + `add`, saturating on overflow. + +", + if_signed_else_empty_str! { + $Signedness, + "The product `self` × `mul` does not need to be +representable for a valid computation: if the product would overflow +but the final result would not overflow, this method still returns the +correct result. + +", + }, + "The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::from_num(4).saturating_mul_add(Fix::from_num(0.5), Fix::from_num(3)), + Fix::from_num(5) +); +let half_max = Fix::MAX / 2; +assert_eq!(half_max.saturating_mul_add(Fix::from_num(3), half_max), Fix::MAX); +", + if_signed_else_empty_str! { + $Signedness, + "assert_eq!(half_max.saturating_mul_add(Fix::from_num(-5), half_max), Fix::MIN); +// MAX × 1.5 − MAX = MAX / 2, which does not overflow +assert_eq!(Fix::MAX.saturating_mul_add(Fix::from_num(1.5), -Fix::MAX), half_max); +" + }, + "``` +"; + #[inline] + pub fn saturating_mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> $Fixed { + match self.to_bits().mul_add_overflow( + mul.to_bits(), + add.to_bits(), + MulFrac::U32, + ) { + (ans, false) => Self::from_bits(ans), + (_, true) => { + let negative = if_signed_unsigned! { + $Signedness, + self.is_negative() != mul.is_negative(), + false, + }; + if negative { + Self::MIN + } else { + Self::MAX + } + } + } + } + } + comment! { "Saturating multiplication by an integer. Returns the product, saturating on overflow. @@ -1083,6 +1265,43 @@ assert_eq!(Fix::from_num(0)", } } + comment! { + "Wrapping multiply and add. +Returns `self` × `mul` + `add`, wrapping on overflow. + +The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::from_num(4).wrapping_mul_add(Fix::from_num(0.5), Fix::from_num(3)), + Fix::from_num(5) +); +assert_eq!(Fix::MAX.wrapping_mul_add(Fix::from_num(1), Fix::from_num(0)), Fix::MAX); +assert_eq!(Fix::MAX.wrapping_mul_add(Fix::from_num(1), Fix::from_bits(1)), Fix::MIN); +let wrapped = Fix::from_bits(!0 << 2); +assert_eq!(Fix::MAX.wrapping_mul_add(Fix::from_num(3), Fix::MAX), wrapped); +``` +"; + #[inline] + pub fn wrapping_mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> $Fixed { + let (ans, _) = self.to_bits().mul_add_overflow( + mul.to_bits(), + add.to_bits(), + MulFrac::U32, + ); + Self::from_bits(ans) + } + } + comment! { "Wrapping multiplication by an integer. Returns the product, wrapping on overflow. @@ -1366,6 +1585,69 @@ let _overflow = Fix::MIN.unwrapped_sub(Fix::from_bits(1)); } } + #[cfg(feature = "unwrapped")] + comment! { + "Unwrapped multiply and add. +Returns `self` × `mul` + `add`, panicking on overflow. + +", + if_signed_else_empty_str! { + $Signedness, + "The product `self` × `mul` does not need to be +representable for a valid computation: if the product would overflow +but the final result would not overflow, this method still returns the +correct result. + +", + }, + "The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +This method is only available when the [`unwrapped` experimental +feature][exp] is enabled. + +# Panics + +Panics if the result does not fit. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::from_num(4).unwrapped_mul_add(Fix::from_num(0.5), Fix::from_num(3)), + Fix::from_num(5) +); +", + if_signed_else_empty_str! { + $Signedness, + "// MAX × 1.5 − MAX = MAX / 2, which does not overflow +assert_eq!(Fix::MAX.unwrapped_mul_add(Fix::from_num(1.5), -Fix::MAX), Fix::MAX / 2); +" + }, + "``` + +The following panics because of overflow. + +```should_panic +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +let _overflow = Fix::MAX.unwrapped_mul_add(Fix::from_num(1), Fix::from_bits(1)); +``` + +[exp]: index.html#experimental-optional-features +"; + #[inline] + pub fn unwrapped_mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> $Fixed { + self.checked_mul_add(mul, add).expect("overflow") + } + } + #[cfg(feature = "unwrapped")] comment! { "Unwrapped multiplication by an integer. Returns the product, panicking on overflow. @@ -1718,6 +2000,53 @@ assert_eq!(Fix::from_num(0)", } } + comment! { + "Overflowing multiply and add. + +Returns a [tuple] of `self` × `mul` + `add` and a [`bool`] indicating +whether an overflow has occurred. On overflow, the wrapped value is +returned. + +The `mul` parameter can have a fixed-point type like +`self` but with a different number of fractional bits. + +# Examples + +```rust +use fixed::{types::extra::U4, ", $s_fixed, "}; +type Fix = ", $s_fixed, "; +assert_eq!( + Fix::MAX.overflowing_mul_add(Fix::from_num(1), Fix::from_num(0)), + (Fix::MAX, false) +); +assert_eq!( + Fix::MAX.overflowing_mul_add(Fix::from_num(1), Fix::from_bits(1)), + (Fix::MIN, true) +); +assert_eq!( + Fix::MAX.overflowing_mul_add(Fix::from_num(3), Fix::MAX), + (Fix::from_bits(!0 << 2), true) +); +``` + +[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html +[tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html +"; + #[inline] + pub fn overflowing_mul_add( + self, + mul: $Fixed, + add: $Fixed, + ) -> ($Fixed, bool) { + let (ans, overflow) = self.to_bits().mul_add_overflow( + mul.to_bits(), + add.to_bits(), + MulFrac::U32, + ); + (Self::from_bits(ans), overflow) + } + } + comment! { "Overflowing multiplication by an integer. diff --git a/src/traits.rs b/src/traits.rs index d5a1723..6801b39 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -838,6 +838,9 @@ where /// Shifts to the right by `n` bits, wrapping the truncated bits to the left end. fn rotate_right(self, n: u32) -> Self; + /// Multiply and add. Returns `self` × `mul` + `add`. + fn mul_add(self, mul: Self, add: Self) -> Self; + /// Euclidean division by an integer. /// /// # Panics @@ -898,6 +901,11 @@ where /// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None fn checked_rem(self, rhs: Self) -> Option; + /// Checked multiply and add. Returns `self` × `mul` + `add`, or [`None`] on overflow. + /// + /// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None + fn checked_mul_add(self, mul: Self, add: Self) -> Option; + /// Checked remainder for Euclidean division. Returns the /// remainder, or [`None`] if the divisor is zero or the division /// results in overflow. @@ -976,6 +984,9 @@ where /// Panics if the divisor is zero. fn saturating_div(self, rhs: Self) -> Self; + /// Saturating multiply and add. Returns `self` × `mul` + `add`, saturating on overflow. + fn saturating_mul_add(self, mul: Self, add: Self) -> Self; + /// Saturating Euclidean division. Returns the quotient, saturating on overflow. /// /// # Panics @@ -1005,6 +1016,9 @@ where /// Panics if the divisor is zero. fn wrapping_div(self, rhs: Self) -> Self; + /// Wrapping multiply and add. Returns `self` × `mul` + `add`, wrapping on overflow. + fn wrapping_mul_add(self, mul: Self, add: Self) -> Self; + /// Wrapping Euclidean division. Returns the quotient, wrapping on overflow. /// /// # Panics @@ -1115,6 +1129,19 @@ where /// [exp]: ../index.html#experimental-optional-features fn unwrapped_div(self, rhs: Self) -> Self; + #[cfg(feature = "unwrapped")] + /// Unwrapped multiply and add. Returns `self` × `mul` + `add`, panicking on overflow. + /// + /// This method is only available when the [`unwrapped` + /// experimental feature][exp] is enabled. + /// + /// # Panics + /// + /// Panics if the result does not fit. + /// + /// [exp]: ../index.html#experimental-optional-features + fn unwrapped_mul_add(self, mul: Self, add: Self) -> Self; + #[cfg(feature = "unwrapped")] /// Unwrapped Euclidean division. Returns the quotient, panicking on overflow. /// @@ -1266,6 +1293,16 @@ where /// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html fn overflowing_div(self, rhs: Self) -> (Self, bool); + /// Overflowing multiply and add. + /// + /// Returns a [tuple] of `self` × `mul` + `add` and a [`bool`], + /// indicating whether an overflow has occurred. On overflow, the + /// wrapped value is returned. + /// + /// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html + /// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html + fn overflowing_mul_add(self, mul: Self, add: Self) -> (Self, bool); + /// Overflowing Euclidean division. /// /// Returns a [tuple] of the quotient and a [`bool`], indicating @@ -2361,6 +2398,7 @@ macro_rules! impl_fixed { trait_delegate! { fn checked_int_log10(self) -> Option } trait_delegate! { fn rotate_left(self, n: u32) -> Self } trait_delegate! { fn rotate_right(self, n: u32) -> Self } + trait_delegate! { fn mul_add(self, mul: Self, add: Self) -> Self } trait_delegate! { fn div_euclid(self, rhs: Self) -> Self } trait_delegate! { fn rem_euclid(self, rhs: Self) -> Self } trait_delegate! { fn div_euclid_int(self, rhs: Self::Bits) -> Self } @@ -2371,6 +2409,7 @@ macro_rules! impl_fixed { trait_delegate! { fn checked_mul(self, rhs: Self) -> Option } trait_delegate! { fn checked_div(self, rhs: Self) -> Option } trait_delegate! { fn checked_rem(self, rhs: Self) -> Option } + trait_delegate! { fn checked_mul_add(self, mul: Self, add: Self) -> Option } trait_delegate! { fn checked_div_euclid(self, rhs: Self) -> Option } trait_delegate! { fn checked_rem_euclid(self, rhs: Self) -> Option } trait_delegate! { fn checked_mul_int(self, rhs: Self::Bits) -> Option } @@ -2385,6 +2424,7 @@ macro_rules! impl_fixed { trait_delegate! { fn saturating_sub(self, rhs: Self) -> Self } trait_delegate! { fn saturating_mul(self, rhs: Self) -> Self } trait_delegate! { fn saturating_div(self, rhs: Self) -> Self } + trait_delegate! { fn saturating_mul_add(self, mul: Self, add: Self) -> Self } trait_delegate! { fn saturating_div_euclid(self, rhs: Self) -> Self } trait_delegate! { fn saturating_mul_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn wrapping_neg(self) -> Self } @@ -2392,6 +2432,7 @@ macro_rules! impl_fixed { trait_delegate! { fn wrapping_sub(self, rhs: Self) -> Self } trait_delegate! { fn wrapping_mul(self, rhs: Self) -> Self } trait_delegate! { fn wrapping_div(self, rhs: Self) -> Self } + trait_delegate! { fn wrapping_mul_add(self, mul: Self, add: Self) -> Self } trait_delegate! { fn wrapping_div_euclid(self, rhs: Self) -> Self } trait_delegate! { fn wrapping_mul_int(self, rhs: Self::Bits) -> Self } trait_delegate! { fn wrapping_div_int(self, rhs: Self::Bits) -> Self } @@ -2410,6 +2451,8 @@ macro_rules! impl_fixed { #[cfg(feature = "unwrapped")] trait_delegate! { fn unwrapped_div(self, rhs: Self) -> Self } #[cfg(feature = "unwrapped")] + trait_delegate! { fn unwrapped_mul_add(self, mul: Self, add: Self) -> Self } + #[cfg(feature = "unwrapped")] trait_delegate! { fn unwrapped_div_euclid(self, rhs: Self) -> Self } #[cfg(feature = "unwrapped")] trait_delegate! { fn unwrapped_mul_int(self, rhs: Self::Bits) -> Self } @@ -2428,6 +2471,7 @@ macro_rules! impl_fixed { trait_delegate! { fn overflowing_sub(self, rhs: Self) -> (Self, bool) } trait_delegate! { fn overflowing_mul(self, rhs: Self) -> (Self, bool) } trait_delegate! { fn overflowing_div(self, rhs: Self) -> (Self, bool) } + trait_delegate! { fn overflowing_mul_add(self, mul: Self, add: Self) -> (Self, bool) } trait_delegate! { fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) } trait_delegate! { fn overflowing_mul_int(self, rhs: Self::Bits) -> (Self, bool) } trait_delegate! { fn overflowing_div_int(self, rhs: Self::Bits) -> (Self, bool) }