implement to_f32 and to_f64
This commit is contained in:
parent
6553256f79
commit
3432356643
120
src/display.rs
120
src/display.rs
|
@ -2,14 +2,13 @@ use std::cmp::Ordering;
|
||||||
use std::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex};
|
use std::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use FixedNum;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
||||||
FixedU8,
|
FixedU8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const F: u32 = 7;
|
|
||||||
|
|
||||||
trait Radix2 {
|
trait Radix2 {
|
||||||
const BITS: u8;
|
const BITS: u8;
|
||||||
fn radix() -> u8;
|
fn radix() -> u8;
|
||||||
|
@ -46,123 +45,6 @@ radix2! { Oct(3, "0o"), 0..=7 => b'0' }
|
||||||
radix2! { LowHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'a' - 10 }
|
radix2! { LowHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'a' - 10 }
|
||||||
radix2! { UpHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'A' - 10 }
|
radix2! { UpHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'A' - 10 }
|
||||||
|
|
||||||
trait FixedNum: Copy {
|
|
||||||
type Part;
|
|
||||||
fn parts(self) -> (bool, Self::Part, Self::Part);
|
|
||||||
#[inline(always)]
|
|
||||||
fn int_bits() -> u32 {
|
|
||||||
mem::size_of::<Self::Part>() as u32 * 8 - F
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn frac_bits() -> u32 {
|
|
||||||
F
|
|
||||||
}
|
|
||||||
fn take_int_digit(int_part: &mut Self::Part, digit_bits: u32) -> u8;
|
|
||||||
fn take_frac_digit(frac_part: &mut Self::Part, digit_bits: u32) -> u8;
|
|
||||||
fn take_int_dec_digit(int_part: &mut Self::Part) -> u8;
|
|
||||||
fn take_frac_dec_digit(int_part: &mut Self::Part) -> u8;
|
|
||||||
fn part_is_zero(part: &Self::Part) -> bool;
|
|
||||||
fn part_cmp_half(part: &Self::Part) -> Ordering;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! fixed_num_common {
|
|
||||||
($Fixed:ident($Part:ty); $($rem:tt)+) => {
|
|
||||||
impl FixedNum for $Fixed {
|
|
||||||
type Part = $Part;
|
|
||||||
|
|
||||||
$($rem)+
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_int_digit(int_part: &mut $Part, digit_bits: u32) -> u8 {
|
|
||||||
let mask = (1 << digit_bits) - 1;
|
|
||||||
let ret = (*int_part & mask) as u8;
|
|
||||||
*int_part >>= digit_bits;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_frac_digit(frac_part: &mut $Part, digit_bits: u32) -> u8 {
|
|
||||||
let rem_bits = mem::size_of::<$Part>() as u32 * 8 - digit_bits;
|
|
||||||
let mask = !0 << rem_bits;
|
|
||||||
let ret = ((*frac_part & mask) >> rem_bits) as u8;
|
|
||||||
*frac_part <<= digit_bits;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_int_dec_digit(int_part: &mut $Part) -> u8 {
|
|
||||||
println!("int part {}", int_part);
|
|
||||||
let ret = (*int_part % 10) as u8;
|
|
||||||
*int_part /= 10;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_frac_dec_digit(frac_part: &mut $Part) -> u8 {
|
|
||||||
let next = frac_part.wrapping_mul(10);
|
|
||||||
let ret = ((*frac_part - next / 10) / (!0 / 10)) as u8;
|
|
||||||
*frac_part = next;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn part_is_zero(part: &$Part) -> bool {
|
|
||||||
*part == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn part_cmp_half(part: &$Part) -> Ordering {
|
|
||||||
part.cmp(&!(!0 >> 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! fixed_num_unsigned {
|
|
||||||
($Fixed:ident($Part:ty)) => {
|
|
||||||
fixed_num_common! {
|
|
||||||
$Fixed($Part);
|
|
||||||
#[inline]
|
|
||||||
fn parts(self) -> (bool, $Part, $Part) {
|
|
||||||
let bits = self.to_bits();
|
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
|
||||||
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
|
|
||||||
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
|
||||||
(false, int_part, frac_part)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! fixed_num_signed {
|
|
||||||
($Fixed:ident($Part:ty)) => {
|
|
||||||
fixed_num_common! {
|
|
||||||
$Fixed($Part);
|
|
||||||
#[inline]
|
|
||||||
fn parts(self) -> (bool, $Part, $Part) {
|
|
||||||
let bits = self.to_bits().wrapping_abs() as $Part;
|
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
|
||||||
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
|
|
||||||
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
|
||||||
(self.0 < 0, int_part,frac_part)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed_num_unsigned! { FixedU8(u8) }
|
|
||||||
fixed_num_unsigned! { FixedU16(u16) }
|
|
||||||
fixed_num_unsigned! { FixedU32(u32) }
|
|
||||||
fixed_num_unsigned! { FixedU64(u64) }
|
|
||||||
fixed_num_unsigned! { FixedU128(u128) }
|
|
||||||
fixed_num_signed! { FixedI8(u8) }
|
|
||||||
fixed_num_signed! { FixedI16(u16) }
|
|
||||||
fixed_num_signed! { FixedI32(u32) }
|
|
||||||
fixed_num_signed! { FixedI64(u64) }
|
|
||||||
fixed_num_signed! { FixedI128(u128) }
|
|
||||||
|
|
||||||
fn fmt_radix2<F: FixedNum, R: Radix2>(num: F, _radix: R, fmt: &mut Formatter) -> FmtResult {
|
fn fmt_radix2<F: FixedNum, R: Radix2>(num: F, _radix: R, fmt: &mut Formatter) -> FmtResult {
|
||||||
let digit_bits: u32 = R::BITS.into();
|
let digit_bits: u32 = R::BITS.into();
|
||||||
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
|
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
|
||||||
|
|
173
src/lib.rs
173
src/lib.rs
|
@ -9,13 +9,17 @@ Coming soon (waiting on [const generics]).
|
||||||
#![doc(html_root_url = "https://docs.rs/rug/0.0.0")]
|
#![doc(html_root_url = "https://docs.rs/rug/0.0.0")]
|
||||||
#![doc(test(attr(deny(warnings))))]
|
#![doc(test(attr(deny(warnings))))]
|
||||||
|
|
||||||
|
mod display;
|
||||||
|
mod traits;
|
||||||
|
|
||||||
|
use std::f32;
|
||||||
|
use std::f64;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{
|
use std::ops::{
|
||||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||||
Mul, MulAssign, Neg, Not, Sub, SubAssign,
|
Mul, MulAssign, Neg, Not, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
use traits::FixedNum;
|
||||||
mod display;
|
|
||||||
|
|
||||||
const F: u32 = 7;
|
const F: u32 = 7;
|
||||||
|
|
||||||
|
@ -112,6 +116,79 @@ macro_rules! doc_comment {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! to_f {
|
||||||
|
($method:ident -> $f:ident($u:ident), $exp_bits:expr, $prec:expr) => {
|
||||||
|
doc_comment! {
|
||||||
|
concat!(
|
||||||
|
"Converts the fixed-point number to `",
|
||||||
|
stringify!($f),
|
||||||
|
"`."
|
||||||
|
),
|
||||||
|
pub fn $method(self) -> $f {
|
||||||
|
// exponent is IEEE754 style (1 <= significand < 2)
|
||||||
|
let exp_max = (1 << ($exp_bits - 1)) - 1;
|
||||||
|
let exp_min = 1 - exp_max;
|
||||||
|
let (int_bits, frac_bits) = (Self::int_bits(), Self::frac_bits());
|
||||||
|
|
||||||
|
let (neg, int, frac) = self.parts();
|
||||||
|
let int_frac = (int << frac_bits) | (frac >> int_bits);
|
||||||
|
let leading_zeros = int_frac.leading_zeros();
|
||||||
|
let signif_bits = int_bits + frac_bits - leading_zeros;
|
||||||
|
if signif_bits == 0 {
|
||||||
|
debug_assert!(!neg);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
// remove leading zeros and implicit one
|
||||||
|
let mut mantissa = int_frac << leading_zeros << 1;
|
||||||
|
let exponent = int_bits as i32 - 1 - leading_zeros as i32;
|
||||||
|
let biased_exponent = if exponent > exp_max {
|
||||||
|
return if neg { $f::NEG_INFINITY } else { $f::INFINITY };
|
||||||
|
} else if exponent < exp_min {
|
||||||
|
let lost_prec = exp_min - exponent;
|
||||||
|
if lost_prec as u32 >= (int_bits + frac_bits) {
|
||||||
|
mantissa = 0;
|
||||||
|
} else {
|
||||||
|
// reinsert implicit one
|
||||||
|
mantissa = (mantissa >> 1) | !(!0 >> 1);
|
||||||
|
mantissa >>= lost_prec - 1;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(exponent + exp_max) as $u
|
||||||
|
};
|
||||||
|
// check for rounding
|
||||||
|
let round_up = (int_bits + frac_bits >= $prec) && {
|
||||||
|
let shift = $prec - 1;
|
||||||
|
let mid_bit = !(!0 >> 1) >> shift;
|
||||||
|
let lower_bits = mid_bit - 1;
|
||||||
|
if mantissa & mid_bit == 0 {
|
||||||
|
false
|
||||||
|
} else if mantissa & lower_bits != 0 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// round to even
|
||||||
|
mantissa & (mid_bit << 1) != 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let bits_sign = if neg { !(!0 >> 1) } else { 0 };
|
||||||
|
let bits_exp = biased_exponent << ($prec - 1);
|
||||||
|
let bits_mantissa = (if int_bits + frac_bits >= $prec - 1 {
|
||||||
|
(mantissa >> (int_bits + frac_bits - $prec + 1)) as $u
|
||||||
|
} else {
|
||||||
|
(mantissa as $u) << ($prec - 1 - int_bits - frac_bits)
|
||||||
|
}) & !(!0 << ($prec - 1));
|
||||||
|
let mut bits_exp_mantissa = bits_exp | bits_mantissa;
|
||||||
|
if round_up {
|
||||||
|
// cannot be infinite already
|
||||||
|
debug_assert!(bits_exp_mantissa != !0 >> 1);
|
||||||
|
bits_exp_mantissa += 1;
|
||||||
|
}
|
||||||
|
$f::from_bits(bits_sign | bits_exp_mantissa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! fixed_unsigned {
|
macro_rules! fixed_unsigned {
|
||||||
($(#[$attr:meta])* $Fixed:ident($Inner:ty)) => {
|
($(#[$attr:meta])* $Fixed:ident($Inner:ty)) => {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -148,6 +225,8 @@ macro_rules! fixed_unsigned {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_f! { to_f32 -> f32(u32), 8, 24 }
|
||||||
|
to_f! { to_f64 -> f64(u64), 11, 53 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pass! { impl Add for $Fixed($Inner) { add } }
|
pass! { impl Add for $Fixed($Inner) { add } }
|
||||||
|
@ -354,4 +433,94 @@ mod tests {
|
||||||
assert_eq!((-af).to_bits(), -(a << F));
|
assert_eq!((-af).to_bits(), -(a << F));
|
||||||
assert_eq!((!af).to_bits(), !(a << F));
|
assert_eq!((!af).to_bits(), !(a << F));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_f32() {
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::from_bits(i);
|
||||||
|
assert_eq!(fi.to_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::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f32(), uu as f32 / 128.0);
|
||||||
|
let ii = uu as i32;
|
||||||
|
let fii = FixedI32::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_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::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f32(), (uu as f64 / 128.0) as f32);
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f32(), (ii as f64 / 128.0) as f32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_f64() {
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::from_bits(i);
|
||||||
|
assert_eq!(fi.to_f32(), i as f32 / 128.0);
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u64,
|
||||||
|
0x0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u as u64;
|
||||||
|
let fuu = FixedU64::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
|
let ii = uu as i64;
|
||||||
|
let fii = FixedI64::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f64(), ii as f64 / 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::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
use {
|
||||||
|
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
||||||
|
FixedU8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const F: u32 = 7;
|
||||||
|
|
||||||
|
pub(crate) trait FixedNum: Copy {
|
||||||
|
type Part;
|
||||||
|
fn parts(self) -> (bool, Self::Part, Self::Part);
|
||||||
|
#[inline(always)]
|
||||||
|
fn int_bits() -> u32 {
|
||||||
|
mem::size_of::<Self::Part>() as u32 * 8 - F
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn frac_bits() -> u32 {
|
||||||
|
F
|
||||||
|
}
|
||||||
|
fn take_int_digit(int_part: &mut Self::Part, digit_bits: u32) -> u8;
|
||||||
|
fn take_frac_digit(frac_part: &mut Self::Part, digit_bits: u32) -> u8;
|
||||||
|
fn take_int_dec_digit(int_part: &mut Self::Part) -> u8;
|
||||||
|
fn take_frac_dec_digit(int_part: &mut Self::Part) -> u8;
|
||||||
|
fn part_is_zero(part: &Self::Part) -> bool;
|
||||||
|
fn part_cmp_half(part: &Self::Part) -> Ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fixed_num_common {
|
||||||
|
($Fixed:ident($Part:ty); $($rem:tt)+) => {
|
||||||
|
impl FixedNum for $Fixed {
|
||||||
|
type Part = $Part;
|
||||||
|
|
||||||
|
$($rem)+
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn take_int_digit(int_part: &mut $Part, digit_bits: u32) -> u8 {
|
||||||
|
let mask = (1 << digit_bits) - 1;
|
||||||
|
let ret = (*int_part & mask) as u8;
|
||||||
|
*int_part >>= digit_bits;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn take_frac_digit(frac_part: &mut $Part, digit_bits: u32) -> u8 {
|
||||||
|
let rem_bits = mem::size_of::<$Part>() as u32 * 8 - digit_bits;
|
||||||
|
let mask = !0 << rem_bits;
|
||||||
|
let ret = ((*frac_part & mask) >> rem_bits) as u8;
|
||||||
|
*frac_part <<= digit_bits;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn take_int_dec_digit(int_part: &mut $Part) -> u8 {
|
||||||
|
println!("int part {}", int_part);
|
||||||
|
let ret = (*int_part % 10) as u8;
|
||||||
|
*int_part /= 10;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn take_frac_dec_digit(frac_part: &mut $Part) -> u8 {
|
||||||
|
let next = frac_part.wrapping_mul(10);
|
||||||
|
let ret = ((*frac_part - next / 10) / (!0 / 10)) as u8;
|
||||||
|
*frac_part = next;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn part_is_zero(part: &$Part) -> bool {
|
||||||
|
*part == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn part_cmp_half(part: &$Part) -> Ordering {
|
||||||
|
part.cmp(&!(!0 >> 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fixed_num_unsigned {
|
||||||
|
($Fixed:ident($Part:ty)) => {
|
||||||
|
fixed_num_common! {
|
||||||
|
$Fixed($Part);
|
||||||
|
#[inline]
|
||||||
|
fn parts(self) -> (bool, $Part, $Part) {
|
||||||
|
let bits = self.to_bits();
|
||||||
|
let int_bits = <$Fixed as FixedNum>::int_bits();
|
||||||
|
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
||||||
|
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
|
||||||
|
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
||||||
|
(false, int_part, frac_part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fixed_num_signed {
|
||||||
|
($Fixed:ident($Part:ty)) => {
|
||||||
|
fixed_num_common! {
|
||||||
|
$Fixed($Part);
|
||||||
|
#[inline]
|
||||||
|
fn parts(self) -> (bool, $Part, $Part) {
|
||||||
|
let bits = self.to_bits().wrapping_abs() as $Part;
|
||||||
|
let int_bits = <$Fixed as FixedNum>::int_bits();
|
||||||
|
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
||||||
|
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
|
||||||
|
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
||||||
|
(self.0 < 0, int_part,frac_part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed_num_unsigned! { FixedU8(u8) }
|
||||||
|
fixed_num_unsigned! { FixedU16(u16) }
|
||||||
|
fixed_num_unsigned! { FixedU32(u32) }
|
||||||
|
fixed_num_unsigned! { FixedU64(u64) }
|
||||||
|
fixed_num_unsigned! { FixedU128(u128) }
|
||||||
|
fixed_num_signed! { FixedI8(u8) }
|
||||||
|
fixed_num_signed! { FixedI16(u16) }
|
||||||
|
fixed_num_signed! { FixedI32(u32) }
|
||||||
|
fixed_num_signed! { FixedI64(u64) }
|
||||||
|
fixed_num_signed! { FixedI128(u128) }
|
Loading…
Reference in New Issue