fix incorrect overflow handling for rem_euclid_int
This commit is contained in:
parent
e8f5a8238e
commit
e0f3eb77b8
10
README.md
10
README.md
|
@ -74,6 +74,11 @@ The conversions supported cover the following cases.
|
||||||
|
|
||||||
## What’s new
|
## What’s 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)
|
### Version 0.5.3 news (2020-02-13)
|
||||||
|
|
||||||
* Bug fix: [`round_to_zero`] was returning incorrect results for
|
* 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:
|
* The following methods were added to the [`Wrapping`] wrapper:
|
||||||
* [`div_euclid`][wde], [`rem_euclid`][wre]
|
* [`div_euclid`][wde], [`rem_euclid`][wre]
|
||||||
* [`div_euclid_int`][wdei], [`rem_euclid_int`][wrei]
|
* [`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)
|
### 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
|
[`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
|
[`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_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
|
[`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
|
[`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
|
[`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_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
|
[issue 13]: https://gitlab.com/tspiteri/fixed/issues/13
|
||||||
[wde]: https://docs.rs/fixed/0.5.3/fixed/struct.Wrapping.html#method.div_euclid
|
[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
|
[wdei]: https://docs.rs/fixed/0.5.3/fixed/struct.Wrapping.html#method.div_euclid_int
|
||||||
|
|
|
@ -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
|
copyright notice and this notice are preserved. This file is offered
|
||||||
as-is, without any warranty. -->
|
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)
|
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:
|
* The following methods were added to the `Wrapping` wrapper:
|
||||||
* `div_euclid`, `rem_euclid`
|
* `div_euclid`, `rem_euclid`
|
||||||
* `div_euclid_int`, `rem_euclid_int`
|
* `div_euclid_int`, `rem_euclid_int`
|
||||||
|
* The following methods were deprecated:
|
||||||
|
* `wrapping_rem_int`, `overflowing_rem_int`
|
||||||
|
|
||||||
Version 0.5.2 (2020-02-02)
|
Version 0.5.2 (2020-02-02)
|
||||||
==========================
|
==========================
|
||||||
|
|
64
src/arith.rs
64
src/arith.rs
|
@ -805,7 +805,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rem_int() {
|
fn rem_int() {
|
||||||
use crate::types::I16F16;
|
use crate::types::{I0F32, I16F16, I1F31};
|
||||||
check_rem_int(-0x8000, -0x8000);
|
check_rem_int(-0x8000, -0x8000);
|
||||||
check_rem_int(-0x8000, -0x7fff);
|
check_rem_int(-0x8000, -0x7fff);
|
||||||
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, 0x7fff);
|
||||||
check_rem_int(0x7fff, 0x8000);
|
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() % -1, 0);
|
||||||
assert_eq!(I16F16::min_value().checked_rem_int(-1).unwrap(), 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().rem_euclid_int(-1), 0);
|
||||||
assert_eq!(I16F16::min_value().checked_rem_euclid_int(-1).unwrap(), 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
src/lib.rs
31
src/lib.rs
|
@ -267,6 +267,7 @@ pub mod traits;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
mod wide_div;
|
mod wide_div;
|
||||||
mod wrapping;
|
mod wrapping;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arith::MulDivOverflow,
|
arith::MulDivOverflow,
|
||||||
from_str::FromStrRadix,
|
from_str::FromStrRadix,
|
||||||
|
@ -312,20 +313,22 @@ mod macros_frac;
|
||||||
macro_rules! fixed {
|
macro_rules! fixed {
|
||||||
(
|
(
|
||||||
$description:expr,
|
$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,
|
$nbytes:expr, $bytes_val:expr, $be_bytes:expr, $le_bytes:expr,
|
||||||
$UInner:ty, $Signedness:tt
|
$UInner:ty, $Signedness:tt
|
||||||
) => {
|
) => {
|
||||||
fixed! {
|
fixed! {
|
||||||
$description,
|
$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,
|
$nbytes, $bytes_val, $be_bytes, $le_bytes,
|
||||||
$UInner, $Signedness
|
$UInner, $Signedness
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
$description:expr,
|
$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,
|
$nbytes:expr, $bytes_val:expr, $be_bytes:expr, $le_bytes:expr,
|
||||||
$UInner:ty, $Signedness:tt
|
$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
|
// inherent methods that require Frac bounds, and cannot be const
|
||||||
fixed_frac! {
|
fixed_frac! {
|
||||||
$description,
|
$description,
|
||||||
$Fixed[$s_fixed]($Inner[$s_inner], $LeEqU, $s_nbits),
|
$Fixed[$s_fixed]($Inner[$s_inner], $LeEqU, $s_nbits, $s_nbits_m4),
|
||||||
$UInner, $Signedness
|
$UInner, $Signedness
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -409,25 +412,25 @@ assert_eq!(two_point_75.to_string(), \"2.8\");
|
||||||
|
|
||||||
fixed! {
|
fixed! {
|
||||||
"An eight-bit fixed-point unsigned",
|
"An eight-bit fixed-point unsigned",
|
||||||
FixedU8(u8, LeEqU8, "8"),
|
FixedU8(u8, LeEqU8, "8", "4"),
|
||||||
1, "0x12", "[0x12]", "[0x12]",
|
1, "0x12", "[0x12]", "[0x12]",
|
||||||
u8, Unsigned
|
u8, Unsigned
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 16-bit fixed-point unsigned",
|
"A 16-bit fixed-point unsigned",
|
||||||
FixedU16(u16, LeEqU16, "16"),
|
FixedU16(u16, LeEqU16, "16", "12"),
|
||||||
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
|
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
|
||||||
u16, Unsigned
|
u16, Unsigned
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 32-bit fixed-point unsigned",
|
"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]",
|
4, "0x1234_5678", "[0x12, 0x34, 0x56, 0x78]", "[0x78, 0x56, 0x34, 0x12]",
|
||||||
u32, Unsigned
|
u32, Unsigned
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 64-bit fixed-point unsigned",
|
"A 64-bit fixed-point unsigned",
|
||||||
FixedU64(u64, LeEqU64, "64"),
|
FixedU64(u64, LeEqU64, "64", "60"),
|
||||||
8, "0x1234_5678_9ABC_DEF0",
|
8, "0x1234_5678_9ABC_DEF0",
|
||||||
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
||||||
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
|
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
|
||||||
|
@ -435,7 +438,7 @@ fixed! {
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 128-bit fixed-point unsigned",
|
"A 128-bit fixed-point unsigned",
|
||||||
FixedU128(u128, LeEqU128, "128"),
|
FixedU128(u128, LeEqU128, "128", "124"),
|
||||||
16, "0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0",
|
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, \
|
||||||
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
||||||
|
@ -445,25 +448,25 @@ fixed! {
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"An eight-bit fixed-point signed",
|
"An eight-bit fixed-point signed",
|
||||||
FixedI8(i8, LeEqU8, "8"),
|
FixedI8(i8, LeEqU8, "8", "4"),
|
||||||
1, "0x12", "[0x12]", "[0x12]",
|
1, "0x12", "[0x12]", "[0x12]",
|
||||||
u8, Signed
|
u8, Signed
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 16-bit fixed-point signed",
|
"A 16-bit fixed-point signed",
|
||||||
FixedI16(i16, LeEqU16, "16"),
|
FixedI16(i16, LeEqU16, "16", "12"),
|
||||||
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
|
2, "0x1234", "[0x12, 0x34]", "[0x34, 0x12]",
|
||||||
u16, Signed
|
u16, Signed
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 32-bit fixed-point signed",
|
"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]",
|
4, "0x1234_5678", "[0x12, 0x34, 0x56, 0x78]", "[0x78, 0x56, 0x34, 0x12]",
|
||||||
u32, Signed
|
u32, Signed
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 64-bit fixed-point signed",
|
"A 64-bit fixed-point signed",
|
||||||
FixedI64(i64, LeEqU64, "64"),
|
FixedI64(i64, LeEqU64, "64", "60"),
|
||||||
8, "0x1234_5678_9ABC_DEF0",
|
8, "0x1234_5678_9ABC_DEF0",
|
||||||
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
"[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
||||||
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
|
"[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]",
|
||||||
|
@ -471,7 +474,7 @@ fixed! {
|
||||||
}
|
}
|
||||||
fixed! {
|
fixed! {
|
||||||
"A 128-bit fixed-point signed",
|
"A 128-bit fixed-point signed",
|
||||||
FixedI128(i128, LeEqU128, "128"),
|
FixedI128(i128, LeEqU128, "128", "124"),
|
||||||
16, "0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0",
|
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, \
|
||||||
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]",
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
macro_rules! fixed_frac {
|
macro_rules! fixed_frac {
|
||||||
(
|
(
|
||||||
$description:expr,
|
$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
|
$UInner:ty, $Signedness:tt
|
||||||
) => {
|
) => {
|
||||||
impl<Frac: $LeEqU> $Fixed<Frac> {
|
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]
|
#[inline]
|
||||||
pub fn rem_euclid_int(self, rhs: $Inner) -> $Fixed<Frac> {
|
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>> {
|
pub fn checked_rem_int(self, rhs: $Inner) -> Option<$Fixed<Frac>> {
|
||||||
// Overflow converting rhs to $Fixed<Frac> means that either
|
// Overflow converting rhs to $Fixed<Frac> means that either
|
||||||
// * |rhs| > |self|, and so remainder is self, or
|
// * |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) {
|
match Self::checked_from_num(rhs) {
|
||||||
Some(fixed_rhs) => self.checked_rem(fixed_rhs),
|
Some(fixed_rhs) => self.checked_rem(fixed_rhs),
|
||||||
None => Some(if_signed_unsigned!(
|
None => Some(if_signed_unsigned!(
|
||||||
$Signedness,
|
$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)
|
Self::from_bits(0)
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
|
@ -437,19 +444,26 @@ assert_eq!(Fix::from_num(7.5).checked_div_euclid_int(0), None);
|
||||||
|
|
||||||
comment! {
|
comment! {
|
||||||
"Checked remainder for Euclidean division by an integer.
|
"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
|
# Examples
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use fixed::{types::extra::U4, ", $s_fixed, "};
|
use fixed::{types::extra::U", $s_nbits_m4, ", ", $s_fixed, "};
|
||||||
type Fix = ", $s_fixed, "<U4>;
|
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(2), Some(Fix::from_num(1.5)));
|
||||||
assert_eq!(Fix::from_num(7.5).checked_rem_euclid_int(0), None);
|
assert_eq!(Fix::from_num(7.5).checked_rem_euclid_int(0), None);
|
||||||
",
|
",
|
||||||
if_signed_else_empty_str! {
|
if_signed_else_empty_str! {
|
||||||
$Signedness,
|
$Signedness,
|
||||||
"assert_eq!(Fix::from_num(-7.5).checked_rem_euclid_int(2), Some(Fix::from_num(0.5)));
|
"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]
|
#[inline]
|
||||||
pub fn checked_rem_euclid_int(self, rhs: $Inner) -> Option<$Fixed<Frac>> {
|
pub fn checked_rem_euclid_int(self, rhs: $Inner) -> Option<$Fixed<Frac>> {
|
||||||
// For signed rem_euclid_int, rhs can be made
|
if_signed! {
|
||||||
// negative without changing result.
|
$Signedness;
|
||||||
// Then, overflow converting rhs to $Fixed<Frac> means
|
let rem = self.checked_rem_int(rhs)?;
|
||||||
// that |rhs| > |self|, and so remainder is self.
|
if rem >= 0 {
|
||||||
let prep_rhs = if_signed_unsigned!(
|
return Some(rem);
|
||||||
$Signedness,
|
}
|
||||||
rhs.wrapping_abs().wrapping_neg(),
|
// Work in unsigned.
|
||||||
rhs,
|
// Answer required is |rhs| - |rem|, but rhs is int, rem is fixed.
|
||||||
);
|
// INT_NBITS == 0 is a special case, as fraction can be negative.
|
||||||
match Self::checked_from_num(prep_rhs) {
|
if Self::INT_NBITS == 0 {
|
||||||
Some(fixed_rhs) => self.checked_rem_euclid(fixed_rhs),
|
// -0.5 <= rem < 0, so euclidean remainder is in the range
|
||||||
None => Some(self),
|
// 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! {
|
comment! {
|
||||||
"Overflowing multiplication.
|
"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.
|
/// Remainder for division by an integer.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # 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) {
|
pub fn overflowing_rem_int(self, rhs: $Inner) -> ($Fixed<Frac>, bool) {
|
||||||
(self % rhs, false)
|
(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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -689,9 +689,9 @@ where
|
||||||
/// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None
|
/// [`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>;
|
fn checked_div_euclid_int(self, rhs: Self::Bits) -> Option<Self>;
|
||||||
|
|
||||||
/// Checked fixed-point remainder for Euclidean division by an
|
/// Checked remainder for Euclidean division by an integer.
|
||||||
/// integer. Returns the remainder, or [`None`] if the divisor is
|
/// Returns the remainder, or [`None`] if the divisor is zero or
|
||||||
/// zero.
|
/// if the remainder results in overflow.
|
||||||
///
|
///
|
||||||
/// [`None`]: https://doc.rust-lang.org/nightly/core/option/enum.Option.html#variant.None
|
/// [`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>;
|
fn checked_rem_euclid_int(self, rhs: Self::Bits) -> Option<Self>;
|
||||||
|
@ -785,6 +785,14 @@ where
|
||||||
/// Panics if the divisor is zero.
|
/// Panics if the divisor is zero.
|
||||||
fn wrapping_div_euclid_int(self, rhs: Self::Bits) -> Self;
|
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
|
/// Wrapping shift left. Wraps `rhs` if `rhs` ≥ the number of
|
||||||
/// bits, then shifts and returns the number.
|
/// bits, then shifts and returns the number.
|
||||||
fn wrapping_shl(self, rhs: u32) -> Self;
|
fn wrapping_shl(self, rhs: u32) -> Self;
|
||||||
|
@ -899,6 +907,20 @@ where
|
||||||
/// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html
|
/// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html
|
||||||
fn overflowing_div_euclid_int(self, rhs: Self::Bits) -> (Self, bool);
|
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.
|
/// Overflowing shift left.
|
||||||
///
|
///
|
||||||
/// Returns a [tuple] of the shifted value and a [`bool`],
|
/// 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) {
|
fn overflowing_rem_int(self, rhs: Self::Bits) -> (Self, bool) {
|
||||||
(self % rhs, false)
|
(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.
|
/// 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_mul_int(self, rhs: Self::Bits) -> Self }
|
||||||
trait_delegate! { fn wrapping_div_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_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_shl(self, rhs: u32) -> Self }
|
||||||
trait_delegate! { fn wrapping_shr(self, rhs: u32) -> Self }
|
trait_delegate! { fn wrapping_shr(self, rhs: u32) -> Self }
|
||||||
trait_delegate! { fn overflowing_neg(self) -> (Self, bool) }
|
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_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_int(self, rhs: Self::Bits) -> (Self, bool) }
|
||||||
trait_delegate! { fn overflowing_div_euclid_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_shl(self, rhs: u32) -> (Self, bool) }
|
||||||
trait_delegate! { fn overflowing_shr(self, rhs: u32) -> (Self, bool) }
|
trait_delegate! { fn overflowing_shr(self, rhs: u32) -> (Self, bool) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,7 +603,7 @@ impl<F: Fixed> Wrapping<F> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rem_euclid_int(self, divisor: F::Bits) -> Wrapping<F> {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue