use crate::{f256, U256};
const fn min(x: u32, y: u32) -> u32 {
x - x.saturating_sub(y)
}
trait Float: Copy + Clone {
const PREC_LEVEL: u32;
const TOTAL_BITS: u32 = 1_u32 << Self::PREC_LEVEL;
const EXP_BITS: u32 = 4 * Self::PREC_LEVEL - min(6, Self::PREC_LEVEL) - 7;
const FRACTION_BITS: u32 = Self::TOTAL_BITS - Self::EXP_BITS - 1;
const BIASED_EXP_MAX: u32 = (1_u32 << Self::EXP_BITS) - 1;
const EXP_BIAS_ADJ: u32 =
(Self::BIASED_EXP_MAX >> 1) + Self::FRACTION_BITS;
const FRACTION_MASK: u64 = (1_u64 << Self::FRACTION_BITS) - 1;
const FRACTION_BIAS: u64 = 1_u64 << Self::FRACTION_BITS;
const SIGN_SHIFT: u32 = Self::TOTAL_BITS - 1;
const SIGN_MASK: u64 = 1_u64 << Self::SIGN_SHIFT;
const ABS_MASK: u64 = !Self::SIGN_MASK;
const INF: u64 = (Self::BIASED_EXP_MAX as u64) << Self::FRACTION_BITS;
fn to_bits(self) -> u64;
}
impl Float for f32 {
const PREC_LEVEL: u32 = 5;
#[inline]
fn to_bits(self) -> u64 {
self.to_bits() as u64
}
}
impl Float for f64 {
const PREC_LEVEL: u32 = 6;
#[inline]
fn to_bits(self) -> u64 {
self.to_bits()
}
}
impl<F: Float> From<F> for f256 {
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_possible_truncation)]
fn from(f: F) -> Self {
let bits = f.to_bits();
let abs_bits = bits & F::ABS_MASK;
let sign = (bits >> F::SIGN_SHIFT) as u32;
if abs_bits >= F::FRACTION_BIAS && abs_bits < F::INF {
let exp = (abs_bits >> F::FRACTION_BITS as u64) as i32
- F::EXP_BIAS_ADJ as i32;
let significand = U256::new(
0,
((bits & F::FRACTION_MASK) | F::FRACTION_BIAS) as u128,
);
Self::encode(sign, exp, significand)
} else if abs_bits == 0 {
[Self::ZERO, Self::NEG_ZERO][sign as usize]
} else if abs_bits < F::FRACTION_BIAS {
Self::encode(
sign,
1 - F::EXP_BIAS_ADJ as i32,
U256::new(0, (bits & F::FRACTION_MASK) as u128),
)
} else if abs_bits == F::INF {
[Self::INFINITY, Self::NEG_INFINITY][sign as usize]
} else {
[Self::NAN, -Self::NAN][sign as usize]
}
}
}
#[cfg(test)]
mod from_f64_tests {
use super::*;
#[test]
fn test_nan() {
assert!(f256::from(f64::NAN).is_nan());
assert!(f256::from(-f64::NAN).is_nan());
}
#[test]
fn test_inf() {
assert_eq!(f256::from(f64::INFINITY), f256::INFINITY);
assert_eq!(f256::from(f64::NEG_INFINITY), f256::NEG_INFINITY);
}
#[test]
fn test_zero() {
assert_eq!(f256::from(0_f64), f256::ZERO);
assert_eq!(f256::from(-0_f64), f256::NEG_ZERO);
}
#[test]
fn test_normal_values() {
assert_eq!(f256::from(1_f64), f256::ONE);
assert_eq!(f256::from(-1_f64), f256::NEG_ONE);
assert_eq!(f256::from(2_f64), f256::TWO);
let x = f256::from(3.5_f64);
assert_eq!(x.as_sign_exp_signif(), (0, -1, (0, 7)));
let x = f256::from(-17.625_f64);
assert_eq!(x.as_sign_exp_signif(), (1, -3, (0, 141)));
let x = f256::from(0.0625_f64);
assert_eq!(x.as_sign_exp_signif(), (0, -4, (0, 1)));
let x = f256::from(109.04e-115_f64);
assert_eq!(x.as_sign_exp_signif(), (0, -428, (0, 7558297586173341)));
}
#[test]
fn test_subnormal_values() {
let x = f256::from(7.4e-317_f64);
assert_eq!(x.as_sign_exp_signif(), (0, -1074, (0, 14977767)));
let x = f256::from(-0.984e-312_f64);
assert_eq!(x.as_sign_exp_signif(), (1, -1073, (0, 99581908627)));
}
}
#[cfg(test)]
mod from_f32_tests {
use super::*;
#[test]
fn test_nan() {
assert!(f256::from(f32::NAN).is_nan());
assert!(f256::from(-f32::NAN).is_nan());
}
#[test]
fn test_inf() {
assert_eq!(f256::from(f32::INFINITY), f256::INFINITY);
assert_eq!(f256::from(f32::NEG_INFINITY), f256::NEG_INFINITY);
}
#[test]
fn test_zero() {
assert_eq!(f256::from(0_f32), f256::ZERO);
assert_eq!(f256::from(-0_f32), f256::NEG_ZERO);
}
#[test]
fn test_normal_values() {
assert_eq!(f256::from(1_f32), f256::ONE);
assert_eq!(f256::from(-1_f32), f256::NEG_ONE);
assert_eq!(f256::from(2_f32), f256::TWO);
let x = f256::from(3.5_f32);
assert_eq!(x.as_sign_exp_signif(), (0, -1, (0, 7)));
let x = f256::from(-17.625_f32);
assert_eq!(x.as_sign_exp_signif(), (1, -3, (0, 141)));
let x = f256::from(0.0625_f32);
assert_eq!(x.as_sign_exp_signif(), (0, -4, (0, 1)));
let x = f256::from(3.782e-38_f32);
assert_eq!(x.as_sign_exp_signif(), (0, -148, (0, 13494627)));
}
#[test]
fn test_subnormal_values() {
let x = f256::from(7.4e-317);
assert_eq!(x.as_sign_exp_signif(), (0, -1074, (0, 14977767)));
let x = f256::from(-0.984e-312);
assert_eq!(x.as_sign_exp_signif(), (1, -1073, (0, 99581908627)));
}
}