#[inline(always)]
pub fn exp(x: f32) -> f32 {
libm::expf(x)
}
#[inline(always)]
pub fn ln(x: f32) -> f32 {
libm::logf(x)
}
#[inline(always)]
pub fn sin(x: f32) -> f32 {
libm::sinf(x)
}
#[inline(always)]
pub fn cos(x: f32) -> f32 {
libm::cosf(x)
}
#[inline(always)]
pub fn sqrt(x: f32) -> f32 {
libm::sqrtf(x)
}
#[inline(always)]
pub fn tanh(x: f32) -> f32 {
libm::tanhf(x)
}
#[inline(always)]
pub fn powf(base: f32, exp: f32) -> f32 {
libm::powf(base, exp)
}
#[inline(always)]
pub fn round(x: f32) -> f32 {
libm::roundf(x)
}
#[inline(always)]
pub fn abs(x: f32) -> f32 {
libm::fabsf(x)
}
#[inline]
pub fn f16_to_f32(bits: u16) -> f32 {
let sign = ((bits >> 15) as u32) << 31;
let exp = ((bits >> 10) & 0x1F) as u32;
let mant = (bits & 0x3FF) as u32;
if exp == 0 {
let val = mant as f32 / (1u32 << 24) as f32;
return if sign != 0 { -val } else { val };
}
if exp == 31 {
return f32::from_bits(sign | 0x7F80_0000 | (mant << 13));
}
f32::from_bits(sign | ((exp + 127 - 15) << 23) | (mant << 13))
}
#[cfg(test)]
mod f16_tests {
use super::f16_to_f32;
#[test]
fn known_values() {
assert_eq!(f16_to_f32(0x0000), 0.0);
assert_eq!(f16_to_f32(0x8000), -0.0);
assert_eq!(f16_to_f32(0x3C00), 1.0);
assert_eq!(f16_to_f32(0xBC00), -1.0);
assert_eq!(f16_to_f32(0x4000), 2.0);
assert_eq!(f16_to_f32(0x3555), 0.33325195); assert_eq!(f16_to_f32(0x7BFF), 65504.0); assert_eq!(f16_to_f32(0x0001), 5.9604645e-8); assert_eq!(f16_to_f32(0x03FF), 6.0975552e-5); assert_eq!(f16_to_f32(0x0400), 6.1035156e-5); assert!(f16_to_f32(0x7C00).is_infinite() && f16_to_f32(0x7C00) > 0.0);
assert!(f16_to_f32(0xFC00).is_infinite() && f16_to_f32(0xFC00) < 0.0);
assert!(f16_to_f32(0x7E00).is_nan());
}
#[test]
fn every_finite_half_round_trips() {
for bits in 0u32..=0xFFFF {
let b = bits as u16;
let v = f16_to_f32(b);
if v.is_nan() {
continue;
}
let back = f32_to_f16_bits(v);
assert_eq!(back, b, "bits={b:#06x} value={v}");
}
}
fn f32_to_f16_bits(v: f32) -> u16 {
let x = v.to_bits();
let sign = ((x >> 31) as u16) << 15;
let exp = ((x >> 23) & 0xFF) as i32;
let mant = x & 0x7F_FFFF;
if exp == 0xFF {
return sign | 0x7C00 | ((mant >> 13) as u16);
}
let unbiased = exp - 127;
if unbiased < -24 {
return sign;
}
if unbiased < -14 {
let shift = (-14 - unbiased) as u32;
let m = (mant | 0x80_0000) >> (shift + 13);
return sign | m as u16;
}
if unbiased > 15 {
return sign | 0x7C00;
}
sign | (((unbiased + 15) as u16) << 10) | ((mant >> 13) as u16)
}
}