use super::num::*;
use super::rounding::*;
use super::shift::*;
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ExtendedFloat {
pub mant: u64,
pub exp: i32,
}
impl ExtendedFloat {
pub(crate) fn mul(&self, b: &ExtendedFloat) -> ExtendedFloat {
debug_assert!((self.mant & u64::HIMASK != 0) && (b.mant & u64::HIMASK != 0));
let ah = self.mant >> u64::HALF;
let al = self.mant & u64::LOMASK;
let bh = b.mant >> u64::HALF;
let bl = b.mant & u64::LOMASK;
let ah_bl = ah * bl;
let al_bh = al * bh;
let al_bl = al * bl;
let ah_bh = ah * bh;
let mut tmp = (ah_bl & u64::LOMASK) + (al_bh & u64::LOMASK) + (al_bl >> u64::HALF);
tmp += 1 << (u64::HALF-1);
ExtendedFloat {
mant: ah_bh + (ah_bl >> u64::HALF) + (al_bh >> u64::HALF) + (tmp >> u64::HALF),
exp: self.exp + b.exp + u64::FULL
}
}
#[inline]
pub(crate) fn imul(&mut self, b: &ExtendedFloat) {
*self = self.mul(b);
}
#[inline]
pub(crate) fn normalize(&mut self) -> u32 {
let shift = if self.mant == 0 { 0 } else { self.mant.leading_zeros() };
shl(self, shift as i32);
shift
}
#[inline]
pub(crate) fn round_to_native<F, Algorithm>(&mut self, algorithm: Algorithm)
where F: Float,
Algorithm: FnOnce(&mut ExtendedFloat, i32)
{
round_to_native::<F, _>(self, algorithm)
}
#[inline]
pub fn from_float<F: Float>(f: F) -> ExtendedFloat {
from_float(f)
}
#[inline]
pub(crate) fn into_float<F: Float>(mut self) -> F {
self.round_to_native::<F, _>(round_nearest_tie_even);
into_float(self)
}
#[inline]
pub(crate) fn into_downward_float<F: Float>(mut self) -> F {
self.round_to_native::<F, _>(round_downward);
into_float(self)
}
}
#[inline]
pub(crate) fn from_float<F>(f: F) -> ExtendedFloat
where F: Float
{
ExtendedFloat {
mant: u64::as_cast(f.mantissa()),
exp: f.exponent(),
}
}
#[inline]
pub(crate) fn into_float<F>(fp: ExtendedFloat) -> F
where F: Float
{
if fp.mant == 0 || fp.exp < F::DENORMAL_EXPONENT {
F::ZERO
} else if fp.exp >= F::MAX_EXPONENT {
F::from_bits(F::INFINITY_BITS)
} else {
let exp: u64;
if (fp.exp == F::DENORMAL_EXPONENT) && (fp.mant & F::HIDDEN_BIT_MASK.as_u64()) == 0 {
exp = 0;
} else {
exp = (fp.exp + F::EXPONENT_BIAS).as_u64();
}
let exp = exp << F::MANTISSA_SIZE;
let mant = fp.mant & F::MANTISSA_MASK.as_u64();
F::from_bits(F::Unsigned::as_cast(mant | exp))
}
}
#[cfg(test)]
mod tests {
use crate::lib::{f32, f64};
use super::*;
fn check_normalize(mant: u64, exp: i32, shift: u32, r_mant: u64, r_exp: i32) {
let mut x = ExtendedFloat {mant: mant, exp: exp};
assert_eq!(x.normalize(), shift);
assert_eq!(x, ExtendedFloat {mant: r_mant, exp: r_exp});
}
#[test]
fn normalize_test() {
check_normalize(0, 0, 0, 0, 0);
check_normalize(1, -149, 63, 9223372036854775808, -212);
check_normalize(71362, -149, 47, 10043308644012916736, -196);
check_normalize(12379400, -90, 40, 13611294244890214400, -130);
check_normalize(8388608, -23, 40, 9223372036854775808, -63);
check_normalize(11368684, 43, 40, 12500000250510966784, 3);
check_normalize(16777213, 104, 40, 18446740775174668288, 64);
check_normalize(1, -1074, 63, 9223372036854775808, -1137);
check_normalize(6448907850777164, -883, 11, 13207363278391631872, -894);
check_normalize(7371020360979573, -551, 11, 15095849699286165504, -562);
check_normalize(6427752177035961, -202, 11, 13164036458569648128, -213);
check_normalize(4903985730770844, -185, 11, 10043362776618688512, -196);
check_normalize(6646139978924579, -119, 11, 13611294676837537792, -130);
check_normalize(4503599627370496, -52, 11, 9223372036854775808, -63);
check_normalize(6103515625000000, 14, 11, 12500000000000000000, 3);
check_normalize(8271806125530277, 80, 11, 16940658945086007296, 69);
check_normalize(5503284107318959, 446, 11, 11270725851789228032, 435);
check_normalize(6290184345309700, 778, 11, 12882297539194265600, 767);
check_normalize(9007199254740991, 971, 11, 18446744073709549568, 960);
}
fn check_round_to_f32(mant: u64, exp: i32, r_mant: u64, r_exp: i32)
{
let mut x = ExtendedFloat {mant: mant, exp: exp};
x.round_to_native::<f32, _>(round_nearest_tie_even);
assert_eq!(x, ExtendedFloat {mant: r_mant, exp: r_exp});
}
#[test]
fn round_to_f32_test() {
check_round_to_f32(9223372036854775808, -213, 0, -149);
check_round_to_f32(9223372036854775808, -212, 1, -149);
check_round_to_f32(10043308644012916736, -196, 71362, -149);
check_round_to_f32(13611294244890214400, -130, 12379400, -90);
check_round_to_f32(9223372036854775808, -63, 8388608, -23);
check_round_to_f32(12500000250510966784, 3, 11368684, 43);
check_round_to_f32(18446740775174668288, 64, 16777213, 104);
check_round_to_f32(18446740775174668288, 65, 16777213, 105);
}
fn check_round_to_f64(mant: u64, exp: i32, r_mant: u64, r_exp: i32)
{
let mut x = ExtendedFloat {mant: mant, exp: exp};
x.round_to_native::<f64, _>(round_nearest_tie_even);
assert_eq!(x, ExtendedFloat {mant: r_mant, exp: r_exp});
}
#[test]
fn round_to_f64_test() {
check_round_to_f64(9223372036854775808, -1138, 0, -1074);
check_round_to_f64(9223372036854775808, -1137, 1, -1074);
check_round_to_f64(15095849699286165504, -562, 7371020360979573, -551);
check_round_to_f64(15095849699286165504, -562, 7371020360979573, -551);
check_round_to_f64(13164036458569648128, -213, 6427752177035961, -202);
check_round_to_f64(10043362776618688512, -196, 4903985730770844, -185);
check_round_to_f64(13611294676837537792, -130, 6646139978924579, -119);
check_round_to_f64(9223372036854775808, -63, 4503599627370496, -52);
check_round_to_f64(12500000000000000000, 3, 6103515625000000, 14);
check_round_to_f64(16940658945086007296, 69, 8271806125530277, 80);
check_round_to_f64(11270725851789228032, 435, 5503284107318959, 446);
check_round_to_f64(12882297539194265600, 767, 6290184345309700, 778);
check_round_to_f64(18446744073709549568, 960, 9007199254740991, 971);
check_round_to_f64(10234494226754558294, -1086, 2498655817078750, -1074)
}
fn assert_normalized_eq(mut x: ExtendedFloat, mut y: ExtendedFloat) {
x.normalize();
y.normalize();
assert_eq!(x, y);
}
#[test]
fn from_float() {
let values: [f32; 26] = [
1e-40,
2e-40,
1e-35,
2e-35,
1e-30,
2e-30,
1e-25,
2e-25,
1e-20,
2e-20,
1e-15,
2e-15,
1e-10,
2e-10,
1e-5,
2e-5,
1.0,
2.0,
1e5,
2e5,
1e10,
2e10,
1e15,
2e15,
1e20,
2e20,
];
for value in values.iter() {
assert_normalized_eq(ExtendedFloat::from_float(*value), ExtendedFloat::from_float(*value as f64));
}
}
const INTEGERS: [u64; 32] = [
0, 1, 7, 15, 112, 119, 127, 240, 247, 255, 2032, 2039, 2047, 4080, 4087, 4095, 65520, 65527, 65535, 1048560, 1048567, 1048575, 16777200, 16777207, 16777215, 268435440, 268435447, 268435455, 4294967280, 4294967287, 4294967295, 18446744073709551615, ];
#[test]
fn to_f32_test() {
let x = ExtendedFloat {mant: 9223372036854775808, exp: -213};
assert_eq!(x.into_float::<f32>(), 0.0);
let x = ExtendedFloat {mant: 9223372036854775808, exp: -212};
assert_eq!(x.into_float::<f32>(), 1e-45);
let x = ExtendedFloat {mant: 10043308644012916736, exp: -196};
assert_eq!(x.into_float::<f32>(), 1e-40);
let x = ExtendedFloat {mant: 13611294244890214400, exp: -130};
assert_eq!(x.into_float::<f32>(), 1e-20);
let x = ExtendedFloat {mant: 9223372036854775808, exp: -63};
assert_eq!(x.into_float::<f32>(), 1.0);
let x = ExtendedFloat {mant: 12500000250510966784, exp: 3};
assert_eq!(x.into_float::<f32>(), 1e20);
let x = ExtendedFloat {mant: 18446740775174668288, exp: 64};
assert_eq!(x.into_float::<f32>(), 3.402823e38);
let x = ExtendedFloat {mant: 1048575, exp: 108};
assert_eq!(x.into_float::<f32>(), 3.4028204e38);
let x = ExtendedFloat {mant: 16777216, exp: 104};
assert_eq!(x.into_float::<f32>(), f32::INFINITY);
let x = ExtendedFloat {mant: 1048576, exp: 108};
assert_eq!(x.into_float::<f32>(), f32::INFINITY);
let x = ExtendedFloat {mant: 16940658945086007296, exp: 69};
assert_eq!(x.into_float::<f32>(), f32::INFINITY);
for int in INTEGERS.iter() {
let fp = ExtendedFloat {mant: *int, exp: 0};
assert_eq!(fp.into_float::<f32>(), *int as f32, "{:?} as f32", *int);
}
}
#[test]
fn to_f64_test() {
let x = ExtendedFloat {mant: 9223372036854775808, exp: -1138};
assert_eq!(x.into_float::<f64>(), 0.0);
let x = ExtendedFloat {mant: 9223372036854775808, exp: -1137};
assert_eq!(x.into_float::<f64>(), 5e-324);
let x = ExtendedFloat {mant: 13207363278391631872, exp: -894};
assert_eq!(x.into_float::<f64>(), 1e-250);
let x = ExtendedFloat {mant: 15095849699286165504, exp: -562};
assert_eq!(x.into_float::<f64>(), 1e-150);
let x = ExtendedFloat {mant: 13164036458569648128, exp: -213};
assert_eq!(x.into_float::<f64>(), 1e-45);
let x = ExtendedFloat {mant: 10043362776618688512, exp: -196};
assert_eq!(x.into_float::<f64>(), 1e-40);
let x = ExtendedFloat {mant: 13611294676837537792, exp: -130};
assert_eq!(x.into_float::<f64>(), 1e-20);
let x = ExtendedFloat {mant: 9223372036854775808, exp: -63};
assert_eq!(x.into_float::<f64>(), 1.0);
let x = ExtendedFloat {mant: 12500000000000000000, exp: 3};
assert_eq!(x.into_float::<f64>(), 1e20);
let x = ExtendedFloat {mant: 16940658945086007296, exp: 69};
assert_eq!(x.into_float::<f64>(), 1e40);
let x = ExtendedFloat {mant: 11270725851789228032, exp: 435};
assert_eq!(x.into_float::<f64>(), 1e150);
let x = ExtendedFloat {mant: 12882297539194265600, exp: 767};
assert_eq!(x.into_float::<f64>(), 1e250);
let x = ExtendedFloat {mant: 9007199254740991, exp: 971};
assert_eq!(x.into_float::<f64>(), 1.7976931348623157e308);
let x = ExtendedFloat {mant: 18446744073709549568, exp: 960};
assert_eq!(x.into_float::<f64>(), 1.7976931348623157e308);
let x = ExtendedFloat {mant: 9007199254740992, exp: 971};
assert_eq!(x.into_float::<f64>(), f64::INFINITY);
let x = ExtendedFloat {mant: 18446744073709549568, exp: 961};
assert_eq!(x.into_float::<f64>(), f64::INFINITY);
let x = ExtendedFloat { exp: -1139, mant: 18446744073709550712 };
assert_eq!(x.into_float::<f64>(), 0.0);
let x = ExtendedFloat { exp: -1139, mant: 18446744073709551460 };
assert_eq!(x.into_float::<f64>(), 0.0);
let x = ExtendedFloat { exp: -1138, mant: 9223372036854776103 };
assert_eq!(x.into_float::<f64>(), 5e-324);
for int in INTEGERS.iter() {
let fp = ExtendedFloat {mant: *int, exp: 0};
assert_eq!(fp.into_float::<f64>(), *int as f64, "{:?} as f64", *int);
}
}
fn check_mul(a: ExtendedFloat, b: ExtendedFloat, c: ExtendedFloat) {
let r = a.mul(&b);
assert_eq!(r, c);
}
#[test]
fn mul_test() {
let a = ExtendedFloat {mant: 13164036458569648128, exp: -213};
let b = ExtendedFloat {mant: 9223372036854775808, exp: -62};
let c = ExtendedFloat {mant: 6582018229284824064, exp: -211};
check_mul(a, b, c);
let mut a = ExtendedFloat { mant: 10, exp: 0 };
let mut b = ExtendedFloat { mant: 10, exp: 0 };
a.normalize();
b.normalize();
assert_eq!(a.mul(&b).into_float::<f64>(), 100.0);
let a = ExtendedFloat { mant: 1 << 32, exp: -31 };
let b = ExtendedFloat { mant: 1 << 32, exp: -31 };
assert_eq!(a.mul(&b).into_float::<f64>(), 4.0);
let a = ExtendedFloat { mant: 10 << 31, exp: -31 };
let b = ExtendedFloat { mant: 10 << 31, exp: -31 };
assert_eq!(a.mul(&b).into_float::<f64>(), 100.0);
}
fn check_imul(mut a: ExtendedFloat, b: ExtendedFloat, c: ExtendedFloat) {
a.imul(&b);
assert_eq!(a, c);
}
#[test]
fn imul_test() {
let a = ExtendedFloat {mant: 13164036458569648128, exp: -213};
let b = ExtendedFloat {mant: 9223372036854775808, exp: -62};
let c = ExtendedFloat {mant: 6582018229284824064, exp: -211};
check_imul(a, b, c);
let mut a = ExtendedFloat { mant: 10, exp: 0 };
let mut b = ExtendedFloat { mant: 10, exp: 0 };
a.normalize();
b.normalize();
a.imul(&b);
assert_eq!(a.into_float::<f64>(), 100.0);
let mut a = ExtendedFloat { mant: 1 << 32, exp: -31 };
let b = ExtendedFloat { mant: 1 << 32, exp: -31 };
a.imul(&b);
assert_eq!(a.into_float::<f64>(), 4.0);
let mut a = ExtendedFloat { mant: 10 << 31, exp: -31 };
let b = ExtendedFloat { mant: 10 << 31, exp: -31 };
a.imul(&b);
assert_eq!(a.into_float::<f64>(), 100.0);
}
}