use crate::math::{self, Signed, Unsigned};
#[inline(always)]
const fn add_sign_word(float: f32, sign: i32) -> f32 {
f32::from_bits(float.to_bits() | (Unsigned(sign).reinterpret() << 31))
}
#[inline(always)]
const fn nonzero_u32_to_f32(fraction: u32) -> f32 {
let leading_zeros = fraction.leading_zeros() + 1;
let fraction = fraction.wrapping_shl(leading_zeros);
let fraction = fraction >> 9;
let exponent = (127 - leading_zeros) << 23;
f32::from_bits(exponent | fraction)
* f32::from_bits(0b111111100000000000000000000001)
}
#[inline(always)]
const fn normal_f32_to_u32(float: f32) -> u32 {
let float =
(float * f32::from_bits(0b111111011111111111111111111111)).to_bits();
let fraction = (float << 9) >> 1;
let fraction = (1 << 31) | fraction | (fraction >> 23);
let exponent =
Unsigned(127 - Signed(float >> 23).reinterpret()).reinterpret();
let (fraction, overflow) = fraction.overflowing_shr(exponent - 1);
let nonzero = Unsigned(-math::word(!overflow)).reinterpret();
fraction & nonzero
}
#[inline(always)]
const fn normal_f32_to_i32(float: f32) -> i32 {
let magnitude = Signed(normal_f32_to_u32(float.abs()) >> 1).reinterpret();
let offset = -math::word(float.is_sign_negative());
let sign = (offset * 2) + 1;
offset + (magnitude * sign)
}
pub const fn u32_to_f32(fraction: u32) -> f32 {
let nonzero = Unsigned(-math::word(fraction != 0)).reinterpret();
f32::from_bits(nonzero_u32_to_f32(fraction).to_bits() & nonzero)
}
pub const fn i32_to_f32(int: i32) -> f32 {
let sign = -math::word(int < 0);
let uint = int.abs_diff(sign);
let uint = (uint * 2) + 1;
add_sign_word(nonzero_u32_to_f32(uint), sign)
}
#[inline(always)]
pub const fn f32_to_u32(float: f32) -> u32 {
let float = math::normalize_f32(float).clamp(0.0, 1.0);
normal_f32_to_u32(float)
}
#[inline(always)]
pub const fn f32_to_i32(float: f32) -> i32 {
let float = math::normalize_f32(float).clamp(-1.0, 1.0);
normal_f32_to_i32(float)
}
#[inline(always)]
pub const fn u32_to_i32(fraction: u32) -> i32 {
Signed(fraction).reinterpret_with_offset()
}
#[inline(always)]
pub const fn i32_to_u32(fraction: i32) -> u32 {
Unsigned(fraction).reinterpret_with_offset()
}
#[inline(always)]
pub const fn u64_to_i64(fraction: u64) -> i64 {
Signed(fraction).reinterpret_with_offset()
}
#[inline(always)]
pub const fn i64_to_u64(fraction: i64) -> u64 {
Unsigned(fraction).reinterpret_with_offset()
}
#[inline(always)]
const fn add_sign_long(float: f64, sign: i64) -> f64 {
f64::from_bits(float.to_bits() | (Unsigned(sign).reinterpret() << 63))
}
#[inline(always)]
const fn nonzero_u64_to_f64(fraction: u64) -> f64 {
let leading_zeros = fraction.leading_zeros() + 1;
let fraction = fraction.wrapping_shl(leading_zeros);
let fraction = fraction >> 12;
let exponent = (1023 - (leading_zeros as u64)) << 52;
f64::from_bits(exponent | fraction)
* f64::from_bits(
0b11111111110000000000000000000000000000000000000000000000000001,
)
}
#[inline(always)]
const fn normal_f64_to_u64(float: f64) -> u64 {
let float = (float
* f64::from_bits(
0b11111111101111111111111111111111111111111111111111111111111111,
))
.to_bits();
let fraction = (float << 12) >> 1;
let fraction = (1 << 63) | fraction | (fraction >> 52);
let exponent = Unsigned(1023 - Signed((float >> 52) as u32).reinterpret())
.reinterpret();
let (fraction, overflow) = fraction.overflowing_shr(exponent - 1);
let nonzero = Unsigned(-math::long(!overflow)).reinterpret();
fraction & nonzero
}
#[inline(always)]
const fn normal_f64_to_i64(float: f64) -> i64 {
let magnitude = Signed(normal_f64_to_u64(float.abs()) >> 1).reinterpret();
let offset = -math::long(float.is_sign_negative());
let sign = (offset * 2) + 1;
offset + (magnitude * sign)
}
pub const fn u64_to_f64(fraction: u64) -> f64 {
let nonzero = Unsigned(-math::long(fraction != 0)).reinterpret();
f64::from_bits(nonzero_u64_to_f64(fraction).to_bits() & nonzero)
}
pub const fn i64_to_f64(int: i64) -> f64 {
let sign = -math::long(int < 0);
let uint = int.abs_diff(sign);
let uint = (uint * 2) + 1;
add_sign_long(nonzero_u64_to_f64(uint), sign)
}
#[inline(always)]
pub const fn f64_to_u64(float: f64) -> u64 {
let float = math::normalize_f64(float).clamp(0.0, 1.0);
normal_f64_to_u64(float)
}
#[inline(always)]
pub const fn f64_to_i64(float: f64) -> i64 {
let float = math::normalize_f64(float).clamp(-1.0, 1.0);
normal_f64_to_i64(float)
}