#![cfg(not(any(
all(feature = "asm", target_arch = "aarch64", target_feature = "fp16"),
all(feature = "asm", target_arch = "x86_64", target_feature = "f16c")
)))]
use crate::f16;
use casting::CastFrom;
const F16_INF: u16 = 0x7C00;
const F16_TO_F32_EXP: [u32; 32] = {
let mut table = [0u32; 32];
let mut i = 1u32;
while i < 31 {
table[i as usize] = (i + 112) << 23;
i += 1;
}
table[31] = 0x7F800000;
table
};
impl CastFrom<f16> for f32 {
#[inline]
fn cast_from(value: f16) -> f32 {
let bits = value.0 as u32;
let sign = (bits & 0x8000) << 16;
let exp = (bits >> 10) & 0x1F;
let mant = bits & 0x3FF;
if exp != 0 {
return f32::from_bits(sign | F16_TO_F32_EXP[exp as usize] | (mant << 13));
}
if mant == 0 {
return f32::from_bits(sign);
}
let shift = mant.leading_zeros() - 22;
let normalized_mant = ((mant << (shift + 1)) & 0x3FF) << 13;
let f32_exp = (113u32 - shift) << 23;
f32::from_bits(sign | f32_exp | normalized_mant)
}
}
impl CastFrom<f32> for f16 {
#[inline]
fn cast_from(value: f32) -> Self {
let bits = value.to_bits();
let sign = ((bits >> 16) & 0x8000) as u16;
let f32_exp = (bits >> 23) & 0xFF;
let f32_mant = bits & 0x7FFFFF;
if f32_exp == 0 {
return Self(sign);
}
if f32_exp == 255 {
return Self(sign | F16_INF | if f32_mant != 0 { 0x0200 } else { 0 });
}
let f16_exp = f32_exp as i32 - 112;
if f16_exp > 30 {
return Self(sign | F16_INF);
}
if f16_exp <= 0 {
let shift = (14 - f16_exp) as u32;
return if shift >= 24 {
Self(sign)
} else {
Self(sign | (((f32_mant | 0x800000) >> shift) as u16))
};
}
let mant = (f32_mant >> 13) as u16;
let round = ((f32_mant >> 12) & 1) as u16;
let rounded = mant + round;
if rounded < 0x400 {
Self(sign | ((f16_exp as u16) << 10) | rounded)
} else if f16_exp >= 30 {
Self(sign | F16_INF)
} else {
Self(sign | (((f16_exp + 1) as u16) << 10))
}
}
}