use crate::core::integer::*;
use crate::core::undefined::*;
use crate::{Integer, Scalar, ScalarConstants};
use num_traits::AsPrimitive;
impl<F: Integer + FullInt, E: Integer + FullInt> From<f64> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary64: f64) -> Self {
Self::from(&binary64)
}
}
impl<F: Integer + FullInt, E: Integer + FullInt> From<&mut f64> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary64: &mut f64) -> Self {
Self::from(*binary64)
}
}
impl<F: Integer + FullInt, E: Integer + FullInt> From<&f64> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary64: &f64) -> Self {
let bits = binary64.to_bits();
let sign = bits >> 63;
let raw_exp = ((bits >> 52) & 0x7FF) as i16;
let mantissa = bits & 0xFFFFFFFFFFFFF;
if raw_exp == 0x7FF {
return if mantissa != 0 {
Scalar {
fraction: GENERAL.prefix.sa(),
exponent: Self::ambiguous_exponent(),
}
} else if sign != 0 {
Self::EXPLODED_NEG
} else {
Self::EXPLODED_POS
};
}
if raw_exp == 0 && mantissa == 0 {
return Self::ZERO;
}
let abs_mantissa: u64 = if raw_exp == 0 {
mantissa
} else {
mantissa | (1 << 52)
};
let leading = abs_mantissa.leading_zeros() as isize;
let significant = 64isize.wrapping_sub(leading);
let eff_exp: i16 = if raw_exp == 0 { 1 } else { raw_exp };
let spirix_exp: i16 = eff_exp.wrapping_sub(1076).wrapping_add(significant as i16);
let shift = Self::fraction_bits().wrapping_sub(significant);
let fraction_pos: F = if shift < 0 {
(abs_mantissa >> shift.wrapping_neg()).as_()
} else {
let intermediate: F = abs_mantissa.as_();
intermediate << shift as usize
};
if Self::exponent_bits() == 8 {
if spirix_exp > E::max_value().saturate::<i16>() {
if sign != 0
&& spirix_exp == E::max_value().saturate::<i16>() + 1
&& fraction_pos == Self::pos_one_normal()
{
return Self {
fraction: Self::neg_one_normal(),
exponent: E::max_value() ^ E::min_value(),
};
}
return Self {
fraction: if sign != 0 {
Self::neg_one_exploded()
} else {
Self::pos_one_exploded()
},
exponent: Self::ambiguous_exponent(),
};
} else if spirix_exp < -(E::max_value().saturate::<i16>()) {
return Self {
fraction: if sign != 0 {
Self::neg_one_vanished()
} else {
Self::pos_one_vanished()
},
exponent: Self::ambiguous_exponent(),
};
}
}
if sign == 0 {
return Self {
fraction: fraction_pos,
exponent: {
let v: E = spirix_exp.as_();
v ^ E::min_value()
},
};
}
if fraction_pos == Self::pos_one_normal() {
Self {
fraction: Self::neg_one_normal(),
exponent: {
let v: E = (spirix_exp.wrapping_sub(1)).as_();
v ^ E::min_value()
},
}
} else {
Self {
fraction: F::zero() - fraction_pos,
exponent: {
let v: E = spirix_exp.as_();
v ^ E::min_value()
},
}
}
}
}
impl<F: Integer + FullInt, E: Integer + FullInt> From<f32> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary32: f32) -> Self {
Self::from(&binary32)
}
}
impl<F: Integer + FullInt, E: Integer + FullInt> From<&mut f32> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary32: &mut f32) -> Self {
Self::from(*binary32)
}
}
impl<F: Integer + FullInt, E: Integer + FullInt> From<&f32> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(binary32: &f32) -> Self {
let bits = binary32.to_bits();
let sign = bits >> 31;
let raw_exp = ((bits >> 23) & 0xFF) as i16;
let mantissa = bits & 0x7FFFFF;
if raw_exp == 0xFF {
return if mantissa != 0 {
Scalar {
fraction: GENERAL.prefix.sa(),
exponent: Self::ambiguous_exponent(),
}
} else if sign != 0 {
Self::EXPLODED_NEG
} else {
Self::EXPLODED_POS
};
}
if raw_exp == 0 && mantissa == 0 {
return Self::ZERO;
}
let abs_mantissa: u32 = if raw_exp == 0 {
mantissa
} else {
mantissa | (1 << 23)
};
let leading = abs_mantissa.leading_zeros() as isize;
let significant = 32isize.wrapping_sub(leading);
let eff_exp: i16 = if raw_exp == 0 { 1 } else { raw_exp as i16 };
let spirix_exp: i16 = eff_exp.wrapping_sub(151).wrapping_add(significant as i16);
let shift = Self::fraction_bits().wrapping_sub(significant);
let fraction_pos: F = if shift < 0 {
(abs_mantissa >> shift.wrapping_neg()).as_()
} else {
let intermediate: F = abs_mantissa.as_();
intermediate << shift as usize
};
if Self::exponent_bits() == 8 {
if spirix_exp > E::max_value().saturate::<i16>() {
if sign != 0
&& spirix_exp == E::max_value().saturate::<i16>() + 1
&& fraction_pos == Self::pos_one_normal()
{
return Self {
fraction: Self::neg_one_normal(),
exponent: E::max_value() ^ E::min_value(),
};
}
return Self {
fraction: if sign != 0 {
Self::neg_one_exploded()
} else {
Self::pos_one_exploded()
},
exponent: Self::ambiguous_exponent(),
};
} else if spirix_exp < -(E::max_value().saturate::<i16>()) {
return Self {
fraction: if sign != 0 {
Self::neg_one_vanished()
} else {
Self::pos_one_vanished()
},
exponent: Self::ambiguous_exponent(),
};
}
}
if sign == 0 {
return Self {
fraction: fraction_pos,
exponent: {
let v: E = spirix_exp.as_();
v ^ E::min_value()
},
};
}
if fraction_pos == Self::pos_one_normal() {
Self {
fraction: Self::neg_one_normal(),
exponent: {
let v: E = (spirix_exp.wrapping_sub(1)).as_();
v ^ E::min_value()
},
}
} else {
Self {
fraction: F::zero() - fraction_pos,
exponent: {
let v: E = spirix_exp.as_();
v ^ E::min_value()
},
}
}
}
}
macro_rules! impl_from_int {
($($i:ty),*) => {
$(
impl<F: Integer+FullInt, E: Integer+FullInt> From<$i> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: $i) -> Self {
if value == 0 {
return Self::ZERO;
}
let negative = value < 0;
let abs_value = if value == <$i>::MIN {
let bits = (core::mem::size_of::<$i>() as isize).wrapping_shl(3);
if bits > E::max_value().saturate::<isize>() {
return Self {
fraction: Self::neg_one_exploded(),
exponent: Self::ambiguous_exponent(),
};
}
return Self {
fraction: Self::neg_one_normal(),
exponent: { let v: E = bits.wrapping_sub(2).as_(); v ^ E::min_value() },
};
} else if negative {
value.wrapping_neg()
} else {
value
};
let leading = abs_value.leading_zeros() as isize;
let significant_bits = (core::mem::size_of::<$i>() as isize).wrapping_shl(3).wrapping_sub(leading);
let spirix_exp: isize = significant_bits.wrapping_sub(1);
if spirix_exp > E::max_value().saturate::<isize>() {
return Self {
fraction: if negative { Self::neg_one_exploded() } else { Self::pos_one_exploded() },
exponent: Self::ambiguous_exponent(),
};
}
let shift = (Self::fraction_bits() as isize).wrapping_sub(significant_bits);
let fraction_pos: F = if shift < 0 {
(abs_value >> shift.wrapping_neg()).as_()
} else {
let intermediate: F = abs_value.as_();
intermediate << shift as usize
};
if !negative {
return Self { fraction: fraction_pos, exponent: { let v: E = spirix_exp.as_(); v ^ E::min_value() } };
}
if fraction_pos == Self::pos_one_normal() {
Self {
fraction: Self::neg_one_normal(),
exponent: { let v: E = spirix_exp.wrapping_sub(1).as_(); v ^ E::min_value() },
}
} else {
Self {
fraction: F::zero() - fraction_pos,
exponent: { let v: E = spirix_exp.as_(); v ^ E::min_value() },
}
}
}
}
impl<F: Integer+FullInt, E: Integer+FullInt> From<&mut $i> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: &mut $i) -> Self {
Self::from(*value)
}
}
impl<F: Integer+FullInt, E: Integer+FullInt> From<&$i> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: &$i) -> Self {
Self::from(*value)
}
}
)*
}
}
impl_from_int!(i8, i16, i32, i64, i128, isize);
macro_rules! impl_from_uint {
($($u:ty),*) => {
$(
impl<F: Integer+FullInt, E: Integer+FullInt> From<$u> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: $u) -> Self {
if value == 0 {
return Self::ZERO;
}
let leading = value.leading_zeros() as isize;
let significant_bits = (core::mem::size_of::<$u>() as isize).wrapping_shl(3).wrapping_sub(leading);
let spirix_exp: isize = significant_bits.wrapping_sub(1);
if spirix_exp > E::max_value().saturate::<isize>() {
return Self {
fraction: Self::pos_one_exploded(),
exponent: Self::ambiguous_exponent(),
};
}
let shift = (Self::fraction_bits() as isize).wrapping_sub(significant_bits);
let fraction: F = if shift < 0 {
(value >> shift.wrapping_neg()).as_()
} else {
let intermediate: F = value.as_();
intermediate << shift as usize
};
Self { fraction, exponent: { let v: E = spirix_exp.as_(); v ^ E::min_value() } }
}
}
impl<F: Integer+FullInt, E: Integer+FullInt> From<&mut $u> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: &mut $u) -> Self {
Self::from(*value)
}
}
impl<F: Integer+FullInt, E: Integer+FullInt> From<&$u> for Scalar<F, E>
where
Scalar<F, E>: ScalarConstants,
u8: AsPrimitive<F>,
u16: AsPrimitive<F>,
u32: AsPrimitive<F>,
u64: AsPrimitive<F>,
u128: AsPrimitive<F>,
usize: AsPrimitive<F>,
i8: AsPrimitive<F>,
i16: AsPrimitive<F>,
i32: AsPrimitive<F>,
i64: AsPrimitive<F>,
i128: AsPrimitive<F>,
isize: AsPrimitive<F>,
u8: AsPrimitive<E>,
u16: AsPrimitive<E>,
u32: AsPrimitive<E>,
u64: AsPrimitive<E>,
u128: AsPrimitive<E>,
usize: AsPrimitive<E>,
i8: AsPrimitive<E>,
i16: AsPrimitive<E>,
i32: AsPrimitive<E>,
i64: AsPrimitive<E>,
i128: AsPrimitive<E>,
isize: AsPrimitive<E>,
{
fn from(value: &$u) -> Self {
Self::from(*value)
}
}
)*
}
}
impl_from_uint!(u8, u16, u32, u64, u128, usize);
impl Scalar<i16, i16> {
#[inline(always)]
pub const fn from_f32(v: f32) -> Self {
let bits = v.to_bits();
let sign = bits >> 31;
let raw_exp = ((bits >> 23) & 0xFF) as i16;
let mantissa = bits & 0x7F_FFFF;
if raw_exp == 0xFF {
if mantissa != 0 {
return Scalar {
fraction: 0xE000u16 as i16,
exponent: 0,
};
}
return if sign != 0 {
Scalar {
fraction: i16::MIN,
exponent: 0,
}
} else {
Scalar {
fraction: -(i16::MIN >> 1),
exponent: 0,
}
};
}
if raw_exp == 0 && mantissa == 0 {
return Scalar {
fraction: 0,
exponent: 0,
};
}
let abs_mantissa: u32 = if raw_exp == 0 {
mantissa
} else {
mantissa | 0x80_0000
};
let leading = abs_mantissa.leading_zeros() as i16;
let significant: i16 = 32 - leading;
let eff_exp = if raw_exp == 0 { 1 } else { raw_exp };
let spirix_exp: i16 = eff_exp - 151 + significant;
let shift = 16 - significant;
let fraction_pos: i16 = if shift < 0 {
(abs_mantissa >> ((-shift) as u32)) as i16
} else {
(abs_mantissa as i16).wrapping_shl(shift as u32)
};
if sign == 0 {
return Scalar {
fraction: fraction_pos,
exponent: spirix_exp ^ i16::MIN,
};
}
if fraction_pos == i16::MIN {
return Scalar {
fraction: 0,
exponent: (spirix_exp - 1) ^ i16::MIN,
};
}
Scalar {
fraction: -fraction_pos,
exponent: spirix_exp ^ i16::MIN,
}
}
}
#[cfg(test)]
mod tests_from_f32 {
use crate::ScalarF4E4;
#[test]
fn from_f32_matches_runtime() {
let cases: &[f32] = &[
1.0, -1.0, 0.5, -0.5, 0.0031308, 12.92, 1.055, 0.055, 255.0, 0.00390625, 3.14159265,
0.1, 100.0, -42.75,
];
for &v in cases {
let runtime = ScalarF4E4::from(v);
let compile = ScalarF4E4::from_f32(v);
assert_eq!(
compile.fraction, runtime.fraction,
"fraction mismatch for {v}: from_f32={} from={}",
compile.fraction, runtime.fraction
);
assert_eq!(
compile.exponent, runtime.exponent,
"exponent mismatch for {v}: from_f32={} from={}",
compile.exponent, runtime.exponent
);
}
}
#[test]
fn from_f32_is_const() {
const K: ScalarF4E4 = ScalarF4E4::from_f32(0.0031308);
const ONE: ScalarF4E4 = ScalarF4E4::from_f32(1.0);
assert_eq!(ONE, ScalarF4E4::ONE);
let _ = K;
}
}