const CANONICAL_NAN_F32: u32 = 0x7fc0_0000;
const CANONICAL_NAN_F64: u64 = 0x7ff8_0000_0000_0000;
const NAN_BOX_MASK: u64 = 0xFFFF_FFFF_0000_0000;
#[inline]
pub const fn box_f32(f: f32) -> u64 {
(f.to_bits() as u64) | NAN_BOX_MASK
}
#[inline]
pub const fn box_f32_canon(f: f32) -> u64 {
let mut bits = f.to_bits();
if (bits & 0x7F80_0000) == 0x7F80_0000 && (bits & 0x007F_FFFF) != 0 {
bits = CANONICAL_NAN_F32;
}
(bits as u64) | NAN_BOX_MASK
}
#[inline]
pub const fn canonicalize_f64_bits(f: f64) -> u64 {
let mut bits = f.to_bits();
if (bits & 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000
&& (bits & 0x000F_FFFF_FFFF_FFFF) != 0
{
bits = CANONICAL_NAN_F64;
}
bits
}
#[inline]
pub const fn unbox_f32(val: u64) -> f32 {
if (val & NAN_BOX_MASK) == NAN_BOX_MASK {
f32::from_bits(val as u32)
} else {
f32::from_bits(CANONICAL_NAN_F32)
}
}
#[inline]
pub const fn fmin_f32(a: f32, b: f32) -> f32 {
match (a.is_nan(), b.is_nan()) {
(true, true) => f32::from_bits(CANONICAL_NAN_F32),
(true, false) => b,
(false, true) => a,
(false, false) => {
if a.to_bits() == 0x8000_0000 && b.to_bits() == 0x0000_0000 {
a } else if b.to_bits() == 0x8000_0000 && a.to_bits() == 0x0000_0000 {
b } else {
a.min(b)
}
}
}
}
#[inline]
pub const fn fmax_f32(a: f32, b: f32) -> f32 {
match (a.is_nan(), b.is_nan()) {
(true, true) => f32::from_bits(CANONICAL_NAN_F32),
(true, false) => b,
(false, true) => a,
(false, false) => {
if a.to_bits() == 0x0000_0000 && b.to_bits() == 0x8000_0000 {
a } else if b.to_bits() == 0x0000_0000 && a.to_bits() == 0x8000_0000 {
b } else {
a.max(b)
}
}
}
}
#[inline]
pub const fn fmin_f64(a: f64, b: f64) -> f64 {
match (a.is_nan(), b.is_nan()) {
(true, true) => f64::from_bits(CANONICAL_NAN_F64),
(true, false) => b,
(false, true) => a,
(false, false) => {
if a.to_bits() == 0x8000_0000_0000_0000 && b.to_bits() == 0x0000_0000_0000_0000 {
a
} else if b.to_bits() == 0x8000_0000_0000_0000 && a.to_bits() == 0x0000_0000_0000_0000 {
b
} else {
a.min(b)
}
}
}
}
#[inline]
pub const fn fmax_f64(a: f64, b: f64) -> f64 {
match (a.is_nan(), b.is_nan()) {
(true, true) => f64::from_bits(CANONICAL_NAN_F64),
(true, false) => b,
(false, true) => a,
(false, false) => {
if a.to_bits() == 0x0000_0000_0000_0000 && b.to_bits() == 0x8000_0000_0000_0000 {
a
} else if b.to_bits() == 0x0000_0000_0000_0000 && a.to_bits() == 0x8000_0000_0000_0000 {
b
} else {
a.max(b)
}
}
}
}
pub const fn is_snan_f32(f: f32) -> bool {
let bits = f.to_bits();
let exp = (bits >> 23) & 0xFF;
let mantissa = bits & 0x007F_FFFF;
let quiet_bit = bits & 0x0040_0000;
exp == 0xFF && mantissa != 0 && quiet_bit == 0
}
pub const fn is_snan_f64(f: f64) -> bool {
let bits = f.to_bits();
let exp = (bits >> 52) & 0x7FF;
let mantissa = bits & 0x000F_FFFF_FFFF_FFFF;
let quiet_bit = bits & 0x0008_0000_0000_0000;
exp == 0x7FF && mantissa != 0 && quiet_bit == 0
}