#![cfg_attr(any(), rustfmt::skip)]
use core::{fmt, mem, ops};
#[cfg(feature = "f16")]
use crate::bf16::bf16;
#[cfg(feature = "f16")]
use crate::f16::f16;
pub trait AsPrimitive: Copy + PartialEq + PartialOrd + Send + Sync + Sized {
fn as_u8(self) -> u8;
fn as_u16(self) -> u16;
fn as_u32(self) -> u32;
fn as_u64(self) -> u64;
fn as_u128(self) -> u128;
fn as_usize(self) -> usize;
fn as_i8(self) -> i8;
fn as_i16(self) -> i16;
fn as_i32(self) -> i32;
fn as_i64(self) -> i64;
fn as_i128(self) -> i128;
fn as_isize(self) -> isize;
fn as_f32(self) -> f32;
fn as_f64(self) -> f64;
fn from_u32(value: u32) -> Self;
fn from_u64(value: u64) -> Self;
#[cfg(feature = "f16")]
fn as_f16(self) -> f16;
#[cfg(feature = "f16")]
fn as_bf16(self) -> bf16;
}
macro_rules! as_primitive {
($($t:ty)*) => ($(
impl AsPrimitive for $t {
#[inline(always)]
fn as_u8(self) -> u8 {
self as u8
}
#[inline(always)]
fn as_u16(self) -> u16 {
self as u16
}
#[inline(always)]
fn as_u32(self) -> u32 {
self as u32
}
#[inline(always)]
fn as_u64(self) -> u64 {
self as u64
}
#[inline(always)]
fn as_u128(self) -> u128 {
self as u128
}
#[inline(always)]
fn as_usize(self) -> usize {
self as usize
}
#[inline(always)]
fn as_i8(self) -> i8 {
self as i8
}
#[inline(always)]
fn as_i16(self) -> i16 {
self as i16
}
#[inline(always)]
fn as_i32(self) -> i32 {
self as i32
}
#[inline(always)]
fn as_i64(self) -> i64 {
self as i64
}
#[inline(always)]
fn as_i128(self) -> i128 {
self as i128
}
#[inline(always)]
fn as_isize(self) -> isize {
self as isize
}
#[inline(always)]
fn as_f32(self) -> f32 {
self as f32
}
#[inline(always)]
fn as_f64(self) -> f64 {
self as f64
}
#[inline(always)]
fn from_u32(value: u32) -> Self {
value as Self
}
#[inline(always)]
fn from_u64(value: u64) -> Self {
value as Self
}
#[cfg(feature = "f16")]
#[inline(always)]
fn as_f16(self) -> f16 {
f16::from_f32(self as f32)
}
#[cfg(feature = "f16")]
#[inline(always)]
fn as_bf16(self) -> bf16 {
bf16::from_f32(self as f32)
}
}
)*)
}
as_primitive! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 }
#[cfg(feature = "f16")]
macro_rules! half_as_primitive {
($($t:ty)*) => ($(
impl AsPrimitive for $t {
#[inline(always)]
fn as_u8(self) -> u8 {
self.as_f32() as u8
}
#[inline(always)]
fn as_u16(self) -> u16 {
self.as_f32() as u16
}
#[inline(always)]
fn as_u32(self) -> u32 {
self.as_f32() as u32
}
#[inline(always)]
fn as_u64(self) -> u64 {
self.as_f32() as u64
}
#[inline(always)]
fn as_u128(self) -> u128 {
self.as_f32() as u128
}
#[inline(always)]
fn as_usize(self) -> usize {
self.as_f32() as usize
}
#[inline(always)]
fn as_i8(self) -> i8 {
self.as_f32() as i8
}
#[inline(always)]
fn as_i16(self) -> i16 {
self.as_f32() as i16
}
#[inline(always)]
fn as_i32(self) -> i32 {
self.as_f32() as i32
}
#[inline(always)]
fn as_i64(self) -> i64 {
self.as_f32() as i64
}
#[inline(always)]
fn as_i128(self) -> i128 {
self.as_f32() as i128
}
#[inline(always)]
fn as_isize(self) -> isize {
self.as_f32() as isize
}
#[inline(always)]
fn as_f32(self) -> f32 {
self.as_f32() as f32
}
#[inline(always)]
fn as_f64(self) -> f64 {
self.as_f32() as f64
}
#[inline(always)]
#[allow(clippy::as_underscore)] fn from_u32(value: u32) -> Self {
Self::from_f32(value as _)
}
#[inline(always)]
fn from_u64(value: u64) -> Self {
_ = value;
unimplemented!()
}
#[inline(always)]
fn as_f16(self) -> f16 {
f16::from_f32(self.as_f32())
}
#[inline(always)]
fn as_bf16(self) -> bf16 {
bf16::from_f32(self.as_f32())
}
}
)*)
}
#[cfg(feature = "f16")]
half_as_primitive! { f16 bf16 }
pub trait AsCast: AsPrimitive {
fn as_cast<N: AsPrimitive>(n: N) -> Self;
}
#[inline(always)]
pub fn as_cast<U: AsCast, T: AsCast>(t: T) -> U {
U::as_cast(t)
}
macro_rules! as_cast {
($($t:ty, $meth:ident ; )*) => ($(
impl AsCast for $t {
#[inline(always)]
#[allow(clippy::as_underscore)] fn as_cast<N: AsPrimitive>(n: N) -> $t {
n.$meth() as _
}
}
)*);
}
as_cast!(
u8, as_u8 ;
u16, as_u16 ;
u32, as_u32 ;
u64, as_u64 ;
u128, as_u128 ;
usize, as_usize ;
i8, as_i8 ;
i16, as_i16 ;
i32, as_i32 ;
i64, as_i64 ;
i128, as_i128 ;
isize, as_isize ;
f32, as_f32 ;
f64, as_f64 ;
);
#[cfg(feature = "f16")]
as_cast!(
f16, as_f16 ;
bf16, as_bf16 ;
);
pub trait Primitive: 'static + fmt::Debug + fmt::Display + AsCast {}
macro_rules! primitive {
($($t:ty)*) => ($(
impl Primitive for $t {}
)*)
}
primitive! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 }
#[cfg(feature = "f16")]
primitive! { f16 bf16 }
pub trait Number:
Default +
Primitive +
ops::Add<Output=Self> +
ops::AddAssign +
ops::Div<Output=Self> +
ops::DivAssign +
ops::Mul<Output=Self> +
ops::MulAssign +
ops::Rem<Output=Self> +
ops::RemAssign +
ops::Sub<Output=Self> +
ops::SubAssign
{
const IS_SIGNED: bool;
}
macro_rules! number_impl {
($($t:tt $is_signed:literal ; )*) => ($(
impl Number for $t {
const IS_SIGNED: bool = $is_signed;
}
)*)
}
number_impl! {
u8 false ;
u16 false ;
u32 false ;
u64 false ;
u128 false ;
usize false ;
i8 true ;
i16 true ;
i32 true ;
i64 true ;
i128 true ;
isize true ;
f32 true ;
f64 true ;
}
#[cfg(feature = "f16")]
number_impl! {
f16 true ;
bf16 true ;
}
pub trait Integer:
Number + Eq + Ord +
ops::BitAnd<Output=Self> +
ops::BitAndAssign +
ops::BitOr<Output=Self> +
ops::BitOrAssign +
ops::BitXor<Output=Self> +
ops::BitXorAssign +
ops::Not<Output=Self> +
ops::Shl<Self, Output=Self> +
ops::Shl<i32, Output=Self> +
ops::ShlAssign<i32> +
ops::Shr<i32, Output=Self> +
ops::ShrAssign<i32> +
{
const ZERO: Self;
const ONE: Self;
const TWO: Self;
const MAX: Self;
const MIN: Self;
const BITS: usize;
fn leading_zeros(self) -> u32;
fn trailing_zeros(self) -> u32;
fn pow(self, exp: u32) -> Self;
fn checked_pow(self, exp: u32) -> Option<Self>;
fn overflowing_pow(self, exp: u32) -> (Self, bool);
fn checked_add(self, i: Self) -> Option<Self>;
fn checked_sub(self, i: Self) -> Option<Self>;
fn checked_mul(self, i: Self) -> Option<Self>;
fn overflowing_add(self, i: Self) -> (Self, bool);
fn overflowing_sub(self, i: Self) -> (Self, bool);
fn overflowing_mul(self, i: Self) -> (Self, bool);
fn wrapping_add(self, i: Self) -> Self;
fn wrapping_sub(self, i: Self) -> Self;
fn wrapping_mul(self, i: Self) -> Self;
fn wrapping_neg(self) -> Self;
fn saturating_add(self, i: Self) -> Self;
fn saturating_sub(self, i: Self) -> Self;
fn saturating_mul(self, i: Self) -> Self;
#[inline(always)]
fn ceil_divmod(self, y: Self) -> (Self, i32) {
let q = self / y;
let r = self % y;
match r == Self::ZERO {
true => (q, i32::as_cast(r)),
false => (q + Self::ONE, i32::as_cast(r) - i32::as_cast(y))
}
}
#[inline(always)]
fn ceil_div(self, y: Self) -> Self {
self.ceil_divmod(y).0
}
#[inline(always)]
fn ceil_mod(self, y: Self) -> i32 {
self.ceil_divmod(y).1
}
#[inline(always)]
fn bit_length(self) -> u32 {
Self::BITS as u32 - self.leading_zeros()
}
#[inline(always)]
fn is_odd(self) -> bool {
self & Self::ONE == Self::ONE
}
#[inline(always)]
fn is_even(self) -> bool {
!self.is_odd()
}
#[inline(always)]
fn overflow_digits(radix: u32) -> usize {
if radix <= 16 {
core::mem::size_of::<Self>() * 2 - Self::IS_SIGNED as usize
} else {
core::mem::size_of::<Self>()
}
}
}
macro_rules! integer_impl {
($($t:tt)*) => ($(
impl Integer for $t {
const ZERO: $t = 0;
const ONE: $t = 1;
const TWO: $t = 2;
const MAX: $t = $t::MAX;
const MIN: $t = $t::MIN;
const BITS: usize = mem::size_of::<$t>() * 8;
#[inline(always)]
fn leading_zeros(self) -> u32 {
$t::leading_zeros(self)
}
#[inline(always)]
fn trailing_zeros(self) -> u32 {
$t::trailing_zeros(self)
}
#[inline(always)]
fn checked_add(self, i: Self) -> Option<Self> {
$t::checked_add(self, i)
}
#[inline(always)]
fn checked_sub(self, i: Self) -> Option<Self> {
$t::checked_sub(self, i)
}
#[inline(always)]
fn checked_mul(self, i: Self) -> Option<Self> {
$t::checked_mul(self, i)
}
#[inline(always)]
fn overflowing_add(self, i: Self) -> (Self, bool) {
$t::overflowing_add(self, i)
}
#[inline(always)]
fn overflowing_sub(self, i: Self) -> (Self, bool) {
$t::overflowing_sub(self, i)
}
#[inline(always)]
fn overflowing_mul(self, i: Self) -> (Self, bool) {
$t::overflowing_mul(self, i)
}
#[inline(always)]
fn wrapping_add(self, i: Self) -> Self {
$t::wrapping_add(self, i)
}
#[inline(always)]
fn wrapping_sub(self, i: Self) -> Self {
$t::wrapping_sub(self, i)
}
#[inline(always)]
fn wrapping_mul(self, i: Self) -> Self {
$t::wrapping_mul(self, i)
}
#[inline(always)]
fn wrapping_neg(self) -> Self {
$t::wrapping_neg(self)
}
#[inline(always)]
fn pow(self, exp: u32) -> Self {
Self::pow(self, exp)
}
#[inline(always)]
fn checked_pow(self, exp: u32) -> Option<Self> {
Self::checked_pow(self, exp)
}
#[inline(always)]
fn overflowing_pow(self, exp: u32) -> (Self, bool) {
Self::overflowing_pow(self, exp)
}
#[inline(always)]
fn saturating_add(self, i: Self) -> Self {
$t::saturating_add(self, i)
}
#[inline(always)]
fn saturating_sub(self, i: Self) -> Self {
$t::saturating_sub(self, i)
}
#[inline(always)]
fn saturating_mul(self, i: Self) -> Self {
$t::saturating_mul(self, i)
}
}
)*)
}
integer_impl! { u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 usize isize }
pub trait SignedInteger: Integer + ops::Neg<Output = Self> {}
macro_rules! signed_integer_impl {
($($t:tt)*) => ($(
impl SignedInteger for $t {}
)*)
}
signed_integer_impl! { i8 i16 i32 i64 i128 isize }
pub trait UnsignedInteger: Integer {}
macro_rules! unsigned_integer_impl {
($($t:ty)*) => ($(
impl UnsignedInteger for $t {}
)*)
}
unsigned_integer_impl! { u8 u16 u32 u64 u128 usize }
#[cfg(feature = "floats")]
pub trait Float: Number + ops::Neg<Output = Self> {
type Unsigned: UnsignedInteger;
const ZERO: Self;
const ONE: Self;
const TWO: Self;
const MAX: Self;
const MIN: Self;
const INFINITY: Self;
const NEG_INFINITY: Self;
const NAN: Self;
const BITS: usize;
const SIGN_MASK: Self::Unsigned;
const EXPONENT_MASK: Self::Unsigned;
const HIDDEN_BIT_MASK: Self::Unsigned;
const MANTISSA_MASK: Self::Unsigned;
const CARRY_MASK: Self::Unsigned;
const INFINITY_BITS: Self::Unsigned;
const NEGATIVE_INFINITY_BITS: Self::Unsigned;
const EXPONENT_SIZE: i32;
const MANTISSA_SIZE: i32;
const EXPONENT_BIAS: i32;
const DENORMAL_EXPONENT: i32;
const MAX_EXPONENT: i32;
fn to_bits(self) -> Self::Unsigned;
fn from_bits(u: Self::Unsigned) -> Self;
fn ln(self) -> Self;
fn floor(self) -> Self;
fn is_sign_positive(self) -> bool;
fn is_sign_negative(self) -> bool;
#[inline(always)]
fn is_denormal(self) -> bool {
self.to_bits() & Self::EXPONENT_MASK == Self::Unsigned::ZERO
}
#[inline(always)]
fn is_special(self) -> bool {
self.to_bits() & Self::EXPONENT_MASK == Self::EXPONENT_MASK
}
#[inline(always)]
fn is_nan(self) -> bool {
self.is_special() && (self.to_bits() & Self::MANTISSA_MASK) != Self::Unsigned::ZERO
}
#[inline(always)]
fn is_inf(self) -> bool {
self.is_special() && (self.to_bits() & Self::MANTISSA_MASK) == Self::Unsigned::ZERO
}
#[inline(always)]
fn is_odd(self) -> bool {
self.to_bits().is_odd()
}
#[inline(always)]
fn is_even(self) -> bool {
!self.is_odd()
}
#[inline(always)]
fn needs_negative_sign(self) -> bool {
self.is_sign_negative() && !self.is_nan()
}
#[inline(always)]
fn exponent(self) -> i32 {
if self.is_denormal() {
return Self::DENORMAL_EXPONENT;
}
let bits = self.to_bits();
let biased_e = i32::as_cast((bits & Self::EXPONENT_MASK) >> Self::MANTISSA_SIZE).as_i32();
biased_e - Self::EXPONENT_BIAS
}
#[inline(always)]
fn mantissa(self) -> Self::Unsigned {
let bits = self.to_bits();
let s = bits & Self::MANTISSA_MASK;
if !self.is_denormal() {
s + Self::HIDDEN_BIT_MASK
} else {
s
}
}
#[inline(always)]
fn next(self) -> Self {
let bits = self.to_bits();
if self.is_sign_negative() && self == Self::ZERO {
Self::ZERO
} else if bits == Self::INFINITY_BITS {
Self::from_bits(Self::INFINITY_BITS)
} else if self.is_sign_negative() {
Self::from_bits(bits.saturating_sub(Self::Unsigned::ONE))
} else {
Self::from_bits(bits.saturating_add(Self::Unsigned::ONE))
}
}
#[inline(always)]
fn next_positive(self) -> Self {
debug_assert!(self.is_sign_positive() && !self.is_inf());
Self::from_bits(self.to_bits() + Self::Unsigned::ONE)
}
#[inline(always)]
fn prev(self) -> Self {
let bits = self.to_bits();
if self.is_sign_positive() && self == Self::ZERO {
-Self::ZERO
} else if bits == Self::NEGATIVE_INFINITY_BITS {
Self::from_bits(Self::NEGATIVE_INFINITY_BITS)
} else if self.is_sign_negative() {
Self::from_bits(bits.saturating_add(Self::Unsigned::ONE))
} else {
Self::from_bits(bits.saturating_sub(Self::Unsigned::ONE))
}
}
#[inline(always)]
fn prev_positive(self) -> Self {
debug_assert!(self.is_sign_positive() && self != Self::ZERO);
Self::from_bits(self.to_bits() - Self::Unsigned::ONE)
}
#[inline(always)]
fn round_positive_even(self) -> Self {
if self.mantissa().is_odd() {
self.next_positive()
} else {
self
}
}
#[inline(always)]
fn max_finite(self, f: Self) -> Self {
debug_assert!(!self.is_special() && !f.is_special(), "max_finite self={} f={}", self, f);
if self < f {
f
} else {
self
}
}
#[inline(always)]
fn min_finite(self, f: Self) -> Self {
debug_assert!(!self.is_special() && !f.is_special(), "min_finite self={} f={}", self, f);
if self < f {
self
} else {
f
}
}
}
#[cfg(feature = "floats")]
macro_rules! float_literals {
($float:ty) => {
const ZERO: $float = 0.0;
const ONE: $float = 1.0;
const TWO: $float = 2.0;
const MAX: $float = <$float>::MAX;
const MIN: $float = <$float>::MIN;
const INFINITY: $float = <$float>::INFINITY;
const NEG_INFINITY: $float = <$float>::NEG_INFINITY;
const NAN: $float = <$float>::NAN;
const BITS: usize = mem::size_of::<$float>() * 8;
};
}
#[cfg(feature = "floats")]
macro_rules! float_masks {
(
float =>
$float:ty,sign_mask =>
$sign:literal,exponent_mask =>
$exponent:literal,hidden_bit_mask =>
$hidden:literal,mantissa_mask =>
$mantissa:literal,
) => {
const SIGN_MASK: <$float>::Unsigned = $sign;
const EXPONENT_MASK: <$float>::Unsigned = $exponent;
const HIDDEN_BIT_MASK: <$float>::Unsigned = $hidden;
const MANTISSA_MASK: <$float>::Unsigned = $mantissa;
const CARRY_MASK: <$float>::Unsigned = $hidden << 1;
const INFINITY_BITS: <$float>::Unsigned = $exponent;
const NEGATIVE_INFINITY_BITS: <$float>::Unsigned = $exponent | $sign;
};
}
#[cfg(feature = "f16")]
macro_rules! float_one {
($f:ident) => {
(($f::EXPONENT_BIAS - $f::MANTISSA_SIZE) as u16) << $f::MANTISSA_SIZE
};
}
#[cfg(feature = "f16")]
macro_rules! float_two {
($f:ident) => {
(($f::EXPONENT_BIAS - $f::MANTISSA_SIZE + 1) as u16) << $f::MANTISSA_SIZE
};
}
#[cfg(feature = "f16")]
macro_rules! float_max {
($f:ident) => {
($f::EXPONENT_MASK ^ $f::HIDDEN_BIT_MASK) | $f::MANTISSA_MASK
};
}
#[cfg(feature = "f16")]
macro_rules! float_min {
($f:ident) => {
$f::MAX.to_bits() | $f::SIGN_MASK
};
}
#[cfg(feature = "f16")]
macro_rules! float_nan {
($f:ident) => {
$f::EXPONENT_MASK | ($f::HIDDEN_BIT_MASK >> 1)
};
}
#[cfg(feature = "f16")]
impl Float for f16 {
type Unsigned = u16;
const ZERO: Self = Self::from_bits(0);
const ONE: Self = Self::from_bits(float_one!(Self));
const TWO: Self = Self::from_bits(float_two!(Self));
const MAX: Self = Self::from_bits(float_max!(Self));
const MIN: Self = Self::from_bits(float_min!(Self));
const INFINITY: Self = Self::from_bits(Self::INFINITY_BITS);
const NEG_INFINITY: Self = Self::from_bits(Self::NEGATIVE_INFINITY_BITS);
const NAN: Self = Self::from_bits(float_nan!(Self));
const BITS: usize = mem::size_of::<Self>() * 8;
float_masks!(
float => Self,
sign_mask => 0x8000,
exponent_mask => 0x7C00,
hidden_bit_mask => 0x0400,
mantissa_mask => 0x03FF,
);
const EXPONENT_SIZE: i32 = 5;
const MANTISSA_SIZE: i32 = 10;
const EXPONENT_BIAS: i32 = 15 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;
const MAX_EXPONENT: i32 = 0x1F - Self::EXPONENT_BIAS;
#[inline(always)]
fn to_bits(self) -> u16 {
f16::to_bits(self)
}
#[inline(always)]
fn from_bits(u: u16) -> f16 {
f16::from_bits(u)
}
#[inline(always)]
fn ln(self) -> f16 {
f16::from_f32(self.as_f32().ln())
}
#[inline(always)]
fn floor(self) -> f16 {
f16::from_f32(self.as_f32().floor())
}
#[inline(always)]
fn is_sign_positive(self) -> bool {
self.to_bits() & Self::SIGN_MASK == 0
}
#[inline(always)]
fn is_sign_negative(self) -> bool {
!self.is_sign_positive()
}
}
#[cfg(feature = "f16")]
impl Float for bf16 {
type Unsigned = u16;
const ZERO: Self = Self::from_bits(0);
const ONE: Self = Self::from_bits(float_one!(Self));
const TWO: Self = Self::from_bits(float_two!(Self));
const MAX: Self = Self::from_bits(float_max!(Self));
const MIN: Self = Self::from_bits(float_min!(Self));
const INFINITY: Self = Self::from_bits(Self::INFINITY_BITS);
const NEG_INFINITY: Self = Self::from_bits(Self::NEGATIVE_INFINITY_BITS);
const NAN: Self = Self::from_bits(float_nan!(Self));
const BITS: usize = mem::size_of::<Self>() * 8;
float_masks!(
float => Self,
sign_mask => 0x8000,
exponent_mask => 0x7F80,
hidden_bit_mask => 0x0080,
mantissa_mask => 0x007F,
);
const EXPONENT_SIZE: i32 = 8;
const MANTISSA_SIZE: i32 = 7;
const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;
const MAX_EXPONENT: i32 = 0xFF - Self::EXPONENT_BIAS;
#[inline(always)]
fn to_bits(self) -> u16 {
bf16::to_bits(self)
}
#[inline(always)]
fn from_bits(u: u16) -> bf16 {
bf16::from_bits(u)
}
#[inline(always)]
fn ln(self) -> bf16 {
bf16::from_f32(self.as_f32().ln())
}
#[inline(always)]
fn floor(self) -> bf16 {
bf16::from_f32(self.as_f32().floor())
}
#[inline(always)]
fn is_sign_positive(self) -> bool {
self.to_bits() & Self::SIGN_MASK == 0
}
#[inline(always)]
fn is_sign_negative(self) -> bool {
!self.is_sign_positive()
}
}
#[cfg(feature = "floats")]
impl Float for f32 {
type Unsigned = u32;
float_literals!(f32);
float_masks!(
float => Self,
sign_mask => 0x80000000,
exponent_mask => 0x7F800000,
hidden_bit_mask => 0x00800000,
mantissa_mask => 0x007FFFFF,
);
const EXPONENT_SIZE: i32 = 8;
const MANTISSA_SIZE: i32 = 23;
const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;
const MAX_EXPONENT: i32 = 0xFF - Self::EXPONENT_BIAS;
#[inline(always)]
fn to_bits(self) -> u32 {
f32::to_bits(self)
}
#[inline(always)]
fn from_bits(u: u32) -> f32 {
f32::from_bits(u)
}
#[inline(always)]
fn ln(self) -> f32 {
#[cfg(feature = "std")]
return f32::ln(self);
#[cfg(not(feature = "std"))]
return logf(self);
}
#[inline(always)]
fn floor(self) -> f32 {
#[cfg(feature = "std")]
return f32::floor(self);
#[cfg(not(feature = "std"))]
return floorf(self);
}
#[inline(always)]
fn is_sign_positive(self) -> bool {
f32::is_sign_positive(self)
}
#[inline(always)]
fn is_sign_negative(self) -> bool {
f32::is_sign_negative(self)
}
}
#[cfg(feature = "floats")]
impl Float for f64 {
type Unsigned = u64;
float_literals!(f64);
float_masks!(
float => Self,
sign_mask => 0x8000000000000000,
exponent_mask => 0x7FF0000000000000,
hidden_bit_mask => 0x0010000000000000,
mantissa_mask => 0x000FFFFFFFFFFFFF,
);
const EXPONENT_SIZE: i32 = 11;
const MANTISSA_SIZE: i32 = 52;
const EXPONENT_BIAS: i32 = 1023 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;
const MAX_EXPONENT: i32 = 0x7FF - Self::EXPONENT_BIAS;
#[inline(always)]
fn to_bits(self) -> u64 {
f64::to_bits(self)
}
#[inline(always)]
fn from_bits(u: u64) -> f64 {
f64::from_bits(u)
}
#[inline(always)]
fn ln(self) -> f64 {
#[cfg(feature = "std")]
return f64::ln(self);
#[cfg(not(feature = "std"))]
return logd(self);
}
#[inline(always)]
fn floor(self) -> f64 {
#[cfg(feature = "std")]
return f64::floor(self);
#[cfg(not(feature = "std"))]
return floord(self);
}
#[inline(always)]
fn is_sign_positive(self) -> bool {
f64::is_sign_positive(self)
}
#[inline(always)]
fn is_sign_negative(self) -> bool {
f64::is_sign_negative(self)
}
}
#[cfg(all(not(feature = "std"), feature = "floats"))]
macro_rules! volatile {
($e:expr) => {
unsafe {
core::ptr::read_volatile(&$e);
}
};
}
#[cfg(all(not(feature = "std"), feature = "floats"))]
fn floord(x: f64) -> f64 {
const TOINT: f64 = 1. / f64::EPSILON;
let ui = x.to_bits();
let e = ((ui >> 52) & 0x7ff) as i32;
if (e >= 0x3ff + 52) || (x == 0.) {
return x;
}
let y = if (ui >> 63) != 0 {
x - TOINT + TOINT - x
} else {
x + TOINT - TOINT - x
};
if e < 0x3ff {
volatile!(y);
return if (ui >> 63) != 0 {
-1.
} else {
0.
};
}
if y > 0. {
x + y - 1.
} else {
x + y
}
}
#[cfg(all(not(feature = "std"), feature = "floats"))]
fn floorf(x: f32) -> f32 {
let mut ui = x.to_bits();
let e = (((ui >> 23) as i32) & 0xff) - 0x7f;
if e >= 23 {
return x;
}
if e >= 0 {
let m: u32 = 0x007fffff >> e;
if (ui & m) == 0 {
return x;
}
volatile!(x + f32::from_bits(0x7b800000));
if ui >> 31 != 0 {
ui += m;
}
ui &= !m;
} else {
volatile!(x + f32::from_bits(0x7b800000));
if ui >> 31 == 0 {
ui = 0;
} else if ui << 1 != 0 {
return -1.0;
}
}
f32::from_bits(ui)
}
#[allow(clippy::eq_op, clippy::excessive_precision)] #[cfg(all(not(feature = "std"), feature = "floats"))]
fn logd(mut x: f64) -> f64 {
const LN2_HI: f64 = 6.93147180369123816490e-01; const LN2_LO: f64 = 1.90821492927058770002e-10; const LG1: f64 = 6.666666666666735130e-01; const LG2: f64 = 3.999999999940941908e-01; const LG3: f64 = 2.857142874366239149e-01; const LG4: f64 = 2.222219843214978396e-01; const LG5: f64 = 1.818357216161805012e-01; const LG6: f64 = 1.531383769920937332e-01; const LG7: f64 = 1.479819860511658591e-01; let x1p54 = f64::from_bits(0x4350000000000000); let mut ui = x.to_bits();
let mut hx: u32 = (ui >> 32) as u32;
let mut k: i32 = 0;
if (hx < 0x00100000) || ((hx >> 31) != 0) {
if ui << 1 == 0 {
return -1. / (x * x); }
if hx >> 31 != 0 {
return (x - x) / 0.0; }
k -= 54;
x *= x1p54;
ui = x.to_bits();
hx = (ui >> 32) as u32;
} else if hx >= 0x7ff00000 {
return x;
} else if hx == 0x3ff00000 && ui << 32 == 0 {
return 0.;
}
hx += 0x3ff00000 - 0x3fe6a09e;
k += ((hx >> 20) as i32) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e;
ui = ((hx as u64) << 32) | (ui & 0xffffffff);
x = f64::from_bits(ui);
let f: f64 = x - 1.0;
let hfsq: f64 = 0.5 * f * f;
let s: f64 = f / (2.0 + f);
let z: f64 = s * s;
let w: f64 = z * z;
let t1: f64 = w * (LG2 + w * (LG4 + w * LG6));
let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
let r: f64 = t2 + t1;
let dk: f64 = k as f64;
s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI
}
#[allow(clippy::eq_op, clippy::excessive_precision)] #[cfg(all(not(feature = "std"), feature = "floats"))]
fn logf(mut x: f32) -> f32 {
const LN2_HI: f32 = 6.9313812256e-01; const LN2_LO: f32 = 9.0580006145e-06; const LG1: f32 = 0.66666662693; const LG2: f32 = 0.40000972152; const LG3: f32 = 0.28498786688; const LG4: f32 = 0.24279078841; let x1p25 = f32::from_bits(0x4c000000); let mut ix = x.to_bits();
let mut k = 0i32;
if (ix < 0x00800000) || ((ix >> 31) != 0) {
if ix << 1 == 0 {
return -1. / (x * x); }
if (ix >> 31) != 0 {
return (x - x) / 0.; }
k -= 25;
x *= x1p25;
ix = x.to_bits();
} else if ix >= 0x7f800000 {
return x;
} else if ix == 0x3f800000 {
return 0.;
}
ix += 0x3f800000 - 0x3f3504f3;
k += ((ix >> 23) as i32) - 0x7f;
ix = (ix & 0x007fffff) + 0x3f3504f3;
x = f32::from_bits(ix);
let f = x - 1.;
let s = f / (2. + f);
let z = s * s;
let w = z * z;
let t1 = w * (LG2 + w * LG4);
let t2 = z * (LG1 + w * LG3);
let r = t2 + t1;
let hfsq = 0.5 * f * f;
let dk = k as f32;
s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI
}