use crate::num::arithmetic::traits::{
ArithmeticCheckedShl, DivisibleByPowerOf2, ModPowerOf2, ShrRound,
};
use crate::num::basic::floats::PrimitiveFloat;
use crate::num::basic::integers::PrimitiveInt;
use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::{
ExactFrom, IntegerMantissaAndExponent, RawMantissaAndExponent, SciMantissaAndExponent,
WrappingFrom,
};
use crate::num::logic::traits::{BitAccess, LeadingZeros, LowMask, SignificantBits, TrailingZeros};
use crate::rounding_modes::RoundingMode::{self, *};
use core::cmp::Ordering::{self, *};
fn raw_mantissa_and_exponent<T: PrimitiveFloat>(x: T) -> (u64, u64) {
let bits = x.to_bits();
(
bits.mod_power_of_2(T::MANTISSA_WIDTH),
(bits >> T::MANTISSA_WIDTH).mod_power_of_2(T::EXPONENT_WIDTH),
)
}
#[inline]
fn raw_mantissa<T: PrimitiveFloat>(x: T) -> u64 {
x.to_bits().mod_power_of_2(T::MANTISSA_WIDTH)
}
#[inline]
fn raw_exponent<T: PrimitiveFloat>(x: T) -> u64 {
(x.to_bits() >> T::MANTISSA_WIDTH).mod_power_of_2(T::EXPONENT_WIDTH)
}
fn from_raw_mantissa_and_exponent<T: PrimitiveFloat>(raw_mantissa: u64, raw_exponent: u64) -> T {
assert!(raw_mantissa.significant_bits() <= T::MANTISSA_WIDTH);
assert!(raw_exponent.significant_bits() <= T::EXPONENT_WIDTH);
let x = T::from_bits((raw_exponent << T::MANTISSA_WIDTH) | raw_mantissa);
if x.is_nan() { T::NAN } else { x }
}
fn integer_mantissa_and_exponent_primitive_float<T: PrimitiveFloat>(x: T) -> (u64, i64) {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (mut raw_mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent == 0 {
let trailing_zeros = raw_mantissa.trailing_zeros();
(
raw_mantissa >> trailing_zeros,
i64::wrapping_from(trailing_zeros) + T::MIN_EXPONENT,
)
} else {
raw_mantissa.set_bit(T::MANTISSA_WIDTH);
let trailing_zeros = TrailingZeros::trailing_zeros(raw_mantissa);
(
raw_mantissa >> trailing_zeros,
i64::wrapping_from(raw_exponent + trailing_zeros) + T::MIN_EXPONENT - 1,
)
}
}
fn integer_mantissa_primitive_float<T: PrimitiveFloat>(x: T) -> u64 {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (mut raw_mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent != 0 {
raw_mantissa.set_bit(T::MANTISSA_WIDTH);
}
raw_mantissa >> raw_mantissa.trailing_zeros()
}
fn integer_exponent_primitive_float<T: PrimitiveFloat>(x: T) -> i64 {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (raw_mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent == 0 {
i64::wrapping_from(raw_mantissa.trailing_zeros()) + T::MIN_EXPONENT
} else {
i64::wrapping_from(
raw_exponent
+ if raw_mantissa == 0 {
T::MANTISSA_WIDTH
} else {
TrailingZeros::trailing_zeros(raw_mantissa)
},
) + T::MIN_EXPONENT
- 1
}
}
fn from_integer_mantissa_and_exponent_primitive_float<T: PrimitiveFloat>(
integer_mantissa: u64,
integer_exponent: i64,
) -> Option<T> {
if integer_mantissa == 0 {
return Some(T::ZERO);
}
let trailing_zeros = integer_mantissa.trailing_zeros();
let (integer_mantissa, adjusted_exponent) = (
integer_mantissa >> trailing_zeros,
integer_exponent + i64::wrapping_from(trailing_zeros),
);
let mantissa_bits = integer_mantissa.significant_bits();
let sci_exponent = adjusted_exponent.checked_add(i64::exact_from(mantissa_bits))? - 1;
let mut raw_mantissa;
let raw_exponent;
if sci_exponent < T::MIN_EXPONENT || sci_exponent > T::MAX_EXPONENT {
return None;
} else if sci_exponent < T::MIN_NORMAL_EXPONENT {
if adjusted_exponent < T::MIN_EXPONENT {
return None;
}
raw_exponent = 0;
raw_mantissa = integer_mantissa << (adjusted_exponent - T::MIN_EXPONENT);
} else if mantissa_bits > T::MANTISSA_WIDTH + 1 {
return None;
} else {
raw_exponent = u64::exact_from(sci_exponent + i64::low_mask(T::EXPONENT_WIDTH - 1));
raw_mantissa = integer_mantissa << (T::MANTISSA_WIDTH + 1 - mantissa_bits);
raw_mantissa.clear_bit(T::MANTISSA_WIDTH);
}
Some(T::from_raw_mantissa_and_exponent(
raw_mantissa,
raw_exponent,
))
}
fn sci_mantissa_and_exponent_primitive_float<T: PrimitiveFloat>(x: T) -> (T, i64) {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (raw_mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent == 0 {
let leading_zeros =
LeadingZeros::leading_zeros(raw_mantissa) - (u64::WIDTH - T::MANTISSA_WIDTH);
let mut mantissa = raw_mantissa << (leading_zeros + 1);
mantissa.clear_bit(T::MANTISSA_WIDTH);
(
T::from_raw_mantissa_and_exponent(mantissa, u64::wrapping_from(T::MAX_EXPONENT)),
i64::wrapping_from(T::MANTISSA_WIDTH - leading_zeros - 1) + T::MIN_EXPONENT,
)
} else {
(
T::from_raw_mantissa_and_exponent(raw_mantissa, u64::wrapping_from(T::MAX_EXPONENT)),
i64::wrapping_from(raw_exponent) - T::MAX_EXPONENT,
)
}
}
fn sci_mantissa_primitive_float<T: PrimitiveFloat>(x: T) -> T {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (mut mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent == 0 {
mantissa <<= LeadingZeros::leading_zeros(mantissa) - (u64::WIDTH - T::MANTISSA_WIDTH) + 1;
mantissa.clear_bit(T::MANTISSA_WIDTH);
}
T::from_raw_mantissa_and_exponent(mantissa, u64::wrapping_from(T::MAX_EXPONENT))
}
fn sci_exponent_primitive_float<T: PrimitiveFloat>(x: T) -> i64 {
assert!(x.is_finite());
assert!(x != T::ZERO);
let (raw_mantissa, raw_exponent) = x.raw_mantissa_and_exponent();
if raw_exponent == 0 {
i64::wrapping_from(u64::WIDTH - LeadingZeros::leading_zeros(raw_mantissa) - 1)
+ T::MIN_EXPONENT
} else {
i64::wrapping_from(raw_exponent) - T::MAX_EXPONENT
}
}
#[allow(clippy::wrong_self_convention)]
fn from_sci_mantissa_and_exponent_primitive_float<T: PrimitiveFloat>(
sci_mantissa: T,
sci_exponent: i64,
) -> Option<T> {
assert!(sci_mantissa.is_finite());
assert!(sci_mantissa > T::ZERO);
if sci_exponent < T::MIN_EXPONENT || sci_exponent > T::MAX_EXPONENT {
return None;
}
let (mut orig_mantissa, orig_exponent) = sci_mantissa.raw_mantissa_and_exponent();
if orig_exponent != u64::wrapping_from(T::MAX_EXPONENT) {
return None;
}
if sci_exponent < T::MIN_NORMAL_EXPONENT {
let shift = T::MIN_NORMAL_EXPONENT - sci_exponent;
if orig_mantissa.divisible_by_power_of_2(u64::wrapping_from(shift)) {
orig_mantissa.set_bit(T::MANTISSA_WIDTH);
Some(T::from_raw_mantissa_and_exponent(orig_mantissa >> shift, 0))
} else {
None
}
} else {
Some(T::from_raw_mantissa_and_exponent(
orig_mantissa,
u64::wrapping_from(sci_exponent + T::MAX_EXPONENT),
))
}
}
pub fn sci_mantissa_and_exponent_round<T: PrimitiveUnsigned, U: PrimitiveFloat>(
x: T,
rm: RoundingMode,
) -> Option<(U, u64, Ordering)> {
assert_ne!(x, T::ZERO);
let significant_bits = x.significant_bits();
let mut exponent = significant_bits - 1;
let (mut raw_mantissa, o) = if significant_bits > U::MANTISSA_WIDTH {
let shift = significant_bits - U::MANTISSA_WIDTH - 1;
if rm == Exact && TrailingZeros::trailing_zeros(x) < shift {
return None;
}
let (s, o) = x.shr_round(shift, rm);
(s.wrapping_into(), o)
} else {
let x: u64 = x.wrapping_into();
(x << (U::MANTISSA_WIDTH - significant_bits + 1), Equal)
};
if raw_mantissa.significant_bits() == U::MANTISSA_WIDTH + 2 {
raw_mantissa >>= 1;
exponent += 1;
}
raw_mantissa.clear_bit(U::MANTISSA_WIDTH);
Some((
U::from_raw_mantissa_and_exponent(raw_mantissa, u64::wrapping_from(U::MAX_EXPONENT)),
exponent,
o,
))
}
pub fn from_sci_mantissa_and_exponent_round<T: PrimitiveUnsigned, U: PrimitiveFloat>(
sci_mantissa: U,
sci_exponent: u64,
rm: RoundingMode,
) -> Option<(T, Ordering)> {
assert_ne!(sci_mantissa, U::ZERO);
if sci_mantissa < U::ONE || sci_mantissa >= U::TWO {
return None;
}
let mut raw_mantissa = sci_mantissa.raw_mantissa();
raw_mantissa.set_bit(U::MANTISSA_WIDTH);
if sci_exponent >= U::MANTISSA_WIDTH {
T::try_from(raw_mantissa)
.ok()?
.arithmetic_checked_shl(sci_exponent - U::MANTISSA_WIDTH)
.map(|n| (n, Equal))
} else {
let shift = U::MANTISSA_WIDTH - sci_exponent;
if rm == Exact && TrailingZeros::trailing_zeros(raw_mantissa) < shift {
return None;
}
let (s, o) = raw_mantissa.shr_round(shift, rm);
T::try_from(s).ok().map(|s| (s, o))
}
}
macro_rules! impl_mantissa_and_exponent_unsigned {
($t:ident) => {
impl IntegerMantissaAndExponent<$t, u64> for $t {
#[inline]
fn integer_mantissa_and_exponent(self) -> ($t, u64) {
assert_ne!(self, 0);
let exponent = TrailingZeros::trailing_zeros(self);
(self >> exponent, exponent)
}
#[inline]
fn integer_mantissa(self) -> $t {
assert_ne!(self, 0);
self >> self.trailing_zeros()
}
#[inline]
fn integer_exponent(self) -> u64 {
assert_ne!(self, 0);
TrailingZeros::trailing_zeros(self)
}
#[inline]
fn from_integer_mantissa_and_exponent(
integer_mantissa: $t,
integer_exponent: u64,
) -> Option<$t> {
integer_mantissa.arithmetic_checked_shl(integer_exponent)
}
}
};
}
apply_to_unsigneds!(impl_mantissa_and_exponent_unsigned);
macro_rules! impl_sci_mantissa_and_exponent_unsigned {
($u:ident) => {
macro_rules! impl_sci_mantissa_and_exponent_unsigned_inner {
($f:ident) => {
impl SciMantissaAndExponent<$f, u64> for $u {
#[inline]
fn sci_mantissa_and_exponent(self) -> ($f, u64) {
let (m, e, _) = sci_mantissa_and_exponent_round(self, Nearest).unwrap();
(m, e)
}
#[inline]
fn from_sci_mantissa_and_exponent(
sci_mantissa: $f,
sci_exponent: u64,
) -> Option<$u> {
from_sci_mantissa_and_exponent_round(sci_mantissa, sci_exponent, Nearest)
.map(|p| p.0)
}
}
};
}
apply_to_primitive_floats!(impl_sci_mantissa_and_exponent_unsigned_inner);
};
}
apply_to_unsigneds!(impl_sci_mantissa_and_exponent_unsigned);
macro_rules! impl_mantissa_and_exponent_primitive_float {
($t:ident) => {
impl RawMantissaAndExponent<u64, u64> for $t {
#[inline]
fn raw_mantissa_and_exponent(self) -> (u64, u64) {
raw_mantissa_and_exponent(self)
}
#[inline]
fn raw_mantissa(self) -> u64 {
raw_mantissa(self)
}
#[inline]
fn raw_exponent(self) -> u64 {
raw_exponent(self)
}
#[inline]
fn from_raw_mantissa_and_exponent(raw_mantissa: u64, raw_exponent: u64) -> $t {
from_raw_mantissa_and_exponent(raw_mantissa, raw_exponent)
}
}
impl IntegerMantissaAndExponent<u64, i64> for $t {
#[inline]
fn integer_mantissa_and_exponent(self) -> (u64, i64) {
integer_mantissa_and_exponent_primitive_float(self)
}
#[inline]
fn integer_mantissa(self) -> u64 {
integer_mantissa_primitive_float(self)
}
#[inline]
fn integer_exponent(self) -> i64 {
integer_exponent_primitive_float(self)
}
#[inline]
fn from_integer_mantissa_and_exponent(
integer_mantissa: u64,
integer_exponent: i64,
) -> Option<$t> {
from_integer_mantissa_and_exponent_primitive_float(
integer_mantissa,
integer_exponent,
)
}
}
impl SciMantissaAndExponent<$t, i64> for $t {
#[inline]
fn sci_mantissa_and_exponent(self) -> ($t, i64) {
sci_mantissa_and_exponent_primitive_float(self)
}
#[inline]
fn sci_mantissa(self) -> $t {
sci_mantissa_primitive_float(self)
}
#[inline]
fn sci_exponent(self) -> i64 {
sci_exponent_primitive_float(self)
}
#[inline]
fn from_sci_mantissa_and_exponent(sci_mantissa: $t, sci_exponent: i64) -> Option<$t> {
from_sci_mantissa_and_exponent_primitive_float(sci_mantissa, sci_exponent)
}
}
};
}
apply_to_primitive_floats!(impl_mantissa_and_exponent_primitive_float);