add from_int, to_int*, frac and int methods
This commit is contained in:
parent
29a067e3e9
commit
8f64db356a
12
README.md
12
README.md
|
@ -38,10 +38,20 @@ fixed-point numbers.
|
|||
### Version 0.1.1 news (unreleased)
|
||||
|
||||
* New static methods [`int_bits`] and [`frac_bits`] were added.
|
||||
* New methods [`from_int`], [`to_int`], [`to_int_ceil`],
|
||||
[`to_int_floor`] and [`to_int_round`] were added.
|
||||
* New methods [`int`] and [`frac`] were added.
|
||||
* Support for multiplication and division by integers was added.
|
||||
|
||||
[`frac_bits`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.frac_bits
|
||||
[`int_bits`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.int_bits
|
||||
[`frac`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.frac
|
||||
[`from_int`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.from_int
|
||||
[`to_int_bits`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.to_int_bits
|
||||
[`to_int_ceil`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.to_int_ceil
|
||||
[`to_int_floor`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.to_int_floor
|
||||
[`to_int_round`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.to_int_round
|
||||
[`to_int`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.to_int
|
||||
[`int`]: https://docs.rs/fixed/0.1.0/fixed/struct.FixedI32.html#method.int
|
||||
|
||||
### Version 0.1.0 news (2018-08-10)
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ Version 0.1.1 (unreleased)
|
|||
==========================
|
||||
|
||||
* New static methods `int_bits` and `frac_bits` were added.
|
||||
* New methods `from_int`, `to_int`, `to_int_ceil`, `to_int_floor`
|
||||
and `to_int_round`.
|
||||
* New methods `int` and `frac` were added.
|
||||
* Support for multiplication and division by integers was added.
|
||||
|
||||
Version 0.1.0 (2018-08-10)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright © 2018 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
/*!
|
||||
This module reexports items from the [*typenum* crate].
|
||||
|
||||
[*typenum* crate]: https://crates.io/crates/typenum
|
||||
*/
|
||||
|
||||
pub use typenum::{
|
||||
U0, U1, U10, U100, U101, U102, U103, U104, U105, U106, U107, U108, U109, U11, U110, U111, U112,
|
||||
U113, U114, U115, U116, U117, U118, U119, U12, U120, U121, U122, U123, U124, U125, U126, U127,
|
||||
U128, U13, U14, U15, U16, U17, U18, U19, U2, U20, U21, U22, U23, U24, U25, U26, U27, U28, U29,
|
||||
U3, U30, U31, U32, U33, U34, U35, U36, U37, U38, U39, U4, U40, U41, U42, U43, U44, U45, U46,
|
||||
U47, U48, U49, U5, U50, U51, U52, U53, U54, U55, U56, U57, U58, U59, U6, U60, U61, U62, U63,
|
||||
U64, U65, U66, U67, U68, U69, U7, U70, U71, U72, U73, U74, U75, U76, U77, U78, U79, U8, U80,
|
||||
U81, U82, U83, U84, U85, U86, U87, U88, U89, U9, U90, U91, U92, U93, U94, U95, U96, U97, U98,
|
||||
U99, Unsigned,
|
||||
};
|
652
src/lib.rs
652
src/lib.rs
|
@ -102,8 +102,10 @@ additional terms or conditions.
|
|||
extern crate typenum;
|
||||
|
||||
mod display;
|
||||
pub mod frac;
|
||||
mod helper;
|
||||
|
||||
use frac::Unsigned;
|
||||
use helper::FixedHelper;
|
||||
use std::cmp::Ordering;
|
||||
use std::f32;
|
||||
|
@ -116,7 +118,6 @@ use std::ops::{
|
|||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
};
|
||||
use typenum::Unsigned;
|
||||
|
||||
macro_rules! if_signed {
|
||||
(Signed => $($rem:tt)+) => {
|
||||
|
@ -328,6 +329,13 @@ 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)* } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! to_f {
|
||||
($method:ident -> $f:ident($u:ident), $exp_bits:expr, $prec:expr) => {
|
||||
doc_comment! {
|
||||
|
@ -400,7 +408,7 @@ macro_rules! to_f {
|
|||
}
|
||||
|
||||
macro_rules! fixed {
|
||||
($description:expr, $Fixed:ident($Inner:ty), $Signedness:tt) => {
|
||||
($description:expr, $Fixed:ident($Inner:ty, $bits_count:expr), $Signedness:tt) => {
|
||||
doc_comment! {
|
||||
concat!(
|
||||
$description,
|
||||
|
@ -414,16 +422,12 @@ macro_rules! fixed {
|
|||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"extern crate fixed;\n",
|
||||
"extern crate typenum;\n",
|
||||
"use fixed::frac::U3;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"fn main() {\n",
|
||||
" use typenum::U3;\n",
|
||||
"let eleven = ", stringify!($Fixed), "::<U3>::from_bits(11 << 3);\n",
|
||||
" let five_five = eleven >> 1u32;\n",
|
||||
"let five_half = eleven >> 1u32;\n",
|
||||
"assert_eq!(eleven.to_string(), \"11.0\");\n",
|
||||
" assert_eq!(five_five.to_string(), \"5.5\");\n",
|
||||
"}\n",
|
||||
"assert_eq!(five_half.to_string(), \"5.5\");\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"[`Unsigned`]: https://docs.rs/typenum/^1.3/typenum/marker_traits/trait.Unsigned.html\n",
|
||||
|
@ -499,6 +503,394 @@ macro_rules! fixed {
|
|||
Frac::to_u32()
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Creates a fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"that has a bitwise representation identical to the\n",
|
||||
"`", stringify!($Inner), "` value."
|
||||
),
|
||||
#[inline]
|
||||
pub fn from_bits(v: $Inner) -> $Fixed<Frac> {
|
||||
let bits = <$Fixed<Frac> as FixedHelper<Frac>>::bits();
|
||||
assert!(Frac::to_u32() <= bits, "`Frac` too large");
|
||||
$Fixed((v, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Creates an integer of type `", stringify!($Inner), "`\n",
|
||||
"that has a bitwise representation identical to the\n",
|
||||
"`", stringify!($Fixed), "` value."
|
||||
),
|
||||
#[inline]
|
||||
pub fn to_bits(self) -> $Inner {
|
||||
(self.0).0
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Creates a fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"that has the same value as an integer of type\n",
|
||||
"`", stringify!($Inner), "` if it fits.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let fix_one = Fix::from_bits(1 << 4);\n",
|
||||
"assert_eq!(Fix::from_int(1), Some(fix_one));\n",
|
||||
"let too_large = 1 << (", stringify!($bits_count), " - 2);\n",
|
||||
"assert_eq!(Fix::from_int(too_large), None);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn from_int(v: $Inner) -> Option<$Fixed<Frac>> {
|
||||
let frac_bits = <$Fixed<Frac>>::frac_bits();
|
||||
let bits = v.checked_shl(frac_bits).unwrap_or(0);
|
||||
let all_frac_check;
|
||||
if_signed! { $Signedness => all_frac_check = bits >> (frac_bits - 1); }
|
||||
if_unsigned! { $Signedness => all_frac_check = 0; }
|
||||
|
||||
let check = bits.checked_shr(frac_bits).unwrap_or(all_frac_check);
|
||||
if check == v {
|
||||
Some($Fixed::from_bits(bits))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` truncating the fractional bits.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int(), 2);\n",
|
||||
"let neg_two_half = -two_half;\n",
|
||||
"assert_eq!(neg_two_half.to_int(), -2);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` truncating the fractional bits.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int(), 2);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn to_int(self) -> $Inner {
|
||||
let floor = self.to_int_floor();
|
||||
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 => {
|
||||
floor
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards +∞.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_ceil(), 3);\n",
|
||||
"let neg_two_half = -two_half;\n",
|
||||
"assert_eq!(neg_two_half.to_int_ceil(), -2);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards +∞.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_ceil(), 3);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn to_int_ceil(self) -> $Inner {
|
||||
let floor = self.to_int_floor();
|
||||
let no_frac = self.frac().to_bits() == 0;
|
||||
if no_frac {
|
||||
floor
|
||||
} else {
|
||||
floor + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards −∞.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_floor(), 2);\n",
|
||||
"let neg_two_half = -two_half;\n",
|
||||
"assert_eq!(neg_two_half.to_int_floor(), -3);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards −∞.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_floor(), 2);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
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 }
|
||||
} else {
|
||||
bits >> Self::frac_bits()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards the nearest.\n",
|
||||
"Ties are rounded away from zero.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_round(), 3);\n",
|
||||
"let neg_two_half = -two_half;\n",
|
||||
"assert_eq!(neg_two_half.to_int_round(), -3);\n",
|
||||
"let one_quarter = two_half / 2;\n",
|
||||
"assert_eq!(one_quarter.to_int_round(), 1);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Converts the fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"to an integer of type\n",
|
||||
"`", stringify!($Inner), "` rounding towards −∞.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"let two_half = Fix::from_int(5).unwrap() / 2;\n",
|
||||
"assert_eq!(two_half.to_int_round(), 3);\n",
|
||||
"let one_quarter = two_half / 2;\n",
|
||||
"assert_eq!(one_quarter.to_int_round(), 1);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn to_int_round(self) -> $Inner {
|
||||
let frac_bits = <$Fixed<Frac>>::frac_bits();
|
||||
let floor = self.to_int_floor();
|
||||
if frac_bits == 0 {
|
||||
return floor;
|
||||
}
|
||||
let half_bit = 1 << (frac_bits - 1);
|
||||
if_signed! { $Signedness => {
|
||||
if self.to_bits() >= 0 {
|
||||
if (self.to_bits() & half_bit) != 0 {
|
||||
floor + 1
|
||||
} else {
|
||||
floor
|
||||
}
|
||||
} else {
|
||||
let neg = self.to_bits().wrapping_neg();
|
||||
if (neg & half_bit) != 0 {
|
||||
floor
|
||||
} else {
|
||||
floor + 1
|
||||
}
|
||||
}
|
||||
} }
|
||||
if_unsigned! { $Signedness => {
|
||||
if (self.to_bits() & half_bit) != 0 {
|
||||
floor + 1
|
||||
} else {
|
||||
floor
|
||||
}
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Returns the integer part.\n",
|
||||
"\n",
|
||||
"Note that since the numbers are stored in two’s\n",
|
||||
"complement, negative numbers with non-zero fractional\n",
|
||||
"parts will be rounded towards −∞, except in the case\n",
|
||||
"where there are no integer bits, that is `",
|
||||
stringify!($Fixed), "<U", stringify!($bits_count), ">`,\n",
|
||||
"where the return value is always zero.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"// 0010.0000\n",
|
||||
"let two = Fix::from_int(2).unwrap();\n",
|
||||
"// 0010.0100\n",
|
||||
"let two_and_quarter = two + two / 8;\n",
|
||||
"assert_eq!(two_and_quarter.int(), two);\n",
|
||||
"// 1101.0000\n",
|
||||
"let neg_three = Fix::from_int(-3).unwrap();\n",
|
||||
"// 1101.1100\n",
|
||||
"let neg_two_and_quarter = -two_and_quarter;\n",
|
||||
"assert_eq!(neg_two_and_quarter.int(), neg_three);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Returns the integer part.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"// 0010.0000\n",
|
||||
"let two = Fix::from_int(2).unwrap();\n",
|
||||
"// 0010.0100\n",
|
||||
"let two_and_quarter = two + two / 8;\n",
|
||||
"assert_eq!(two_and_quarter.int(), two);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn int(self) -> $Fixed<Frac> {
|
||||
let frac_bits = <$Fixed<Frac>>::frac_bits();
|
||||
let mask = <$Inner>::checked_shl(!0, frac_bits).unwrap_or(0);
|
||||
$Fixed::from_bits(self.to_bits() & mask)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment_signed_unsigned! {
|
||||
$Signedness,
|
||||
concat!(
|
||||
"Returns the fractional part.\n",
|
||||
"\n",
|
||||
"Note that since the numbers are stored in two’s\n",
|
||||
"complement, the returned fraction will be non-negative\n",
|
||||
"for negative numbers, except in the case where\n",
|
||||
"there are no integer bits, that is `",
|
||||
stringify!($Fixed), "<U", stringify!($bits_count), ">`,\n",
|
||||
"where the return value is always equal to `self`.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"// 0000.0100\n",
|
||||
"let quarter = Fix::from_int(1).unwrap() / 4;\n",
|
||||
"// 0010.0100\n",
|
||||
"let two_and_quarter = quarter * 9;\n",
|
||||
"assert_eq!(two_and_quarter.frac(), quarter);\n",
|
||||
"// 0000.1100\n",
|
||||
"let three_quarters = quarter * 3;\n",
|
||||
"// 1101.1100\n",
|
||||
"let neg_two_and_quarter = -two_and_quarter;\n",
|
||||
"assert_eq!(neg_two_and_quarter.frac(), three_quarters);\n",
|
||||
"```\n"
|
||||
),
|
||||
concat!(
|
||||
"Returns the fractional part.\n",
|
||||
"\n",
|
||||
"# Examples\n",
|
||||
"\n",
|
||||
"```rust\n",
|
||||
"use fixed::frac;\n",
|
||||
"use fixed::", stringify!($Fixed), ";\n",
|
||||
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||
"// 0000.0100\n",
|
||||
"let quarter = Fix::from_int(1).unwrap() / 4;\n",
|
||||
"// 0010.0100\n",
|
||||
"let two_and_quarter = quarter * 9;\n",
|
||||
"assert_eq!(two_and_quarter.frac(), quarter);\n",
|
||||
"```\n"
|
||||
),
|
||||
#[inline]
|
||||
pub fn frac(self) -> $Fixed<Frac> {
|
||||
let frac_bits = <$Fixed<Frac>>::frac_bits();
|
||||
let inv_mask = <$Inner>::checked_shl(!0, frac_bits).unwrap_or(0);
|
||||
$Fixed::from_bits(self.to_bits() & !inv_mask)
|
||||
}
|
||||
}
|
||||
|
||||
to_f! { to_f32 -> f32(u32), 8, 24 }
|
||||
to_f! { to_f64 -> f64(u64), 11, 53 }
|
||||
|
||||
pass_method! {
|
||||
"Returns the number of ones in the binary representation.",
|
||||
$Fixed($Inner) => fn count_ones(self) -> u32
|
||||
|
@ -843,35 +1235,6 @@ macro_rules! fixed {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Creates a fixed-point number of type `", stringify!($Fixed), "`\n",
|
||||
"that has a bitwise representation identical to the\n",
|
||||
"`", stringify!($Inner), "` value."
|
||||
),
|
||||
#[inline]
|
||||
pub fn from_bits(v: $Inner) -> $Fixed<Frac> {
|
||||
let bits = <$Fixed<Frac> as FixedHelper<Frac>>::bits();
|
||||
assert!(Frac::to_u32() <= bits, "`Frac` too large");
|
||||
$Fixed((v, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Creates an integer of type `", stringify!($Inner), "`\n",
|
||||
"that has a bitwise representation identical to the\n",
|
||||
"`", stringify!($Fixed), "` value."
|
||||
),
|
||||
#[inline]
|
||||
pub fn to_bits(self) -> $Inner {
|
||||
(self.0).0
|
||||
}
|
||||
}
|
||||
|
||||
to_f! { to_f32 -> f32(u32), 8, 24 }
|
||||
to_f! { to_f64 -> f64(u64), 11, 53 }
|
||||
}
|
||||
|
||||
if_signed! {
|
||||
|
@ -1148,16 +1511,16 @@ macro_rules! fixed {
|
|||
};
|
||||
}
|
||||
|
||||
fixed! { "An eight-bit fixed-point unsigned integer", FixedU8(u8), Unsigned }
|
||||
fixed! { "A 16-bit fixed-point unsigned integer", FixedU16(u16), Unsigned }
|
||||
fixed! { "A 32-bit fixed-point unsigned integer", FixedU32(u32), Unsigned }
|
||||
fixed! { "A 64-bit fixed-point unsigned integer", FixedU64(u64), Unsigned }
|
||||
fixed! { "A 128-bit fixed-point unsigned integer", FixedU128(u128), Unsigned }
|
||||
fixed! { "An eight-bit fixed-point signed integer", FixedI8(i8), Signed }
|
||||
fixed! { "A 16-bit fixed-point signed integer", FixedI16(i16), Signed }
|
||||
fixed! { "A 32-bit fixed-point signed integer", FixedI32(i32), Signed }
|
||||
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64), Signed }
|
||||
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128), Signed }
|
||||
fixed! { "An eight-bit fixed-point unsigned integer", FixedU8(u8, 8), Unsigned }
|
||||
fixed! { "A 16-bit fixed-point unsigned integer", FixedU16(u16, 16), Unsigned }
|
||||
fixed! { "A 32-bit fixed-point unsigned integer", FixedU32(u32, 32), Unsigned }
|
||||
fixed! { "A 64-bit fixed-point unsigned integer", FixedU64(u64, 64), Unsigned }
|
||||
fixed! { "A 128-bit fixed-point unsigned integer", FixedU128(u128, 128), Unsigned }
|
||||
fixed! { "An eight-bit fixed-point signed integer", FixedI8(i8, 8), Signed }
|
||||
fixed! { "A 16-bit fixed-point signed integer", FixedI16(i16, 16), Signed }
|
||||
fixed! { "A 32-bit fixed-point signed integer", FixedI32(i32, 32), Signed }
|
||||
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64, 64), Signed }
|
||||
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128, 128), Signed }
|
||||
|
||||
trait MulDivDir: Sized {
|
||||
fn mul_dir(self, rhs: Self, frac_bits: u32) -> (Self, Ordering);
|
||||
|
@ -1396,7 +1759,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fixed_u16() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 12;
|
||||
let b = 4;
|
||||
|
@ -1416,7 +1779,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fixed_i16() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 12;
|
||||
let b = 4;
|
||||
|
@ -1440,7 +1803,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fixed_u128() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 0x0003456789abcdef_0123456789abcdef_u128;
|
||||
let b = 5;
|
||||
|
@ -1458,7 +1821,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fixed_i128() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 0x0003456789abcdef_0123456789abcdef_i128;
|
||||
let b = 5;
|
||||
|
@ -1479,7 +1842,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn to_f32() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
for u in 0x00..=0xff {
|
||||
let fu = FixedU8::<Frac>::from_bits(u);
|
||||
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||
|
@ -1525,7 +1888,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn to_f64() {
|
||||
use typenum::U7 as Frac;
|
||||
use frac::U7 as Frac;
|
||||
for u in 0x00..=0xff {
|
||||
let fu = FixedU8::<Frac>::from_bits(u);
|
||||
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||
|
@ -1568,4 +1931,185 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rounding() {
|
||||
use typenum::{U16, U32};
|
||||
|
||||
type I0F32 = FixedI32<U32>;
|
||||
|
||||
// -0.5
|
||||
let f = I0F32::from_bits(-1 << 31);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 0);
|
||||
assert_eq!(f.to_int_floor(), -1);
|
||||
assert_eq!(f.to_int_round(), -1);
|
||||
|
||||
// -0.5 + δ
|
||||
let f = I0F32::from_bits((-1 << 31) + 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 0);
|
||||
assert_eq!(f.to_int_floor(), -1);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
// 0.5 - δ
|
||||
let f = I0F32::from_bits((1 << 30) - 1 + (1 << 30));
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
type U0F32 = FixedU32<U32>;
|
||||
|
||||
// 0.5 - δ
|
||||
let f = U0F32::from_bits((1 << 31) - 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
// 0.5
|
||||
let f = U0F32::from_bits(1 << 31);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
// 0.5 + δ
|
||||
let f = U0F32::from_bits((1 << 31) + 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
type I16F16 = FixedI32<U16>;
|
||||
|
||||
// -3.5 - δ
|
||||
let f = I16F16::from_bits(((-7) << 15) - 1);
|
||||
assert_eq!(f.to_int(), -3);
|
||||
assert_eq!(f.to_int_ceil(), -3);
|
||||
assert_eq!(f.to_int_floor(), -4);
|
||||
assert_eq!(f.to_int_round(), -4);
|
||||
|
||||
// -3.5
|
||||
let f = I16F16::from_bits((-7) << 15);
|
||||
assert_eq!(f.to_int(), -3);
|
||||
assert_eq!(f.to_int_ceil(), -3);
|
||||
assert_eq!(f.to_int_floor(), -4);
|
||||
assert_eq!(f.to_int_round(), -4);
|
||||
|
||||
// -3.5 + δ
|
||||
let f = I16F16::from_bits(((-7) << 15) + 1);
|
||||
assert_eq!(f.to_int(), -3);
|
||||
assert_eq!(f.to_int_ceil(), -3);
|
||||
assert_eq!(f.to_int_floor(), -4);
|
||||
assert_eq!(f.to_int_round(), -3);
|
||||
|
||||
// -0.5 - δ
|
||||
let f = I16F16::from_bits(((-1) << 15) - 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 0);
|
||||
assert_eq!(f.to_int_floor(), -1);
|
||||
assert_eq!(f.to_int_round(), -1);
|
||||
|
||||
// -0.5
|
||||
let f = I16F16::from_bits((-1) << 15);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 0);
|
||||
assert_eq!(f.to_int_floor(), -1);
|
||||
assert_eq!(f.to_int_round(), -1);
|
||||
|
||||
// -0.5 + δ
|
||||
let f = I16F16::from_bits(((-1) << 15) + 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 0);
|
||||
assert_eq!(f.to_int_floor(), -1);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
// 0.5 - δ
|
||||
let f = I16F16::from_bits((1 << 15) - 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
// 0.5
|
||||
let f = I16F16::from_bits(1 << 15);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
// 0.5 + δ
|
||||
let f = I16F16::from_bits((1 << 15) + 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
// 3.5 - δ
|
||||
let f = I16F16::from_bits((7 << 15) - 1);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 3);
|
||||
|
||||
// 3.5
|
||||
let f = I16F16::from_bits(7 << 15);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 4);
|
||||
|
||||
// 3.5 + δ
|
||||
let f = I16F16::from_bits((7 << 15) + 1);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 4);
|
||||
|
||||
type U16F16 = FixedU32<U16>;
|
||||
|
||||
// 0.5 - δ
|
||||
let f = U16F16::from_bits((1 << 15) - 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 0);
|
||||
|
||||
// 0.5
|
||||
let f = U16F16::from_bits(1 << 15);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
// 0.5 + δ
|
||||
let f = U16F16::from_bits((1 << 15) + 1);
|
||||
assert_eq!(f.to_int(), 0);
|
||||
assert_eq!(f.to_int_ceil(), 1);
|
||||
assert_eq!(f.to_int_floor(), 0);
|
||||
assert_eq!(f.to_int_round(), 1);
|
||||
|
||||
// 3.5 - δ
|
||||
let f = U16F16::from_bits((7 << 15) - 1);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 3);
|
||||
|
||||
// 3.5
|
||||
let f = U16F16::from_bits(7 << 15);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 4);
|
||||
|
||||
// 3.5 + δ
|
||||
let f = U16F16::from_bits((7 << 15) + 1);
|
||||
assert_eq!(f.to_int(), 3);
|
||||
assert_eq!(f.to_int_ceil(), 4);
|
||||
assert_eq!(f.to_int_floor(), 3);
|
||||
assert_eq!(f.to_int_round(), 4);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue