add round_ties_to_even and checked variants

This commit is contained in:
Trevor Spiteri 2019-08-22 13:01:28 +02:00
parent b3796a46f0
commit 0eade78071
5 changed files with 353 additions and 15 deletions

View File

@ -65,11 +65,14 @@ Various conversion methods are available:
* The following methods are now `const` functions:
* [`abs`], [`wrapping_abs`], [`overflowing_abs`]
* [`is_power_of_two`]
* The method [`round_ties_to_even`] and its checked variants were
added.
[`abs`]: https://docs.rs/fixed/0.4.3/fixed/struct.FixedI32.html#method.abs
[`is_power_of_two`]: https://docs.rs/fixed/0.4.3/fixed/struct.FixedU32.html#method.is_power_of_two
[`overflowing_abs`]: https://docs.rs/fixed/0.4.3/fixed/struct.FixedI32.html#method.overflowing_abs
[`wrapping_abs`]: https://docs.rs/fixed/0.4.3/fixed/struct.FixedI32.html#method.wrapping_abs
[`round_ties_to_even`]: https://docs.rs/fixed/0.4.3/fixed/struct.FixedI32.html#method.round_ties_to_even
### Version 0.4.3 news (2019-08-20)

View File

@ -13,6 +13,8 @@ Version 0.4.4 (unreleased)
* The following methods are now `const` functions:
* `abs`, `wrapping_abs`, `overflowing_abs`
* `is_power_of_two`
* The method `round_ties_to_even` and its checked variants were
added.
Version 0.4.3 (2019-08-20)
==========================

View File

@ -391,19 +391,20 @@ fixed! { "A 32-bit fixed-point signed", FixedI32(i32, LeEqU32, "32"), u32, Signe
fixed! { "A 64-bit fixed-point signed", FixedI64(i64, LeEqU64, "64"), u64, Signed }
fixed! { "A 128-bit fixed-point signed", FixedI128(i128, LeEqU128, "128"), u128, Signed }
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
#[cfg(test)]
mod tests {
use crate::types::{I0F32, I16F16, U0F32, U16F16};
use crate::types::{I0F32, I16F16, I1F31, U0F32, U16F16};
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
#[test]
fn rounding() {
fn rounding_signed() {
// -0.5
let f = I0F32::from_bits(-1 << 31);
assert_eq!(f.to_num::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I0F32::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I0F32::from_num(0), true));
assert_eq!(f.overflowing_round(), (I0F32::from_num(0), true));
assert_eq!(f.overflowing_round_ties_to_even(), (I0F32::from_num(0), false));
// -0.5 + Δ
let f = I0F32::from_bits((-1 << 31) + 1);
@ -411,6 +412,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I0F32::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I0F32::from_num(0), true));
assert_eq!(f.overflowing_round(), (I0F32::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I0F32::from_num(0), false));
// 0.5 - Δ
let f = I0F32::from_bits((1 << 30) - 1 + (1 << 30));
@ -418,27 +420,55 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (I0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (I0F32::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I0F32::from_num(0), false));
// -0.5 - Δ
let f = I1F31::from_bits(((-1) << 30) - 1);
assert_eq!(f.to_num::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(-1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(-1), false));
// -0.5
let f = I1F31::from_bits((-1) << 30);
assert_eq!(f.to_num::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(-1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(0), false));
// -0.5 + Δ
let f = I1F31::from_bits(((-1) << 30) + 1);
assert_eq!(f.to_num::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(0), false));
// 0.5 - Δ
let f = U0F32::from_bits((1 << 31) - 1);
let f = I1F31::from_bits((1 << 30) - 1);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(-1), true));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(0), false));
// 0.5
let f = U0F32::from_bits(1 << 31);
let f = I1F31::from_bits(1 << 30);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(-1), true));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(-1), true));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(0), false));
// 0.5 + Δ
let f = U0F32::from_bits((1 << 31) + 1);
let f = I1F31::from_bits((1 << 30) + 1);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_ceil(), (I1F31::from_num(-1), true));
assert_eq!(f.overflowing_floor(), (I1F31::from_num(0), false));
assert_eq!(f.overflowing_round(), (I1F31::from_num(-1), true));
assert_eq!(f.overflowing_round_ties_to_even(), (I1F31::from_num(-1), true));
// -3.5 - Δ
let f = I16F16::from_bits(((-7) << 15) - 1);
@ -446,6 +476,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-4), false));
// -3.5
let f = I16F16::from_bits((-7) << 15);
@ -453,6 +484,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-4), false));
// -3.5 + Δ
let f = I16F16::from_bits(((-7) << 15) + 1);
@ -460,6 +492,31 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-3), false));
// -2.5 - Δ
let f = I16F16::from_bits(((-5) << 15) - 1);
assert_eq!(f.to_num::<i32>(), -3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-2), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-3), false));
// -2.5
let f = I16F16::from_bits((-5) << 15);
assert_eq!(f.to_num::<i32>(), -3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-2), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-2), false));
// -2.5 + Δ
let f = I16F16::from_bits(((-5) << 15) + 1);
assert_eq!(f.to_num::<i32>(), -3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(-2), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-2), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-2), false));
// -0.5 - Δ
let f = I16F16::from_bits(((-1) << 15) - 1);
@ -467,6 +524,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(-1), false));
// -0.5
let f = I16F16::from_bits((-1) << 15);
@ -474,6 +532,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(-1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(0), false));
// -0.5 + Δ
let f = I16F16::from_bits(((-1) << 15) + 1);
@ -481,6 +540,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(0), false));
// 0.5 - Δ
let f = I16F16::from_bits((1 << 15) - 1);
@ -488,6 +548,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(0), false));
// 0.5
let f = I16F16::from_bits(1 << 15);
@ -495,6 +556,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(0), false));
// 0.5 + Δ
let f = I16F16::from_bits((1 << 15) + 1);
@ -502,6 +564,31 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(1), false));
// 2.5 - Δ
let f = I16F16::from_bits((5 << 15) - 1);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(2), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(2), false));
// 2.5
let f = I16F16::from_bits(5 << 15);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(2), false));
// 2.5 + Δ
let f = I16F16::from_bits((5 << 15) + 1);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(3), false));
// 3.5 - Δ
let f = I16F16::from_bits((7 << 15) - 1);
@ -509,6 +596,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(3), false));
// 3.5
let f = I16F16::from_bits(7 << 15);
@ -516,6 +604,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(4), false));
// 3.5 + Δ
let f = I16F16::from_bits((7 << 15) + 1);
@ -523,6 +612,34 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (I16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_num(4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (I16F16::from_num(4), false));
}
#[test]
fn rounding_unsigned() {
// 0.5 - Δ
let f = U0F32::from_bits((1 << 31) - 1);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U0F32::from_num(0), false));
// 0.5
let f = U0F32::from_bits(1 << 31);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_round_ties_to_even(), (U0F32::from_num(0), false));
// 0.5 + Δ
let f = U0F32::from_bits((1 << 31) + 1);
assert_eq!(f.to_num::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_num(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_num(0), true));
assert_eq!(f.overflowing_round_ties_to_even(), (U0F32::from_num(0), true));
// 0.5 - Δ
let f = U16F16::from_bits((1 << 15) - 1);
@ -530,6 +647,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(0), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(0), false));
// 0.5
let f = U16F16::from_bits(1 << 15);
@ -537,6 +655,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(0), false));
// 0.5 + Δ
let f = U16F16::from_bits((1 << 15) + 1);
@ -544,6 +663,31 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(1), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(1), false));
// 2.5 - Δ
let f = U16F16::from_bits((5 << 15) - 1);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(2), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(2), false));
// 2.5
let f = U16F16::from_bits(5 << 15);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(2), false));
// 2.5 + Δ
let f = U16F16::from_bits((5 << 15) + 1);
assert_eq!(f.to_num::<i32>(), 2);
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(2), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(3), false));
// 3.5 - Δ
let f = U16F16::from_bits((7 << 15) - 1);
@ -551,6 +695,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(3), false));
// 3.5
let f = U16F16::from_bits(7 << 15);
@ -558,6 +703,7 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(4), false));
// 3.5 + Δ
let f = U16F16::from_bits((7 << 15) + 1);
@ -565,5 +711,6 @@ mod tests {
assert_eq!(f.overflowing_ceil(), (U16F16::from_num(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_num(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_num(4), false));
assert_eq!(f.overflowing_round_ties_to_even(), (U16F16::from_num(4), false));
}
}

View File

@ -212,6 +212,37 @@ assert_eq!(two_half.round(), Fix::from_num(3));
}
}
comment! {
"Rounds to the nearest integer, with ties rounded to even.
# Panics
When debug assertions are enabled, panics if the result does not fit.
When debug assertions are not enabled, the wrapped result can be
returned, but it is not considered a breaking change if in the future
it panics; if wrapping is required use [`wrapping_round_ties_to_even`]
instead.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(2.5).round_ties_to_even(), Fix::from_num(2));
assert_eq!(Fix::from_num(3.5).round_ties_to_even(), Fix::from_num(4));
```
[`wrapping_round_ties_to_even`]: #method.wrapping_round_ties_to_even
";
#[inline]
pub fn round_ties_to_even(self) -> $Fixed<Frac> {
let (round, overflow) = self.overflowing_round_ties_to_even();
debug_assert!(!overflow, "overflow");
let _ = overflow;
round
}
}
comment! {
"Checked ceil. Rounds to the next integer towards +∞,
returning [`None`] on overflow.
@ -325,6 +356,29 @@ assert_eq!(two_half.checked_round(), Some(Fix::from_num(3)));
}
}
comment! {
"Checked round. Rounds to the nearest integer, with ties
rounded to even, returning [`None`] on overflow.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(2.5).checked_round_ties_to_even(), Some(Fix::from_num(2)));
assert_eq!(Fix::from_num(3.5).checked_round_ties_to_even(), Some(Fix::from_num(4)));
assert!(Fix::max_value().checked_round_ties_to_even().is_none());
```
[`None`]: https://doc.rust-lang.org/nightly/std/option/enum.Option.html#variant.None
";
#[inline]
pub fn checked_round_ties_to_even(self) -> Option<$Fixed<Frac>> {
let (round, overflow) = self.overflowing_round_ties_to_even();
if overflow { None } else { Some(round) }
}
}
comment! {
"Saturating ceil. Rounds to the next integer towards +∞,
saturating on overflow.
@ -430,6 +484,32 @@ assert_eq!(two_half.saturating_round(), Fix::from_num(3));
}
}
comment! {
"Saturating round. Rounds to the nearest integer, with
ties rounded to even, and saturating on overflow.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(2.5).saturating_round_ties_to_even(), Fix::from_num(2));
assert_eq!(Fix::from_num(3.5).saturating_round_ties_to_even(), Fix::from_num(4));
assert_eq!(Fix::max_value().saturating_round_ties_to_even(), Fix::max_value());
```
";
#[inline]
pub fn saturating_round_ties_to_even(self) -> $Fixed<Frac> {
let saturated = if self.to_bits() > 0 {
$Fixed::max_value()
} else {
$Fixed::min_value()
};
let (round, overflow) = self.overflowing_round_ties_to_even();
if overflow { saturated } else { round }
}
}
comment! {
"Wrapping ceil. Rounds to the next integer towards +∞,
wrapping on overflow.
@ -527,6 +607,26 @@ assert_eq!(two_half.wrapping_round(), Fix::from_num(3));
}
}
comment! {
"Wrapping round. Rounds to the next integer to the
nearest, with ties rounded to even, and wrapping on overflow.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(2.5).wrapping_round_ties_to_even(), Fix::from_num(2));
assert_eq!(Fix::from_num(3.5).wrapping_round_ties_to_even(), Fix::from_num(4));
assert_eq!(Fix::max_value().wrapping_round_ties_to_even(), Fix::min_value());
```
";
#[inline]
pub fn wrapping_round_ties_to_even(self) -> $Fixed<Frac> {
self.overflowing_round_ties_to_even().0
}
}
comment! {
"Overflowing ceil. Rounds to the next integer towards +∞.
@ -681,6 +781,7 @@ assert_eq!(two_half.overflowing_round(), (Fix::from_num(3), false));
return (int, false);
}
if Self::INT_NBITS == 1 {
// increment is -1, so subtract it
return int.overflowing_sub(increment);
}
int.overflowing_add(increment)
@ -694,5 +795,57 @@ assert_eq!(two_half.overflowing_round(), (Fix::from_num(3), false));
}
}
}
comment! {
"Overflowing round. Rounds to the next integer to the
nearest, with ties rounded to even.
Returns a [tuple] of the fixed-point number and a [`bool`] indicating
whether an overflow has occurred. On overflow, the wrapped value is
returned.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(2.5).overflowing_round_ties_to_even(), (Fix::from_num(2), false));
assert_eq!(Fix::from_num(3.5).overflowing_round_ties_to_even(), (Fix::from_num(4), false));
assert_eq!(Fix::max_value().overflowing_round_ties_to_even(), (Fix::min_value(), 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_round_ties_to_even(self) -> ($Fixed<Frac>, bool) {
let int = self.int();
if (self.to_bits() & Self::FRAC_MSB) == 0 {
return (int, false);
}
if self.frac().to_bits() == Self::FRAC_MSB && (int.to_bits() & Self::INT_LSB) == 0 {
return (int, false);
}
let increment = Self::from_bits(Self::INT_LSB);
if_signed! {
$Signedness;
// If INT_NBITS is 0, increment is zero, and -0.5 ≤ self < 0.5,
// so we're fine returning 0.overflowing_add(0).
if Self::INT_NBITS == 1 {
// increment is -1, so subtract it
int.overflowing_sub(increment)
} else {
int.overflowing_add(increment)
}
}
if_unsigned! {
$Signedness;
if Self::INT_NBITS == 0 {
return (int, true);
}
int.overflowing_add(increment)
}
}
}
};
}

View File

@ -421,6 +421,9 @@ where
/// Rounds to the nearest integer, with ties rounded away from zero.
fn round(self) -> Self;
/// Rounds to the nearest integer, with ties rounded to even.
fn round_ties_to_even(self) -> Self;
/// Checked ceil. Rounds to the next integer towards +∞, returning
/// [`None`] on overflow.
///
@ -439,6 +442,12 @@ where
/// [`None`]: https://doc.rust-lang.org/nightly/std/option/enum.Option.html#variant.None
fn checked_round(self) -> Option<Self>;
/// Checked round. Rounds to the nearest integer, with ties
/// rounded to even, returning [`None`] on overflow.
///
/// [`None`]: https://doc.rust-lang.org/nightly/std/option/enum.Option.html#variant.None
fn checked_round_ties_to_even(self) -> Option<Self>;
/// Saturating ceil. Rounds to the next integer towards +∞,
/// saturating on overflow.
fn saturating_ceil(self) -> Self;
@ -451,6 +460,10 @@ where
/// rounded away from zero, and saturating on overflow.
fn saturating_round(self) -> Self;
/// Saturating round. Rounds to the nearest integer, with ties
/// rounded to_even, and saturating on overflow.
fn saturating_round_ties_to_even(self) -> Self;
/// Wrapping ceil. Rounds to the next integer towards +∞, wrapping
/// on overflow.
fn wrapping_ceil(self) -> Self;
@ -463,6 +476,10 @@ where
/// with ties rounded away from zero, and wrapping on overflow.
fn wrapping_round(self) -> Self;
/// Wrapping round. Rounds to the next integer to the nearest,
/// with ties rounded to even, and wrapping on overflow.
fn wrapping_round_ties_to_even(self) -> Self;
/// Overflowing ceil. Rounds to the next integer towards +∞.
///
/// Returns a [tuple] of the fixed-point number and a [`bool`],
@ -494,6 +511,17 @@ where
/// [tuple]: https://doc.rust-lang.org/nightly/std/primitive.tuple.html
fn overflowing_round(self) -> (Self, bool);
/// Overflowing round. Rounds to the next integer to the nearest,
/// with ties rounded to even.
///
/// Returns a [tuple] of the fixed-point number 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_round_ties_to_even(self) -> (Self, bool);
/// Returns the number of ones in the binary representation.
fn count_ones(self) -> u32;
@ -1447,18 +1475,23 @@ macro_rules! impl_fixed {
trait_delegate! { fn ceil(self) -> Self }
trait_delegate! { fn floor(self) -> Self }
trait_delegate! { fn round(self) -> Self }
trait_delegate! { fn round_ties_to_even(self) -> Self }
trait_delegate! { fn checked_ceil(self) -> Option<Self> }
trait_delegate! { fn checked_floor(self) -> Option<Self> }
trait_delegate! { fn checked_round(self) -> Option<Self> }
trait_delegate! { fn checked_round_ties_to_even(self) -> Option<Self> }
trait_delegate! { fn saturating_ceil(self) -> Self }
trait_delegate! { fn saturating_floor(self) -> Self }
trait_delegate! { fn saturating_round(self) -> Self }
trait_delegate! { fn saturating_round_ties_to_even(self) -> Self }
trait_delegate! { fn wrapping_ceil(self) -> Self }
trait_delegate! { fn wrapping_floor(self) -> Self }
trait_delegate! { fn wrapping_round(self) -> Self }
trait_delegate! { fn wrapping_round_ties_to_even(self) -> Self }
trait_delegate! { fn overflowing_ceil(self) -> (Self, bool) }
trait_delegate! { fn overflowing_floor(self) -> (Self, bool) }
trait_delegate! { fn overflowing_round(self) -> (Self, bool) }
trait_delegate! { fn overflowing_round_ties_to_even(self) -> (Self, bool) }
trait_delegate! { fn count_ones(self) -> u32 }
trait_delegate! { fn count_zeros(self) -> u32 }
trait_delegate! { fn leading_zeros(self) -> u32 }