add f16 feature
This commit is contained in:
parent
f7b4242102
commit
932caf3f92
10
Cargo.toml
10
Cargo.toml
|
@ -17,5 +17,15 @@ keywords = ["mathematics", "numerics"]
|
||||||
categories = ["algorithms", "data-structures", "no-std", "science"]
|
categories = ["algorithms", "data-structures", "no-std", "science"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
f16 = ["half"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.8"
|
typenum = "1.8"
|
||||||
|
|
||||||
|
[dependencies.half]
|
||||||
|
version = "1"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["f16"]
|
||||||
|
|
26
README.md
26
README.md
|
@ -35,6 +35,14 @@ fixed-point numbers.
|
||||||
|
|
||||||
## What’s new
|
## What’s new
|
||||||
|
|
||||||
|
### Version 0.1.3 news (unreleased)
|
||||||
|
|
||||||
|
* The `f16` feature was added with its methods [`from_f16`] and
|
||||||
|
[`to_f16`].
|
||||||
|
|
||||||
|
[`from_f16`]: https://docs.rs/fixed/0.1.3/fixed/struct.FixedI32.html#method.from_f16
|
||||||
|
[`to_f16`]: https://docs.rs/fixed/0.1.3/fixed/struct.FixedI32.html#method.to_f16
|
||||||
|
|
||||||
### Version 0.1.2 news (2018-08-15)
|
### Version 0.1.2 news (2018-08-15)
|
||||||
|
|
||||||
* The crate can now be used without the standard library `std`.
|
* The crate can now be used without the standard library `std`.
|
||||||
|
@ -108,6 +116,22 @@ extern crate fixed;
|
||||||
|
|
||||||
The *fixed* crate requires rustc version 1.28.0 or later.
|
The *fixed* crate requires rustc version 1.28.0 or later.
|
||||||
|
|
||||||
|
## Optional features
|
||||||
|
|
||||||
|
The *fixed* crate has one optional feature:
|
||||||
|
|
||||||
|
1. `f16`, disabled by default. This provides conversion to/from
|
||||||
|
[`f16`]. This features requires the [*half* crate].
|
||||||
|
|
||||||
|
To enable the feature, you can add the dependency like this to
|
||||||
|
[*Cargo.toml*]:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies.fixed]
|
||||||
|
version = "0.1.2"
|
||||||
|
features = ["f16"]
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This crate is free software: you can redistribute it and/or modify it
|
This crate is free software: you can redistribute it and/or modify it
|
||||||
|
@ -127,6 +151,7 @@ additional terms or conditions.
|
||||||
|
|
||||||
[*Cargo.toml*]: https://doc.rust-lang.org/cargo/guide/dependencies.html
|
[*Cargo.toml*]: https://doc.rust-lang.org/cargo/guide/dependencies.html
|
||||||
[*fixed* crate]: https://crates.io/crates/fixed
|
[*fixed* crate]: https://crates.io/crates/fixed
|
||||||
|
[*half* crate]: https://crates.io/crates/half
|
||||||
[*typenum* crate]: https://crates.io/crates/typenum
|
[*typenum* crate]: https://crates.io/crates/typenum
|
||||||
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
|
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
|
||||||
[LICENSE-MIT]: https://opensource.org/licenses/MIT
|
[LICENSE-MIT]: https://opensource.org/licenses/MIT
|
||||||
|
@ -140,5 +165,6 @@ additional terms or conditions.
|
||||||
[`FixedU32`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU32.html
|
[`FixedU32`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU32.html
|
||||||
[`FixedU64`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU64.html
|
[`FixedU64`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU64.html
|
||||||
[`FixedU8`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU8.html
|
[`FixedU8`]: https://docs.rs/fixed/0.1.2/fixed/struct.FixedU8.html
|
||||||
|
[`f16`]: https://docs.rs/half/^1/half/struct.f16.html
|
||||||
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
||||||
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
||||||
|
|
|
@ -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.1.3 news (unreleased)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
* The `f16` feature was added with its methods `from_f16` and
|
||||||
|
`to_f16`.
|
||||||
|
|
||||||
Version 0.1.2 (2018-08-15)
|
Version 0.1.2 (2018-08-15)
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|
61
src/float.rs
61
src/float.rs
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use frac::{IsLessOrEqual, True, Unsigned, U16, U32, U8};
|
use frac::{IsLessOrEqual, True, Unsigned, U16, U32, U8};
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
use half::f16;
|
||||||
use helper::FloatHelper;
|
use helper::FloatHelper;
|
||||||
use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8};
|
use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8};
|
||||||
|
|
||||||
|
@ -149,8 +151,12 @@ macro_rules! to_float {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait FloatConv: Sized {
|
pub(crate) trait FloatConv: Sized {
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
fn from_f16(val: f16, frac_bits: u32) -> Option<(Self, bool)>;
|
||||||
fn from_f32(val: f32, frac_bits: u32) -> Option<(Self, bool)>;
|
fn from_f32(val: f32, frac_bits: u32) -> Option<(Self, bool)>;
|
||||||
fn from_f64(val: f64, frac_bits: u32) -> Option<(Self, bool)>;
|
fn from_f64(val: f64, frac_bits: u32) -> Option<(Self, bool)>;
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
fn to_f16(self, neg: bool, frac_bits: u32) -> f16;
|
||||||
fn to_f32(self, neg: bool, frac_bits: u32) -> f32;
|
fn to_f32(self, neg: bool, frac_bits: u32) -> f32;
|
||||||
fn to_f64(self, neg: bool, frac_bits: u32) -> f64;
|
fn to_f64(self, neg: bool, frac_bits: u32) -> f64;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +164,12 @@ pub(crate) trait FloatConv: Sized {
|
||||||
macro_rules! float_conv {
|
macro_rules! float_conv {
|
||||||
($($Uns:ty)*) => { $(
|
($($Uns:ty)*) => { $(
|
||||||
impl FloatConv for $Uns {
|
impl FloatConv for $Uns {
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
from_float! { fn from_f16(f16) -> $Uns }
|
||||||
from_float! { fn from_f32(f32) -> $Uns }
|
from_float! { fn from_f32(f32) -> $Uns }
|
||||||
from_float! { fn from_f64(f64) -> $Uns }
|
from_float! { fn from_f64(f64) -> $Uns }
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
to_float! { fn to_f16($Uns) -> f16 }
|
||||||
to_float! { fn to_f32($Uns) -> f32 }
|
to_float! { fn to_f32($Uns) -> f32 }
|
||||||
to_float! { fn to_f64($Uns) -> f64 }
|
to_float! { fn to_f64($Uns) -> f64 }
|
||||||
}
|
}
|
||||||
|
@ -181,6 +191,10 @@ macro_rules! lossless_from_fixed {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
lossless_from_fixed! { FixedI8(U8)::to_f16 -> f16 }
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
lossless_from_fixed! { FixedU8(U8)::to_f16 -> f16 }
|
||||||
lossless_from_fixed! { FixedI8(U8)::to_f32 -> f32 }
|
lossless_from_fixed! { FixedI8(U8)::to_f32 -> f32 }
|
||||||
lossless_from_fixed! { FixedI16(U16)::to_f32 -> f32 }
|
lossless_from_fixed! { FixedI16(U16)::to_f32 -> f32 }
|
||||||
lossless_from_fixed! { FixedU8(U8)::to_f32 -> f32 }
|
lossless_from_fixed! { FixedU8(U8)::to_f32 -> f32 }
|
||||||
|
@ -278,6 +292,53 @@ mod tests {
|
||||||
assert!(Fix::from_f32(511.0 / 32.0).is_none());
|
assert!(Fix::from_f32(511.0 / 32.0).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
#[test]
|
||||||
|
fn to_f16() {
|
||||||
|
use half::f16;
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::<frac::U7>::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f16(), f16::from_f32(u as f32 / 128.0));
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::<frac::U7>::from_bits(i);
|
||||||
|
assert_eq!(fi.to_f16(), f16::from_f32(i as f32 / 128.0));
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u32,
|
||||||
|
0x0000_0100,
|
||||||
|
0x7fff_ff00,
|
||||||
|
0x8000_0000,
|
||||||
|
0x8100_0000,
|
||||||
|
0xffff_fe00,
|
||||||
|
0xffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u as u32;
|
||||||
|
let fuu = FixedU32::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f16(), f16::from_f32(uu as f32 / 128.0));
|
||||||
|
let ii = uu as i32;
|
||||||
|
let fii = FixedI32::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f16(), f16::from_f32(ii as f32 / 128.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u128,
|
||||||
|
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u as u128;
|
||||||
|
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f16(), f16::from_f64(uu as f64 / 128.0));
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f16(), f16::from_f64(ii as f64 / 128.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_f32() {
|
fn to_f32() {
|
||||||
for u in 0x00..=0xff {
|
for u in 0x00..=0xff {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
|
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
use half::f16;
|
||||||
use {
|
use {
|
||||||
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
||||||
FixedU8,
|
FixedU8,
|
||||||
|
@ -35,7 +37,7 @@ pub(crate) trait FloatHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! float_helper {
|
macro_rules! float_helper {
|
||||||
($Float:ident($Bits:ty, $prec:expr)) => {
|
($Float:ident($Bits:ty, $prec:expr, $to_bits:ident)) => {
|
||||||
impl FloatHelper for $Float {
|
impl FloatHelper for $Float {
|
||||||
type Bits = $Bits;
|
type Bits = $Bits;
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ macro_rules! float_helper {
|
||||||
let mant_mask = !(!0 << ($prec - 1));
|
let mant_mask = !(!0 << ($prec - 1));
|
||||||
let exp_mask = !(neg_mask | mant_mask);
|
let exp_mask = !(neg_mask | mant_mask);
|
||||||
|
|
||||||
let bits = self.to_bits();
|
let bits = self.$to_bits();
|
||||||
let neg = bits & neg_mask != 0;
|
let neg = bits & neg_mask != 0;
|
||||||
let biased_exp = (bits & exp_mask) >> ($prec - 1);
|
let biased_exp = (bits & exp_mask) >> ($prec - 1);
|
||||||
let exp = (biased_exp as i32) - <$Float as FloatHelper>::exp_bias();
|
let exp = (biased_exp as i32) - <$Float as FloatHelper>::exp_bias();
|
||||||
|
@ -110,8 +112,10 @@ macro_rules! float_helper {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
float_helper! { f32(u32, 24) }
|
#[cfg(feature = "f16")]
|
||||||
float_helper! { f64(u64, 53) }
|
float_helper! { f16(u16, 11, as_bits) }
|
||||||
|
float_helper! { f32(u32, 24, to_bits) }
|
||||||
|
float_helper! { f64(u64, 53, to_bits) }
|
||||||
|
|
||||||
pub(crate) trait FixedHelper<Frac>: Sized
|
pub(crate) trait FixedHelper<Frac>: Sized
|
||||||
where
|
where
|
||||||
|
|
223
src/lib.rs
223
src/lib.rs
|
@ -77,6 +77,22 @@ extern crate fixed;
|
||||||
|
|
||||||
The *fixed* crate requires rustc version 1.28.0 or later.
|
The *fixed* crate requires rustc version 1.28.0 or later.
|
||||||
|
|
||||||
|
## Optional features
|
||||||
|
|
||||||
|
The *fixed* crate has one optional feature:
|
||||||
|
|
||||||
|
1. `f16`, disabled by default. This provides conversion to/from
|
||||||
|
[`f16`]. This features requires the [*half* crate].
|
||||||
|
|
||||||
|
To enable the feature, you can add the dependency like this to
|
||||||
|
[*Cargo.toml*]:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies.fixed]
|
||||||
|
version = "0.1.2"
|
||||||
|
features = ["f16"]
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This crate is free software: you can redistribute it and/or modify it
|
This crate is free software: you can redistribute it and/or modify it
|
||||||
|
@ -96,6 +112,7 @@ additional terms or conditions.
|
||||||
|
|
||||||
[*Cargo.toml*]: https://doc.rust-lang.org/cargo/guide/dependencies.html
|
[*Cargo.toml*]: https://doc.rust-lang.org/cargo/guide/dependencies.html
|
||||||
[*fixed* crate]: https://crates.io/crates/fixed
|
[*fixed* crate]: https://crates.io/crates/fixed
|
||||||
|
[*half* crate]: https://crates.io/crates/half
|
||||||
[*typenum* crate]: https://crates.io/crates/typenum
|
[*typenum* crate]: https://crates.io/crates/typenum
|
||||||
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
|
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
|
||||||
[LICENSE-MIT]: https://opensource.org/licenses/MIT
|
[LICENSE-MIT]: https://opensource.org/licenses/MIT
|
||||||
|
@ -109,6 +126,7 @@ additional terms or conditions.
|
||||||
[`FixedU32`]: struct.FixedU32.html
|
[`FixedU32`]: struct.FixedU32.html
|
||||||
[`FixedU64`]: struct.FixedU64.html
|
[`FixedU64`]: struct.FixedU64.html
|
||||||
[`FixedU8`]: struct.FixedU8.html
|
[`FixedU8`]: struct.FixedU8.html
|
||||||
|
[`f16`]: https://docs.rs/half/^1/half/struct.f16.html
|
||||||
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
||||||
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
||||||
*/
|
*/
|
||||||
|
@ -118,6 +136,8 @@ additional terms or conditions.
|
||||||
#![doc(test(attr(deny(warnings))))]
|
#![doc(test(attr(deny(warnings))))]
|
||||||
#![cfg_attr(nightly_repr_transparent, feature(repr_transparent))]
|
#![cfg_attr(nightly_repr_transparent, feature(repr_transparent))]
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
extern crate half;
|
||||||
extern crate typenum;
|
extern crate typenum;
|
||||||
|
|
||||||
macro_rules! if_signed {
|
macro_rules! if_signed {
|
||||||
|
@ -144,12 +164,12 @@ mod helper;
|
||||||
|
|
||||||
use arith::MulDivDir;
|
use arith::MulDivDir;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::f32;
|
|
||||||
use core::f64;
|
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use float::FloatConv;
|
use float::FloatConv;
|
||||||
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
|
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
use half::f16;
|
||||||
use helper::FixedHelper;
|
use helper::FixedHelper;
|
||||||
|
|
||||||
macro_rules! pass_method {
|
macro_rules! pass_method {
|
||||||
|
@ -208,13 +228,13 @@ macro_rules! doc_comment_signed_unsigned {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! from_float {
|
macro_rules! from_float {
|
||||||
($Signedness:tt, fn $method:ident($Float:ident) -> $Fixed:ident < $Frac:ident >) => {
|
($Signedness:tt,fn $method:ident($Float:ident) -> $Fixed:ident < $Frac:ident >) => {
|
||||||
doc_comment_signed_unsigned! {
|
doc_comment_signed_unsigned! {
|
||||||
$Signedness,
|
$Signedness,
|
||||||
concat!(
|
concat!(
|
||||||
"Creates a fixed-point number from `", stringify!($Float), "`.\n",
|
"Creates a fixed-point number from `", stringify!($Float), "`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This method rounds to the nearest, with ties rounding to even.",
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Examples\n",
|
"# Examples\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -242,7 +262,7 @@ macro_rules! from_float {
|
||||||
concat!(
|
concat!(
|
||||||
"Creates a fixed-point number from `", stringify!($Float), "`.\n",
|
"Creates a fixed-point number from `", stringify!($Float), "`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This method rounds to the nearest, with ties rounding to even.",
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Examples\n",
|
"# Examples\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -299,13 +319,13 @@ macro_rules! from_float {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! to_float {
|
macro_rules! to_float {
|
||||||
($Signedness:tt, fn $method:ident($Fixed:ident < $Frac:ident >) -> $Float:ident) => {
|
($Signedness:tt,fn $method:ident($Fixed:ident < $Frac:ident >) -> $Float:ident) => {
|
||||||
doc_comment_signed_unsigned! {
|
doc_comment_signed_unsigned! {
|
||||||
$Signedness,
|
$Signedness,
|
||||||
concat!(
|
concat!(
|
||||||
"Converts the fixed-point number to `", stringify!($Float), "`.\n",
|
"Converts the fixed-point number to `", stringify!($Float), "`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This method rounds to the nearest, with ties rounding to even.",
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Examples\n",
|
"# Examples\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -323,7 +343,7 @@ macro_rules! to_float {
|
||||||
concat!(
|
concat!(
|
||||||
"Converts the fixed-point number to `", stringify!($Float), "`.\n",
|
"Converts the fixed-point number to `", stringify!($Float), "`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This method rounds to the nearest, with ties rounding to even.",
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Examples\n",
|
"# Examples\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -354,8 +374,21 @@ macro_rules! to_float {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
macro_rules! string_up_to_16 {
|
||||||
|
(U8, $s:expr) => {
|
||||||
|
$s
|
||||||
|
};
|
||||||
|
(U16, $s:expr) => {
|
||||||
|
$s
|
||||||
|
};
|
||||||
|
($other:tt, $s:expr) => {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! fixed {
|
macro_rules! fixed {
|
||||||
($description:expr, $Fixed:ident($Inner:ty, $Len:ty, $bits_count:expr), $Signedness:tt) => {
|
($description:expr, $Fixed:ident($Inner:ty, $Len:tt, $bits_count:expr), $Signedness:tt) => {
|
||||||
doc_comment! {
|
doc_comment! {
|
||||||
concat!(
|
concat!(
|
||||||
$description,
|
$description,
|
||||||
|
@ -809,8 +842,180 @@ macro_rules! fixed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
doc_comment_signed_unsigned! {
|
||||||
|
$Signedness,
|
||||||
|
concat!(
|
||||||
|
"Creates a fixed-point number from `f16`.\n",
|
||||||
|
"\n",
|
||||||
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
|
"\n",
|
||||||
|
"This method is only available when the `f16` feature is enabled.\n",
|
||||||
|
"\n",
|
||||||
|
"# Examples\n",
|
||||||
|
"\n",
|
||||||
|
"```rust\n",
|
||||||
|
"extern crate fixed;\n",
|
||||||
|
"extern crate half;\n",
|
||||||
|
"use fixed::frac;\n",
|
||||||
|
"use fixed::", stringify!($Fixed), ";\n",
|
||||||
|
"use half::f16;\n",
|
||||||
|
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||||
|
"// 1.75 is 0001.1100, that is from_bits(28)\n",
|
||||||
|
"let val = f16::from_f32(1.75);\n",
|
||||||
|
"let neg_val = f16::from_f32(-1.75);\n",
|
||||||
|
"assert_eq!(Fix::from_f16(val), Some(Fix::from_bits(28)));\n",
|
||||||
|
"assert_eq!(Fix::from_f16(neg_val), Some(Fix::from_bits(-28)));\n",
|
||||||
|
"// 1e-2 is too small for four fractional bits\n",
|
||||||
|
"let small = f16::from_f32(1e-2);\n",
|
||||||
|
"let neg_small = f16::from_f32(-1e-2);\n",
|
||||||
|
"assert_eq!(Fix::from_f16(small), Some(Fix::from_bits(0)));\n",
|
||||||
|
"assert_eq!(Fix::from_f16(neg_small), Some(Fix::from_bits(0)));\n",
|
||||||
|
string_up_to_16!(
|
||||||
|
$Len,
|
||||||
|
concat!(
|
||||||
|
"// 50000 is too large for ", stringify!($Fixed), "<frac::U4>\n",
|
||||||
|
"let large = f16::from_f32(50000.0);\n",
|
||||||
|
"let neg_large = f16::from_f32(-50000.0);\n",
|
||||||
|
"assert!(Fix::from_f16(large).is_none());\n",
|
||||||
|
"assert!(Fix::from_f16(neg_large).is_none());\n"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"```\n"
|
||||||
|
),
|
||||||
|
concat!(
|
||||||
|
"Creates a fixed-point number from `", stringify!($Float), "`.\n",
|
||||||
|
"\n",
|
||||||
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
|
"\n",
|
||||||
|
"This method is only available when the `f16` feature is enabled.\n",
|
||||||
|
"\n",
|
||||||
|
"# Examples\n",
|
||||||
|
"\n",
|
||||||
|
"```rust\n",
|
||||||
|
"extern crate fixed;\n",
|
||||||
|
"extern crate half;\n",
|
||||||
|
"use fixed::frac;\n",
|
||||||
|
"use fixed::", stringify!($Fixed), ";\n",
|
||||||
|
"use half::f16;\n",
|
||||||
|
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||||
|
"// 1.75 is 0001.1100, that is from_bits(28)\n",
|
||||||
|
"let val = f16::from_f32(1.75);\n",
|
||||||
|
"assert_eq!(Fix::from_f16(val), Some(Fix::from_bits(28)));\n",
|
||||||
|
"// 1e-2 is too small for four fractional bits\n",
|
||||||
|
"let small = f16::from_f32(1e-2);\n",
|
||||||
|
"assert_eq!(Fix::from_f16(small), Some(Fix::from_bits(0)));\n",
|
||||||
|
string_up_to_16!(
|
||||||
|
$Len,
|
||||||
|
concat!(
|
||||||
|
"// 50000 is too large for ", stringify!($Fixed), "<frac::U4>\n",
|
||||||
|
"let large = f16::from_f32(50000.0);\n",
|
||||||
|
"assert!(Fix::from_f16(large).is_none());\n",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"```\n"
|
||||||
|
),
|
||||||
|
#[inline]
|
||||||
|
pub fn from_f16(val: f16) -> Option<$Fixed<Frac>> {
|
||||||
|
let int_bits = Self::int_bits();
|
||||||
|
let frac_bits = Self::frac_bits();
|
||||||
|
|
||||||
|
let (int_frac, neg) = FloatConv::from_f16(val, frac_bits)?;
|
||||||
|
|
||||||
|
if <$Fixed<Frac> as FixedHelper<Frac>>::is_signed() {
|
||||||
|
// most significant bit (msb) can be one only for min value,
|
||||||
|
// that is for a negative value with only the msb true.
|
||||||
|
let msb = 1 << (int_bits + frac_bits - 1);
|
||||||
|
if int_frac & msb != 0 {
|
||||||
|
if !neg || (int_frac & !msb) != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if neg {
|
||||||
|
if int_frac != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some($Fixed::from_bits(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (int, frac) = if frac_bits == 0 {
|
||||||
|
(int_frac, 0)
|
||||||
|
} else if int_bits == 0 {
|
||||||
|
(0, int_frac)
|
||||||
|
} else {
|
||||||
|
((int_frac >> frac_bits), (int_frac << int_bits))
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(FixedHelper::from_parts(neg, int, frac))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
from_float! { $Signedness, fn from_f32(f32) -> $Fixed<Frac> }
|
from_float! { $Signedness, fn from_f32(f32) -> $Fixed<Frac> }
|
||||||
from_float! { $Signedness, fn from_f64(f64) -> $Fixed<Frac> }
|
from_float! { $Signedness, fn from_f64(f64) -> $Fixed<Frac> }
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
doc_comment_signed_unsigned! {
|
||||||
|
$Signedness,
|
||||||
|
concat!(
|
||||||
|
"Converts the fixed-point number to `f16`.\n",
|
||||||
|
"\n",
|
||||||
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
|
"\n",
|
||||||
|
"This method is only available when the `f16` feature is enabled.\n",
|
||||||
|
"\n",
|
||||||
|
"# Examples\n",
|
||||||
|
"\n",
|
||||||
|
"```rust\n",
|
||||||
|
"extern crate fixed;\n",
|
||||||
|
"extern crate half;\n",
|
||||||
|
"use fixed::frac;\n",
|
||||||
|
"use fixed::", stringify!($Fixed), ";\n",
|
||||||
|
"use half::f16;\n",
|
||||||
|
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||||
|
"// 1.75 is 0001.1100, that is from_bits(28)\n",
|
||||||
|
"let val = f16::from_f32(1.75);\n",
|
||||||
|
"let neg_val = f16::from_f32(-1.75);\n",
|
||||||
|
"assert_eq!(Fix::from_bits(28).to_f16(), val);\n",
|
||||||
|
"assert_eq!(Fix::from_bits(-28).to_f16(), neg_val);\n",
|
||||||
|
"```\n"
|
||||||
|
),
|
||||||
|
concat!(
|
||||||
|
"Converts the fixed-point number to `f16`.\n",
|
||||||
|
"\n",
|
||||||
|
"This method rounds to the nearest, with ties rounding to even.\n",
|
||||||
|
"\n",
|
||||||
|
"This method is only available when the `f16` feature is enabled.\n",
|
||||||
|
"\n",
|
||||||
|
"# Examples\n",
|
||||||
|
"\n",
|
||||||
|
"```rust\n",
|
||||||
|
"extern crate fixed;\n",
|
||||||
|
"extern crate half;\n",
|
||||||
|
"use fixed::frac;\n",
|
||||||
|
"use fixed::", stringify!($Fixed), ";\n",
|
||||||
|
"use half::f16;\n",
|
||||||
|
"type Fix = ", stringify!($Fixed), "<frac::U4>;\n",
|
||||||
|
"// 1.75 is 0001.1100, that is from_bits(28)\n",
|
||||||
|
"let val = f16::from_f32(1.75);\n",
|
||||||
|
"assert_eq!(Fix::from_bits(28).to_f16(), val);\n",
|
||||||
|
"```\n"
|
||||||
|
),
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f16(self) -> f16 {
|
||||||
|
let int_bits = Self::int_bits();
|
||||||
|
let frac_bits = Self::frac_bits();
|
||||||
|
let (neg, int, frac) = self.parts();
|
||||||
|
let int_frac = if frac_bits == 0 {
|
||||||
|
int
|
||||||
|
} else if int_bits == 0 {
|
||||||
|
frac
|
||||||
|
} else {
|
||||||
|
(int << frac_bits) | (frac >> int_bits)
|
||||||
|
};
|
||||||
|
FloatConv::to_f16(int_frac, neg, frac_bits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
to_float! { $Signedness, fn to_f32($Fixed<Frac>) -> f32 }
|
to_float! { $Signedness, fn to_f32($Fixed<Frac>) -> f32 }
|
||||||
to_float! { $Signedness, fn to_f64($Fixed<Frac>) -> f64 }
|
to_float! { $Signedness, fn to_f64($Fixed<Frac>) -> f64 }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue