fix incorrect overflow handling for rem_euclid_int

This commit is contained in:
Trevor Spiteri 2020-02-21 15:39:02 +01:00
parent e8f5a8238e
commit e0f3eb77b8
7 changed files with 282 additions and 86 deletions

View File

@ -74,6 +74,11 @@ The conversions supported cover the following cases.
## Whats new
### Version 0.5.4 news (unreleased)
* Bug fix: [`rem_euclid_int`] and its checked versions were handling
overflow incorrectly.
### Version 0.5.3 news (2020-02-13)
* Bug fix: [`round_to_zero`] was returning incorrect results for
@ -95,6 +100,8 @@ The conversions supported cover the following cases.
* The following methods were added to the [`Wrapping`] wrapper:
* [`div_euclid`][wde], [`rem_euclid`][wre]
* [`div_euclid_int`][wdei], [`rem_euclid_int`][wrei]
* The following methods were deprecated:
* [`wrapping_rem_int`], [`overflowing_rem_int`]
### Version 0.5.2 news (2020-02-02)
@ -109,10 +116,13 @@ The conversions supported cover the following cases.
[`checked_rem`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.checked_rem
[`div_euclid`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.div_euclid
[`overflowing_div_euclid`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.overflowing_div_euclid
[`overflowing_rem_int`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.overflowing_rem_int
[`rem_euclid_int`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.rem_euclid_int
[`rem_euclid`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.rem_euclid
[`round_to_zero`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.round_to_zero
[`saturating_div_euclid`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.saturating_div_euclid
[`wrapping_div_euclid`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.wrapping_div_euclid
[`wrapping_rem_int`]: https://docs.rs/fixed/0.5.3/fixed/struct.FixedI32.html#method.wrapping_rem_int
[issue 13]: https://gitlab.com/tspiteri/fixed/issues/13
[wde]: https://docs.rs/fixed/0.5.3/fixed/struct.Wrapping.html#method.div_euclid
[wdei]: https://docs.rs/fixed/0.5.3/fixed/struct.Wrapping.html#method.div_euclid_int

View File

@ -5,6 +5,12 @@ modification, are permitted in any medium without royalty provided the
copyright notice and this notice are preserved. This file is offered
as-is, without any warranty. -->
Version 0.5.4 (unreleased)
==========================
* Bug fix: `rem_euclid_int` and its checked versions were handling
overflow incorrectly.
Version 0.5.3 (2020-02-13)
==========================
@ -27,6 +33,8 @@ Version 0.5.3 (2020-02-13)
* The following methods were added to the `Wrapping` wrapper:
* `div_euclid`, `rem_euclid`
* `div_euclid_int`, `rem_euclid_int`
* The following methods were deprecated:
* `wrapping_rem_int`, `overflowing_rem_int`
Version 0.5.2 (2020-02-02)
==========================

View File

@ -805,7 +805,7 @@ mod tests {
#[test]
fn rem_int() {
use crate::types::I16F16;
use crate::types::{I0F32, I16F16, I1F31};
check_rem_int(-0x8000, -0x8000);
check_rem_int(-0x8000, -0x7fff);
check_rem_int(-0x8000, 0x7fff);
@ -819,9 +819,71 @@ mod tests {
check_rem_int(0x7fff, 0x7fff);
check_rem_int(0x7fff, 0x8000);
fn i1(f: f32) -> I1F31 {
I1F31::from_num(f)
}
fn i0(f: f32) -> I0F32 {
I0F32::from_num(f)
}
assert_eq!(I16F16::min_value() % -1, 0);
assert_eq!(I16F16::min_value().checked_rem_int(-1).unwrap(), 0);
assert_eq!(I16F16::min_value().rem_euclid_int(-1), 0);
assert_eq!(I16F16::min_value().checked_rem_euclid_int(-1).unwrap(), 0);
assert_eq!(i1(-1.0) % 1, i1(0.0));
assert_eq!(i1(-1.0).rem_euclid_int(1), i1(0.0));
assert_eq!(i1(-0.75) % 1, i1(-0.75));
assert_eq!(i1(-0.75).rem_euclid_int(1), i1(0.25));
assert_eq!(i1(-0.5) % 1, i1(-0.5));
assert_eq!(i1(-0.5).rem_euclid_int(1), i1(0.5));
assert_eq!(i1(-0.5) % 3, i1(-0.5));
assert_eq!(i1(-0.5).checked_rem_euclid_int(3), None);
assert_eq!(i1(-0.5).wrapping_rem_euclid_int(3), i1(0.5));
assert_eq!(i1(-0.5).overflowing_rem_euclid_int(3), (i1(0.5), true));
assert_eq!(i1(-0.25) % 1, i1(-0.25));
assert_eq!(i1(-0.25).rem_euclid_int(1), i1(0.75));
assert_eq!(i1(-0.25) % 3, i1(-0.25));
assert_eq!(i1(-0.25).checked_rem_euclid_int(3), None);
assert_eq!(i1(-0.25).wrapping_rem_euclid_int(3), i1(0.75));
assert_eq!(i1(-0.25).overflowing_rem_euclid_int(3), (i1(0.75), true));
assert_eq!(i1(0.0) % 1, i1(0.0));
assert_eq!(i1(0.0).rem_euclid_int(1), i1(0.0));
assert_eq!(i1(0.25) % 1, i1(0.25));
assert_eq!(i1(0.25).rem_euclid_int(1), i1(0.25));
assert_eq!(i1(0.5) % 1, i1(0.5));
assert_eq!(i1(0.5).rem_euclid_int(1), i1(0.5));
assert_eq!(i1(0.75) % 1, i1(0.75));
assert_eq!(i1(0.75).rem_euclid_int(1), i1(0.75));
assert_eq!(i0(-0.5) % 1, i0(-0.5));
assert_eq!(i0(-0.5).checked_rem_euclid_int(1), None);
assert_eq!(i0(-0.5).wrapping_rem_euclid_int(1), i0(-0.5));
assert_eq!(i0(-0.5).overflowing_rem_euclid_int(1), (i0(-0.5), true));
assert_eq!(i0(-0.375) % 1, i0(-0.375));
assert_eq!(i0(-0.375).checked_rem_euclid_int(1), None);
assert_eq!(i0(-0.375).wrapping_rem_euclid_int(1), i0(-0.375));
assert_eq!(i0(-0.375).overflowing_rem_euclid_int(1), (i0(-0.375), true));
assert_eq!(i0(-0.25) % 1, i0(-0.25));
assert_eq!(i0(-0.25).checked_rem_euclid_int(1), None);
assert_eq!(i0(-0.25).wrapping_rem_euclid_int(1), i0(-0.25));
assert_eq!(i0(-0.25).overflowing_rem_euclid_int(1), (i0(-0.25), true));
assert_eq!(i0(0.0) % 1, i0(0.0));
assert_eq!(i0(0.0).rem_euclid_int(1), i0(0.0));
assert_eq!(i0(0.25) % 1, i0(0.25));
assert_eq!(i0(0.25).rem_euclid_int(1), i0(0.25));
}
}

View File

@ -267,6 +267,7 @@ pub mod traits;
pub mod types;
mod wide_div;
mod wrapping;
use crate::{
arith::MulDivOverflow,
from_str::FromStrRadix,
@ -312,20 +313,22 @@ mod macros_frac;
macro_rules! fixed {
(
$description:expr,
$Fixed:ident($Inner:ty, $LeEqU:tt, $s_nbits:expr),
$Fixed:ident($Inner:ty, $LeEqU:tt, $s_nbits:expr, $s_nbits_m4:expr),
$nbytes:expr, $bytes_val:expr, $be_bytes:expr, $le_bytes:expr,
$UInner:ty, $Signedness:tt
) => {
fixed! {
$description,
$Fixed[stringify!($Fixed)]($Inner[stringify!($Inner)], $LeEqU, $s_nbits),
$Fixed[stringify!($Fixed)]($Inner[stringify!($Inner)], $LeEqU, $s_nbits, $s_nbits_m4),
$nbytes, $bytes_val, $be_bytes, $le_bytes,
$UInner, $Signedness
}
};
(
$description:expr,
$Fixed:ident[$s_fixed:expr]($Inner:ty[$s_inner:expr], $LeEqU:tt, $s_nbits:expr),
$Fixed:ident[$s_fixed:expr](
$Inner:ty[$s_inner:expr], $LeEqU:tt, $s_nbits:expr, $s_nbits_m4:expr
),
$nbytes:expr, $bytes_val:expr, $be_bytes:expr, $le_bytes:expr,
$UInner:ty, $Signedness:tt
) => {
@ -401,7 +404,7 @@ assert_eq!(two_point_75.to_string(), \"2.8\");
// inherent methods that require Frac bounds, and cannot be const
fixed_frac! {
$description,
$Fixed[$s_fixed]($Inner[$s_inner], $LeEqU, $s_nbits),
$Fixed[$s_fixed]($Inner[$s_inner], $LeEqU, $s_nbits, $s_nbits_m4),
$UInner, $Signedness
}
};
@ -409,25 +412,25 @@ assert_eq!(two_point_75.to_string(), \"2.8\");
fixed! {
"An eight-bit fixed-point unsigned",
FixedU8(u8, LeEqU8, "8"),
FixedU8(u8, LeEqU8, "8", "4"),
1, "0x12", "[0x12]", "[0x12]",
u8, Unsigned
}
fixed! {
"A 16-bit fixed-point unsigned",
FixedU16(u16, LeEqU16, "16"),
FixedU16(u16, LeEqU16, "16", "12"),
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
u16, Unsigned
}
fixed! {
"A 32-bit fixed-point unsigned",
FixedU32(u32, LeEqU32, "32"),
FixedU32(u32, LeEqU32, "32", "28"),
4, "0x1234_5678", "[0x12, 0x34, 0x56, 0x78]", "[0x78, 0x56, 0x34, 0x12]",
u32, Unsigned
}
fixed! {
"A 64-bit fixed-point unsigned",
FixedU64(u64, LeEqU64, "64"),
FixedU64(u64, LeEqU64, "64", "60"),
8, "0x1234_5678_9ABC_DEF0",
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
@ -435,7 +438,7 @@ fixed! {
}
fixed! {
"A 128-bit fixed-point unsigned",
FixedU128(u128, LeEqU128, "128"),
FixedU128(u128, LeEqU128, "128", "124"),
16, "0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0",
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, \
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
@ -445,25 +448,25 @@ fixed! {
}
fixed! {
"An eight-bit fixed-point signed",
FixedI8(i8, LeEqU8, "8"),
FixedI8(i8, LeEqU8, "8", "4"),
1, "0x12", "[0x12]", "[0x12]",
u8, Signed
}
fixed! {
"A 16-bit fixed-point signed",
FixedI16(i16, LeEqU16, "16"),
FixedI16(i16, LeEqU16, "16", "12"),
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
u16, Signed
}
fixed! {
"A 32-bit fixed-point signed",
FixedI32(i32, LeEqU32, "32"),
FixedI32(i32, LeEqU32, "32", "28"),
4, "0x1234_5678", "[0x12, 0x34, 0x56, 0x78]", "[0x78, 0x56, 0x34, 0x12]",
u32, Signed
}
fixed! {
"A 64-bit fixed-point signed",
FixedI64(i64, LeEqU64, "64"),
FixedI64(i64, LeEqU64, "64", "60"),
8, "0x1234_5678_9ABC_DEF0",
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
@ -471,7 +474,7 @@ fixed! {
}
fixed! {
"A 128-bit fixed-point signed",
FixedI128(i128, LeEqU128, "128"),
FixedI128(i128, LeEqU128, "128", "124"),
16, "0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0",
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, \
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",

View File

@ -16,7 +16,9 @@
macro_rules! fixed_frac {
(
$description:expr,
$Fixed:ident[$s_fixed:expr]($Inner:ty[$s_inner:expr], $LeEqU:tt, $s_nbits:expr),
$Fixed:ident[$s_fixed:expr](
$Inner:ty[$s_inner:expr], $LeEqU:tt, $s_nbits:expr, $s_nbits_m4:expr
),
$UInner:ty, $Signedness:tt
) => {
impl<Frac: $LeEqU> $Fixed<Frac> {
@ -257,7 +259,9 @@ assert_eq!(Fix::from_num(7.5).rem_euclid_int(2), Fix::from_num(1.5));
";
#[inline]
pub fn rem_euclid_int(self, rhs: $Inner) -> $Fixed<Frac> {
self.checked_rem_euclid_int(rhs).expect("division by zero")
let (ans, overflow) = self.overflowing_rem_euclid_int(rhs);
debug_assert!(!overflow, "overflow");
ans
}
}
@ -375,12 +379,15 @@ assert_eq!(Fix::from_num(3.75).checked_rem_int(0), None);
pub fn checked_rem_int(self, rhs: $Inner) -> Option<$Fixed<Frac>> {
// Overflow converting rhs to $Fixed<Frac> means that either
// * |rhs| > |self|, and so remainder is self, or
// * self is signed min, and the value of rhs is -self, so remainder is 0.
// * self is signed min with at least one integer bit,
// and the value of rhs is -self, so remainder is 0.
match Self::checked_from_num(rhs) {
Some(fixed_rhs) => self.checked_rem(fixed_rhs),
None => Some(if_signed_unsigned!(
$Signedness,
if self.to_num::<$Inner>().wrapping_abs() == rhs {
if self == Self::min_value()
&& (Self::INT_NBITS > 0 && rhs == 1 << (Self::INT_NBITS - 1))
{
Self::from_bits(0)
} else {
self
@ -437,19 +444,26 @@ assert_eq!(Fix::from_num(7.5).checked_div_euclid_int(0), None);
comment! {
"Checked remainder for Euclidean division by an integer.
Returns the remainder, or [`None`] if the divisor is zero.
Returns the remainder, or [`None`] if the divisor is zero",
if_signed_else_empty_str! {
$Signedness,
" or if the remainder results in overflow",
},
".
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
use fixed::{types::extra::U", $s_nbits_m4, ", ", $s_fixed, "};
type Fix = ", $s_fixed, "<U", $s_nbits_m4, ">;
assert_eq!(Fix::from_num(7.5).checked_rem_euclid_int(2), Some(Fix::from_num(1.5)));
assert_eq!(Fix::from_num(7.5).checked_rem_euclid_int(0), None);
",
if_signed_else_empty_str! {
$Signedness,
"assert_eq!(Fix::from_num(-7.5).checked_rem_euclid_int(2), Some(Fix::from_num(0.5)));
// 8 ≤ Fix < 8, so the answer 12.5 overflows
assert_eq!(Fix::from_num(-7.5).checked_rem_euclid_int(20), None);
",
},
"```
@ -458,18 +472,31 @@ assert_eq!(Fix::from_num(7.5).checked_rem_euclid_int(0), None);
";
#[inline]
pub fn checked_rem_euclid_int(self, rhs: $Inner) -> Option<$Fixed<Frac>> {
// For signed rem_euclid_int, rhs can be made
// negative without changing result.
// Then, overflow converting rhs to $Fixed<Frac> means
// that |rhs| > |self|, and so remainder is self.
let prep_rhs = if_signed_unsigned!(
$Signedness,
rhs.wrapping_abs().wrapping_neg(),
rhs,
);
match Self::checked_from_num(prep_rhs) {
Some(fixed_rhs) => self.checked_rem_euclid(fixed_rhs),
None => Some(self),
if_signed! {
$Signedness;
let rem = self.checked_rem_int(rhs)?;
if rem >= 0 {
return Some(rem);
}
// Work in unsigned.
// Answer required is |rhs| - |rem|, but rhs is int, rem is fixed.
// INT_NBITS == 0 is a special case, as fraction can be negative.
if Self::INT_NBITS == 0 {
// -0.5 <= rem < 0, so euclidean remainder is in the range
// 0.5 <= answer < 1, which does not fit.
return None;
}
let rhs_abs = rhs.wrapping_abs() as $UInner;
let remb = rem.to_bits();
let remb_abs = remb.wrapping_neg() as $UInner;
let rem_int_abs = remb_abs >> Self::FRAC_NBITS;
let rem_frac = remb & Self::FRAC_MASK;
let ans_int = rhs_abs - rem_int_abs - if rem_frac > 0 { 1 } else { 0 };
Self::checked_from_num(ans_int).map(|x| x | Self::from_bits(rem_frac))
}
if_unsigned! {
$Signedness;
self.checked_rem_int(rhs)
}
}
}
@ -682,6 +709,46 @@ assert_eq!(Fix::min_value().wrapping_div_euclid_int(-1), wrapped);
}
}
comment! {
"Wrapping remainder for Euclidean division by an integer. Returns the remainder",
if_signed_unsigned! {
$Signedness,
", wrapping on overflow.
Note that while remainder for Euclidean division cannot be negative,
the wrapped value can be negative.",
".
Can never overflow for unsigned values.",
},
"
# Panics
Panics if the divisor is zero.
# Examples
```rust
use fixed::{types::extra::U", $s_nbits_m4, ", ", $s_fixed, "};
type Fix = ", $s_fixed, "<U", $s_nbits_m4, ">;
assert_eq!(Fix::from_num(7.5).wrapping_rem_euclid_int(2), Fix::from_num(1.5));
",
if_signed_else_empty_str! {
$Signedness,
"assert_eq!(Fix::from_num(-7.5).wrapping_rem_euclid_int(2), Fix::from_num(0.5));
// 8 ≤ Fix < 8, so the answer 12.5 wraps to 3.5
assert_eq!(Fix::from_num(-7.5).wrapping_rem_euclid_int(20), Fix::from_num(-3.5));
",
},
"```
";
#[inline]
pub fn wrapping_rem_euclid_int(self, rhs: $Inner) -> $Fixed<Frac> {
self.overflowing_rem_euclid_int(rhs).0
}
}
comment! {
"Overflowing multiplication.
@ -854,6 +921,76 @@ assert_eq!(Fix::min_value().overflowing_div_euclid_int(-1), (wrapped, true));
}
}
comment! {
"Remainder for Euclidean division by an integer.
Returns a [tuple] of the remainder and ",
if_signed_unsigned! {
$Signedness,
"a [`bool`] indicating whether an overflow has
occurred. On overflow, the wrapped value is returned.
Note that while remainder for Euclidean division cannot be negative,
the wrapped value can be negative.",
"[`false`][`bool`], as this can never overflow for unsigned values.",
},
"
# Panics
Panics if the divisor is zero.
# Examples
```rust
use fixed::{types::extra::U", $s_nbits_m4, ", ", $s_fixed, "};
type Fix = ", $s_fixed, "<U", $s_nbits_m4, ">;
assert_eq!(Fix::from_num(7.5).overflowing_rem_euclid_int(2), (Fix::from_num(1.5), false));
",
if_signed_else_empty_str! {
$Signedness,
"assert_eq!(Fix::from_num(-7.5).overflowing_rem_euclid_int(2), (Fix::from_num(0.5), false));
// 8 ≤ Fix < 8, so the answer 12.5 wraps to 3.5
assert_eq!(Fix::from_num(-7.5).overflowing_rem_euclid_int(20), (Fix::from_num(-3.5), 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_rem_euclid_int(self, rhs: $Inner) -> ($Fixed<Frac>, bool) {
if_signed! {
$Signedness;
let rem = self % rhs;
if rem >= 0 {
return (rem, false);
}
// Work in unsigned.
// Answer required is |rhs| - |rem|, but rhs is int, rem is fixed.
// INT_NBITS == 0 is a special case, as fraction can be negative.
if Self::INT_NBITS == 0 {
// -0.5 <= rem < 0, so euclidean remainder is in the range
// 0.5 <= answer < 1, which does not fit.
return (rem, true);
}
let rhs_abs = rhs.wrapping_abs() as $UInner;
let remb = rem.to_bits();
let remb_abs = remb.wrapping_neg() as $UInner;
let rem_int_abs = remb_abs >> Self::FRAC_NBITS;
let rem_frac = remb & Self::FRAC_MASK;
let ans_int = rhs_abs - rem_int_abs - if rem_frac > 0 { 1 } else { 0 };
let (ans, overflow) = Self::overflowing_from_num(ans_int);
(ans | Self::from_bits(rem_frac), overflow)
}
if_unsigned! {
$Signedness;
(self % rhs, false)
}
}
}
/// Remainder for division by an integer.
///
/// # Panics
@ -875,28 +1012,6 @@ assert_eq!(Fix::min_value().overflowing_div_euclid_int(-1), (wrapped, true));
pub fn overflowing_rem_int(self, rhs: $Inner) -> ($Fixed<Frac>, bool) {
(self % rhs, false)
}
/// Remainder for Euclidean division by an integer.
///
/// # Panics
///
/// Panics if the divisor is zero.
#[deprecated(since = "0.5.3", note = "cannot overflow, use `rem_euclid_int` instead")]
#[inline]
pub fn wrapping_rem_euclid_int(self, rhs: $Inner) -> $Fixed<Frac> {
self.rem_euclid_int(rhs)
}
/// Remainder for Euclidean division by an integer.
///
/// # Panics
///
/// Panics if the divisor is zero.
#[deprecated(since = "0.5.3", note = "cannot overflow, use `rem_euclid_int` instead")]
#[inline]
pub fn overflowing_rem_euclid_int(self, rhs: $Inner) -> ($Fixed<Frac>, bool) {
(self.rem_euclid_int(rhs), false)
}
}
};
}

View File

@ -689,9 +689,9 @@ where
/// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None
fn checked_div_euclid_int(self, rhs: Self::Bits) -> Option<Self>;
/// Checked fixed-point remainder for Euclidean division by an
/// integer. Returns the remainder, or [`None`] if the divisor is
/// zero.
/// Checked remainder for Euclidean division by an integer.
/// Returns the remainder, or [`None`] if the divisor is zero or
/// if the remainder results in overflow.
///
/// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None
fn checked_rem_euclid_int(self, rhs: Self::Bits) -> Option<Self>;
@ -785,6 +785,14 @@ where
/// Panics if the divisor is zero.
fn wrapping_div_euclid_int(self, rhs: Self::Bits) -> Self;
/// Wrapping remainder for Euclidean division by an integer.
/// Returns the remainder, wrapping on overflow.
///
/// # Panics
///
/// Panics if the divisor is zero.
fn wrapping_rem_euclid_int(self, rhs: Self::Bits) -> Self;
/// Wrapping shift left. Wraps `rhs` if `rhs` ≥ the number of
/// bits, then shifts and returns the number.
fn wrapping_shl(self, rhs: u32) -> Self;
@ -899,6 +907,20 @@ where
/// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html
fn overflowing_div_euclid_int(self, rhs: Self::Bits) -> (Self, bool);
/// Overflowing remainder for Euclidean division by an integer.
///
/// Returns a [tuple] of the remainder and a [`bool`], indicating
/// whether an overflow has occurred. On overflow, the wrapped
/// value is returned.
///
/// # Panics
///
/// Panics if the divisor is zero.
///
/// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
/// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html
fn overflowing_rem_euclid_int(self, rhs: Self::Bits) -> (Self, bool);
/// Overflowing shift left.
///
/// Returns a [tuple] of the shifted value and a [`bool`],
@ -944,32 +966,6 @@ where
fn overflowing_rem_int(self, rhs: Self::Bits) -> (Self, bool) {
(self % rhs, false)
}
/// Remainder for Euclidean division by an integer.
///
/// # Panics
///
/// Panics if the divisor is zero.
#[deprecated(
since = "0.5.3",
note = "cannot overflow, use `rem_euclid_int` instead"
)]
fn wrapping_rem_euclid_int(self, rhs: Self::Bits) -> Self {
self.rem_euclid_int(rhs)
}
/// Remainder for Euclidean division by an integer.
///
/// # Panics
///
/// Panics if the divisor is zero.
#[deprecated(
since = "0.5.3",
note = "cannot overflow, use `rem_euclid_int` instead"
)]
fn overflowing_rem_euclid_int(self, rhs: Self::Bits) -> (Self, bool) {
(self.rem_euclid_int(rhs), false)
}
}
/// This trait provides methods common to all signed fixed-point numbers.
@ -1616,6 +1612,7 @@ macro_rules! impl_fixed {
trait_delegate! { fn wrapping_mul_int(self, rhs: Self::Bits) -> Self }
trait_delegate! { fn wrapping_div_int(self, rhs: Self::Bits) -> Self }
trait_delegate! { fn wrapping_div_euclid_int(self, rhs: Self::Bits) -> Self }
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 overflowing_neg(self) -> (Self, bool) }
@ -1627,6 +1624,7 @@ macro_rules! impl_fixed {
trait_delegate! { fn overflowing_mul_int(self, rhs: Self::Bits) -> (Self, bool) }
trait_delegate! { fn overflowing_div_int(self, rhs: Self::Bits) -> (Self, bool) }
trait_delegate! { fn overflowing_div_euclid_int(self, rhs: Self::Bits) -> (Self, bool) }
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) }
}

View File

@ -603,7 +603,7 @@ impl<F: Fixed> Wrapping<F> {
/// ```
#[inline]
pub fn rem_euclid_int(self, divisor: F::Bits) -> Wrapping<F> {
Wrapping(self.0.rem_euclid_int(divisor))
Wrapping(self.0.wrapping_rem_euclid_int(divisor))
}
}