use crate::f128;
use crate::f16;
use crate::quad::sw::{F128_ABS_MASK, F128_EXP_BIAS, F128_MANT_MASK};
use casting::CastFrom;
const F16_EXP_BIAS: i32 = 15;
const F16_INF: u16 = 0x7C00;
const EXP_BIAS_DIFF: i32 = F128_EXP_BIAS - F16_EXP_BIAS;
impl CastFrom<f128> for f16 {
#[inline]
fn cast_from(value: f128) -> f16 {
let bits = value.0;
let sign = (bits >> 127) as u16;
let exp = ((bits >> 112) & 0x7FFF) as i32;
let mant = bits & F128_MANT_MASK;
if bits & F128_ABS_MASK == 0 {
return f16::from_bits(sign << 15);
}
if exp == 0x7FFF {
return f16::from_bits((sign << 15) | if mant != 0 { 0x7E00 } else { F16_INF });
}
if exp == 0 {
return f16::from_bits(sign << 15);
}
let f16_exp = exp - EXP_BIAS_DIFF;
if f16_exp >= 0x1F {
return f16::from_bits((sign << 15) | F16_INF);
}
if f16_exp <= 0 {
return f16::from_bits(sign << 15);
}
let f16_mant = (mant >> 102) as u16;
let round_bit = ((mant >> 101) & 1) as u16;
let sticky = (mant & ((1u128 << 101) - 1)) != 0;
let do_round = round_bit & ((sticky as u16) | (f16_mant & 1));
let rounded = f16_mant + do_round;
if rounded < (1u16 << 10) {
f16::from_bits((sign << 15) | ((f16_exp as u16) << 10) | rounded)
} else {
let new_exp = f16_exp + 1;
if new_exp >= 0x1F {
f16::from_bits((sign << 15) | F16_INF)
} else {
f16::from_bits((sign << 15) | ((new_exp as u16) << 10))
}
}
}
}
impl CastFrom<f16> for f128 {
#[inline]
fn cast_from(value: f16) -> f128 {
const F128_INF_EXP: u128 = 0x7FFF;
let bits = value.to_bits();
let sign = (bits >> 15) as u128;
let exp = ((bits >> 10) & 0x1F) as i32;
let mant = bits & 0x3FF;
if exp == 0 {
return f128(sign << 127);
}
if exp == 0x1F {
let nan_payload = if mant != 0 { (mant as u128) << 102 } else { 0 };
return f128((sign << 127) | (F128_INF_EXP << 112) | nan_payload);
}
let f128_exp = (exp + EXP_BIAS_DIFF) as u128;
let f128_mant = (mant as u128) << 102;
f128((sign << 127) | (f128_exp << 112) | f128_mant)
}
}