From 5e5c24c0e9bd6abb542b8aacd7fb08127a12e036 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Tue, 29 Jan 2019 01:12:48 +0100 Subject: [PATCH] add overflowing rounding functions --- src/arith.rs | 32 +++-- src/lib.rs | 299 +++++++++++++++++++++++++++++++++----------- src/sealed_fixed.rs | 39 ++++++ 3 files changed, 284 insertions(+), 86 deletions(-) diff --git a/src/arith.rs b/src/arith.rs index 8eeb82b..7b5ba24 100644 --- a/src/arith.rs +++ b/src/arith.rs @@ -227,7 +227,7 @@ macro_rules! shift_all { macro_rules! fixed_arith { ($Fixed:ident($Inner:ty, $Len:ty, $bits_count:expr), $Signedness:tt) => { if_signed! { - $Signedness => pass_one! { impl Neg for $Fixed($Inner, $Len) { neg } } + $Signedness; pass_one! { impl Neg for $Fixed($Inner, $Len) { neg } } } pass! { impl Add for $Fixed($Inner, $Len) { add } } @@ -618,14 +618,16 @@ macro_rules! mul_div_widen { let rhs2 = <$Double as From<$Single>>::from(rhs) << int_bits; let (prod2, overflow) = lhs2.overflowing_mul(rhs2); let dir; - if_unsigned! { $Signedness => { + if_unsigned! { + $Signedness; dir = if !overflow { Ordering::Equal } else { Ordering::Less }; - } } - if_signed! { $Signedness => { + } + if_signed! { + $Signedness; dir = if !overflow { Ordering::Equal } else if (self < 0) == (rhs < 0) { @@ -633,7 +635,7 @@ macro_rules! mul_div_widen { } else { Ordering::Greater }; - } } + } ((prod2 >> BITS) as $Single, dir) } @@ -756,14 +758,16 @@ macro_rules! mul_div_fallback { if frac_bits == 0 { let (ans, overflow) = self.overflowing_mul(rhs); let dir; - if_unsigned! { $Signedness => { + if_unsigned! { + $Signedness; dir = if !overflow { Ordering::Equal } else { Ordering::Less }; - } } - if_signed! { $Signedness => { + } + if_signed! { + $Signedness; dir = if !overflow { Ordering::Equal } else if (self < 0) == (rhs < 0) { @@ -771,7 +775,7 @@ macro_rules! mul_div_fallback { } else { Ordering::Greater }; - } } + } (ans, dir) } else { let (lh, ll) = self.hi_lo(); @@ -796,14 +800,16 @@ macro_rules! mul_div_fallback { if frac_bits == 0 { let (ans, overflow) = self.overflowing_div(rhs); let dir; - if_unsigned! { $Signedness => { + if_unsigned! { + $Signedness; dir = if !overflow { Ordering::Equal } else { Ordering::Less }; - } } - if_signed! { $Signedness => { + } + if_signed! { + $Signedness; dir = if !overflow { Ordering::Equal } else if (self < 0) == (rhs < 0) { @@ -811,7 +817,7 @@ macro_rules! mul_div_fallback { } else { Ordering::Greater }; - } } + } (ans, dir) } else { const BITS: u32 = mem::size_of::<$Single>() as u32 * 8; diff --git a/src/lib.rs b/src/lib.rs index 3e6e156..e30be8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,16 +160,16 @@ extern crate serde; extern crate typenum; macro_rules! if_signed { - (Signed => $($rem:tt)+) => { + (Signed; $($rem:tt)+) => { $($rem)+ }; - (Unsigned => $($rem:tt)+) => { + (Unsigned; $($rem:tt)+) => { }; } macro_rules! if_unsigned { - (Signed => $($rem:tt)+) => { + (Signed; $($rem:tt)+) => { }; - (Unsigned => $($rem:tt)+) => { + (Unsigned; $($rem:tt)+) => { $($rem)+ }; } @@ -181,7 +181,7 @@ macro_rules! if_signed_unsigned { $unsigned }; ($Signedness:tt, $signed:expr, $unsigned:expr,) => { - if_signed_unsigned! { $Signedness, $signed, $unsigned } + if_signed_unsigned!($Signedness, $signed, $unsigned) }; } @@ -244,8 +244,8 @@ macro_rules! pass_method { macro_rules! pass_method_signed_unsigned { ($Signedness:tt, $signed:expr, $unsigned:expr, $($tt:tt)*) => { - if_signed! { $Signedness => pass_method! { $signed, $($tt)* } } - if_unsigned! { $Signedness => pass_method! { $unsigned, $($tt)* } } + if_signed! { $Signedness; pass_method! { $signed, $($tt)* } } + if_unsigned! { $Signedness; pass_method! { $unsigned, $($tt)* } } } } @@ -258,8 +258,8 @@ macro_rules! doc_comment { macro_rules! doc_comment_signed_unsigned { ($Signedness:tt, $signed:expr, $unsigned:expr, $($tt:tt)*) => { - if_signed! { $Signedness => doc_comment! { $signed, $($tt)* } } - if_unsigned! { $Signedness => doc_comment! { $unsigned, $($tt)* } } + if_signed! { $Signedness; doc_comment! { $signed, $($tt)* } } + if_unsigned! { $Signedness; doc_comment! { $unsigned, $($tt)* } } }; } @@ -536,11 +536,11 @@ macro_rules! fixed { "let src = Src::from_bits(0b111 << (16 - 2));\n", "let expected = Fix::from_bits(0b111 << (4 - 2));\n", "assert_eq!(Fix::from_fixed(src), expected);\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::from_fixed(-src), -expected);\n", "", - }, + ), "// src >> 4 is 0.0001_1100, which for Fix is truncated to 0000.0001\n", "assert_eq!(Fix::from_fixed(src >> 4), Fix::from_bits(1));\n", "```\n", @@ -586,21 +586,21 @@ macro_rules! fixed { "let src = Src::from_bits(0b111 << (16 - 2));\n", "let expected = Fix::from_bits(0b111 << (4 - 2));\n", "assert_eq!(Fix::checked_from_fixed(src), Some(expected));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::checked_from_fixed(-src), Some(-expected));\n", "", - }, + ), "let too_large = ", stringify!($Fixed), "::::max_value();\n", "assert!(Fix::checked_from_fixed(too_large).is_none());\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, concat!( "let too_small = ", stringify!($Fixed), "::::min_value();\n", "assert!(Fix::checked_from_fixed(too_small).is_none());\n", ), "", - }, + ), "```\n", ), #[inline] @@ -637,20 +637,20 @@ macro_rules! fixed { "let src = Src::from_bits(0b111 << (16 - 2));\n", "let expected = Fix::from_bits(0b111 << (4 - 2));\n", "assert_eq!(Fix::saturating_from_fixed(src), expected);\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::saturating_from_fixed(-src), -expected);\n", "", - }, + ), "let too_large = ", stringify!($Fixed), "::::max_value();\n", "assert_eq!(Fix::saturating_from_fixed(too_large), Fix::max_value());\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, concat!( "let too_small = ", stringify!($Fixed), "::::min_value();\n", ), "let too_small = Src::from_bits(-1);\n", - }, + ), "assert_eq!(Fix::saturating_from_fixed(too_small), Fix::min_value());\n", "```\n", ), @@ -721,11 +721,11 @@ macro_rules! fixed { "let src = Src::from_bits(0b111 << (16 - 2));\n", "let expected = Fix::from_bits(0b111 << (4 - 2));\n", "assert_eq!(Fix::wrapping_from_fixed(src), expected);\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::wrapping_from_fixed(-src), -expected);\n", "", - }, + ), "// integer 0b1101 << (", stringify!($nbits), " - 7) will wrap to fixed-point 1010...\n", "let large = ", stringify!($Fixed), "::::from_bits(0b1101 << (", stringify!($nbits), " - 7));\n", "let wrapped = Fix::from_bits(0b1010 << (", stringify!($nbits), " - 4));\n", @@ -760,11 +760,11 @@ macro_rules! fixed { "let src = Src::from_bits(0b111 << (16 - 2));\n", "let expected = Fix::from_bits(0b111 << (4 - 2));\n", "assert_eq!(Fix::overflowing_from_fixed(src), (expected, false));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::overflowing_from_fixed(-src), (-expected, false));\n", "", - }, + ), "// integer 0b1101 << (", stringify!($nbits), " - 7) will wrap to fixed-point 1010...\n", "let large = ", stringify!($Fixed), "::::from_bits(0b1101 << (", stringify!($nbits), " - 7));\n", "let wrapped = Fix::from_bits(0b1010 << (", stringify!($nbits), " - 4));\n", @@ -833,11 +833,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 3 is 0011.0000, that is from_bits(3 << 4)\n", "assert_eq!(Fix::from_int(3), Fix::from_bits(3 << 4));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::from_int(-3), Fix::from_bits(-3 << 4));\n", "", - }, + ), "```\n", "\n", "[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html\n", @@ -886,21 +886,21 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 3 is 0011.0000, that is from_bits(3 << 4)\n", "assert_eq!(Fix::checked_from_int(3), Some(Fix::from_bits(3 << 4)));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::checked_from_int(-3), Some(Fix::from_bits(-3 << 4)));\n", "", - }, + ), "let too_large = ", stringify!($Inner), "::max_value();\n", "assert!(Fix::checked_from_int(too_large).is_none());\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, concat!( "let too_small = ", stringify!($Inner), "::min_value();\n", "assert!(Fix::checked_from_int(too_small).is_none());\n", ), "", - }, + ), "```\n", "\n", "[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html\n", @@ -942,20 +942,20 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 3 is 0011.0000, that is from_bits(3 << 4)\n", "assert_eq!(Fix::saturating_from_int(3), Fix::from_bits(3 << 4));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::saturating_from_int(-3), Fix::from_bits(-3 << 4));\n", "", - }, + ), "let too_large = ", stringify!($Inner), "::max_value();\n", "assert_eq!(Fix::saturating_from_int(too_large), Fix::max_value());\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, concat!( "let too_small = ", stringify!($Inner), "::min_value();\n", ), "let too_small = -1;\n", - }, + ), "assert_eq!(Fix::saturating_from_int(too_small), Fix::min_value());\n", "```\n", "\n", @@ -1030,11 +1030,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 3 is 0011.0000, that is from_bits(3 << 4)\n", "assert_eq!(Fix::wrapping_from_int(3), Fix::from_bits(3 << 4));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::wrapping_from_int(-3), Fix::from_bits(-3 << 4));\n", "", - }, + ), "// integer 0b1101 << (", stringify!($nbits), " - 7) will wrap to fixed-point 1010...\n", "let large: ", stringify!($Inner), " = 0b1101 << (", stringify!($nbits), " - 7);\n", "let wrapped = Fix::from_bits(0b1010 << (", stringify!($nbits), " - 4));\n", @@ -1080,11 +1080,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 3 is 0011.0000, that is from_bits(3 << 4)\n", "assert_eq!(Fix::overflowing_from_int(3), (Fix::from_bits(3 << 4), false));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::overflowing_from_int(-3), (Fix::from_bits(-3 << 4), false));\n", "", - }, + ), "// integer 0b1101 << (", stringify!($nbits), " - 7) will wrap to fixed-point 1010...\n", "let large: ", stringify!($Inner), " = 0b1101 << (", stringify!($nbits), " - 7);\n", "let wrapped = Fix::from_bits(0b1010 << (", stringify!($nbits), " - 4));\n", @@ -1176,17 +1176,19 @@ macro_rules! fixed { #[inline] pub fn to_int(self) -> $Inner { let floor = self.to_int_floor(); - if_signed! { $Signedness => { + if_signed! { + $Signedness; let no_frac = self.frac().to_bits() == 0; if no_frac || self.to_bits() >= 0 { floor } else { floor + 1 } - } } - if_unsigned! { $Signedness => { + } + if_unsigned! { + $Signedness; floor - } } + } } } @@ -1274,8 +1276,8 @@ macro_rules! fixed { pub fn to_int_floor(self) -> $Inner { let bits = self.to_bits(); if Self::int_bits() == 0 { - if_signed! { $Signedness => bits >> (Self::frac_bits() - 1) } - if_unsigned! { $Signedness => 0 } + if_signed! { $Signedness; bits >> (Self::frac_bits() - 1) } + if_unsigned! { $Signedness; 0 } } else { bits >> Self::frac_bits() } @@ -1329,7 +1331,8 @@ macro_rules! fixed { return floor; } let half_bit = 1 << (frac_bits - 1); - if_signed! { $Signedness => { + if_signed! { + $Signedness; if self.to_bits() >= 0 { if (self.to_bits() & half_bit) != 0 { floor + 1 @@ -1344,14 +1347,15 @@ macro_rules! fixed { floor + 1 } } - } } - if_unsigned! { $Signedness => { + } + if_unsigned! { + $Signedness; if (self.to_bits() & half_bit) != 0 { floor + 1 } else { floor } - } } + } } } @@ -1383,11 +1387,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 1.75 is 0001.1100, that is from_bits(28)\n", "assert_eq!(Fix::from_float(1.75f32), Fix::from_bits(28));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::from_float(-1.75f64), Fix::from_bits(-28));\n", "assert_eq!(Fix::from_float(1.75f64), Fix::from_bits(28));\n", - }, + ), "// 1e-10 is too small for four fractional bits\n", "assert_eq!(Fix::from_float(1e-10), Fix::from_bits(0));\n", "```\n", @@ -1435,11 +1439,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 1.75 is 0001.1100, that is from_bits(28)\n", "assert_eq!(Fix::checked_from_float(1.75f32), Some(Fix::from_bits(28)));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::checked_from_float(-1.75f64), Some(Fix::from_bits(-28)));\n", "assert_eq!(Fix::checked_from_float(1.75f64), Some(Fix::from_bits(28)));\n", - }, + ), "// 1e-10 is too small for four fractional bits\n", "assert_eq!(Fix::checked_from_float(1e-10), Some(Fix::from_bits(0)));\n", "// 2e38 is too large for ", stringify!($Fixed), "\n", @@ -1493,11 +1497,11 @@ macro_rules! fixed { "type Fix = ", stringify!($Fixed), ";\n", "// 1.75 is 0001.1100, that is from_bits(28)\n", "assert_eq!(Fix::saturating_from_float(1.75f32), Fix::from_bits(28));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::saturating_from_float(-1.75f64), Fix::from_bits(-28));\n", "assert_eq!(Fix::saturating_from_float(1.75f64), Fix::from_bits(28));\n", - }, + ), "// 1e-10 is too small for four fractional bits\n", "assert_eq!(Fix::saturating_from_float(1e-10), Fix::from_bits(0));\n", "// 2e38 is too large for ", stringify!($Fixed), "\n", @@ -1580,11 +1584,11 @@ macro_rules! fixed { "// 1.75 is 0001.1100, that is from_bits(28)\n", "let from_bits = Fix::from_bits(28);\n", "assert_eq!(Fix::wrapping_from_float(1.75f32), from_bits);\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::wrapping_from_float(-1.75f64), -from_bits);\n", "assert_eq!(Fix::wrapping_from_float(1.75f64), from_bits);\n", - }, + ), "// 1e-10 is too small for four fractional bits\n", "assert_eq!(Fix::wrapping_from_float(1e-10), 0);\n", "// 1.75 << (", stringify!($nbits), " - 4) wraps to binary 11000...\n", @@ -1633,11 +1637,11 @@ macro_rules! fixed { "// 1.75 is 0001.1100, that is from_bits(28)\n", "let from_bits = Fix::from_bits(28);\n", "assert_eq!(Fix::overflowing_from_float(1.75f32), (from_bits, false));\n", - if_signed_unsigned! { + if_signed_unsigned!( $Signedness, "assert_eq!(Fix::overflowing_from_float(-1.75f64), (-from_bits, false));\n", "assert_eq!(Fix::overflowing_from_float(1.75f64), (from_bits, false));\n", - }, + ), "// 1e-10 is too small for four fractional bits\n", "assert_eq!(Fix::overflowing_from_float(1e-10), (Fix::from_bits(0), false));\n", "// 1.75 << (", stringify!($nbits), " - 4) overflows and wraps to binary 11000...\n", @@ -1811,9 +1815,7 @@ macro_rules! fixed { ), #[inline] pub fn int(self) -> $Fixed { - let frac_bits = <$Fixed>::frac_bits(); - let mask = <$Inner>::checked_shl(!0, frac_bits).unwrap_or(0); - $Fixed::from_bits(self.to_bits() & mask) + $Fixed::from_bits(self.to_bits() & Self::int_mask()) } } @@ -1865,9 +1867,7 @@ macro_rules! fixed { ), #[inline] pub fn frac(self) -> $Fixed { - let frac_bits = <$Fixed>::frac_bits(); - let inv_mask = <$Inner>::checked_shl(!0, frac_bits).unwrap_or(0); - $Fixed::from_bits(self.to_bits() & !inv_mask) + $Fixed::from_bits(self.to_bits() & Self::frac_mask()) } } @@ -2044,7 +2044,7 @@ macro_rules! fixed { } if_signed! { - $Signedness => + $Signedness; /// Checked absolute value. #[inline] pub fn checked_abs(self) -> Option<$Fixed> { @@ -2155,7 +2155,7 @@ macro_rules! fixed { } if_signed! { - $Signedness => + $Signedness; /// Wrapping absolute value. #[inline] pub fn wrapping_abs(self) -> $Fixed { @@ -2234,7 +2234,7 @@ macro_rules! fixed { } if_signed! { - $Signedness => + $Signedness; /// Overflowing absolute value. #[inline] pub fn overflowing_abs(self) -> ($Fixed, bool) { @@ -2243,8 +2243,155 @@ macro_rules! fixed { } } + doc_comment! { + concat!(r#" +Overflowing ceil. Rounds towards +∞. + +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::frac; +use fixed::"#, stringify!($Fixed), r#"; +type Fix = "#, stringify!($Fixed), r#"; +let two_half = Fix::from_int(5) / 2; +assert_eq!(two_half.overflowing_ceil(), (Fix::from_int(3), false));"#, +if_signed_unsigned!($Signedness, r#" +assert_eq!((-two_half).overflowing_ceil(), (Fix::from_int(-2), false));"#, "" +), r#" +assert_eq!(Fix::max_value().overflowing_ceil(), (Fix::min_value(), true)); +``` +"#, + ), + #[inline] + pub fn overflowing_ceil(self) -> ($Fixed, bool) { + let int = self.int(); + if self.frac() == 0 { + return (int, false); + } + if Self::int_bits() == 0 { + return (int, self.to_bits() > 0); + } + let increment = Self::from_bits(::lowest_int_bit()); + if_signed! { + $Signedness; + if Self::int_bits() == 1 { + return int.overflowing_sub(increment); + } + } + int.overflowing_add(increment) + } + } + + doc_comment! { + concat!(r#" +Overflowing floor. Rounds towards −∞. + +"#, if_signed_unsigned!($Signedness, r#" +Returns a tuple of the fixed-point number and a [`bool`], indicating +whether an overflow has occurred. On overflow, the wrapped value is +returned. Overflow can only occur when there are zero integer bits. +"#, r#" +Returns a tuple of the fixed-point number and [`false`][`bool`]. +"#), r#" + +# Examples + +```rust +use fixed::frac; +use fixed::"#, stringify!($Fixed), r#"; +type Fix = "#, stringify!($Fixed), r#"; +let two_half = Fix::from_int(5) / 2; +assert_eq!(two_half.overflowing_floor(), (Fix::from_int(2), false));"#, +if_signed_unsigned!($Signedness, concat!(r#" +assert_eq!((-two_half).overflowing_floor(), (Fix::from_int(-3), false)); +type AllFrac = "#, stringify!($Fixed), "; +assert_eq!(AllFrac::min_value().overflowing_floor(), (AllFrac::from_int(0), true));"#), "" +), r#" +``` +"#, + ), + #[inline] + pub fn overflowing_floor(self) -> ($Fixed, bool) { + let int = self.int(); + if_signed! { + $Signedness; + if Self::int_bits() == 0 { + return (int, self.to_bits() < 0); + } + } + return (int, false); + } + } + + doc_comment! { + concat!(r#" +Overflowing round. Rounds to the nearest, with ties rounded away from +zero. + +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::frac; +use fixed::"#, stringify!($Fixed), r#"; +type Fix = "#, stringify!($Fixed), r#"; +let two_half = Fix::from_int(5) / 2; +assert_eq!(two_half.overflowing_round(), (Fix::from_int(3), false));"#, +if_signed_unsigned!($Signedness, r#" +assert_eq!((-two_half).overflowing_round(), (Fix::from_int(-3), false));"#, "" +), r#" +assert_eq!(Fix::max_value().overflowing_round(), (Fix::min_value(), true)); +``` +"#, + ), + #[inline] + pub fn overflowing_round(self) -> ($Fixed, bool) { + let int = self.int(); + let highest_frac_bit = ::highest_frac_bit(); + if (self.to_bits() & highest_frac_bit) == 0 { + return (int, false); + } + let increment = Self::from_bits(::lowest_int_bit()); + if_signed! { + $Signedness; + let tie = self.frac().to_bits() == highest_frac_bit; + if Self::int_bits() == 0 { + // if num is .100...00 = -0.5, we have overflow + // otherwise .100...01, 0 < x < -0.5, no overflow + return (int, tie); + } + // If num is −int.100...00 = (-int) + 0.5, we simply truncate to move to −∞. + // If num is −int.100...01 = (-int) + 0.6, we add 1 to −int. + // If num is +int.100...00 = (+int) + 0.5, we add 1 to +int. + // If num is +int.100...01 = (+int) + 0.6, we add 1 to +int. + if tie && self.to_bits() < 0 { + return (int, false); + } + if Self::int_bits() == 1 { + return int.overflowing_sub(increment); + } + int.overflowing_add(increment) + } + if_unsigned! { + $Signedness; + if Self::int_bits() == 0 { + return (int, true); + } + int.overflowing_add(increment) + } + } + } + if_unsigned! { - $Signedness => pass_method! { + $Signedness; + pass_method! { concat!( "Returns `true` if the fixed-point number is\n", "2k for some k.\n", @@ -2268,7 +2415,8 @@ macro_rules! fixed { } if_unsigned! { - $Signedness => pass_method! { + $Signedness; + pass_method! { concat!( "Returns the smallest power of two ≥ `self`.\n", "\n", @@ -2291,7 +2439,8 @@ macro_rules! fixed { } if_unsigned! { - $Signedness => doc_comment! { + $Signedness; + doc_comment! { concat!( "Returns the smallest power of two ≥ `self`, or `None`\n", "if the next power of two is too large to represent.\n", @@ -2318,7 +2467,8 @@ macro_rules! fixed { } if_signed! { - $Signedness => pass_method! { + $Signedness; + pass_method! { concat!( "Returns the absolute value.\n", "\n", @@ -2339,7 +2489,8 @@ macro_rules! fixed { } if_signed! { - $Signedness => doc_comment! { + $Signedness; + doc_comment! { concat!( "Returns a number representing the sign of `self`.\n", "\n", @@ -2381,7 +2532,8 @@ macro_rules! fixed { } if_signed! { - $Signedness => pass_method! { + $Signedness; + pass_method! { concat!( "Returns `true` if the number is > 0.\n", "\n", @@ -2404,7 +2556,8 @@ macro_rules! fixed { } if_signed! { - $Signedness => pass_method! { + $Signedness; + pass_method! { concat!( "Returns `true` if the number is < 0.\n", "\n", diff --git a/src/sealed_fixed.rs b/src/sealed_fixed.rs index 6849530..ceb82a8 100644 --- a/src/sealed_fixed.rs +++ b/src/sealed_fixed.rs @@ -49,6 +49,13 @@ pub trait SealedFixed: Copy + Debug + Display { } } + fn frac_mask() -> Self::Bits; + fn int_mask() -> Self::Bits; + // 0 for no frac bits + fn highest_frac_bit() -> Self::Bits; + // 0 for no int bits + fn lowest_int_bit() -> Self::Bits; + fn from_bits(bits: Self::Bits) -> Self; fn to_bits(self) -> Self::Bits; fn parts( @@ -76,6 +83,38 @@ macro_rules! sealed_fixed { Frac::to_u32() } + #[inline] + fn frac_mask() -> Self::Bits { + !Self::int_mask() + } + + #[inline] + fn int_mask() -> Self::Bits { + if Self::int_bits() == 0 { + 0 + } else { + !0 << Self::frac_bits() + } + } + + #[inline] + fn highest_frac_bit() -> Self::Bits { + if Self::frac_bits() == 0 { + 0 + } else { + 1 << (Self::frac_bits() - 1) + } + } + + #[inline] + fn lowest_int_bit() -> Self::Bits { + if Self::int_bits() == 0 { + 0 + } else { + 1 << Self::frac_bits() + } + } + #[inline] fn from_bits(bits: Self::Bits) -> Self { $Fixed::from_bits(bits)