use u32;
use cmp::Ordering::{Less, Equal, Greater};
use ops::{Mul, Div, Neg};
use fmt::{Debug, LowerExp};
use mem::transmute;
use num::diy_float::Fp;
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
use num::Float;
use num::dec2flt::num::{self, Big};
use num::dec2flt::table;
#[derive(Copy, Clone, Debug)]
pub struct Unpacked {
pub sig: u64,
pub k: i16,
}
impl Unpacked {
pub fn new(sig: u64, k: i16) -> Self {
Unpacked { sig: sig, k: k }
}
}
pub trait RawFloat : Float + Copy + Debug + LowerExp
+ Mul<Output=Self> + Div<Output=Self> + Neg<Output=Self>
{
const INFINITY: Self;
const NAN: Self;
const ZERO: Self;
fn integer_decode(self) -> (u64, i16, i8);
fn transmute(self) -> u64;
fn from_bits(bits: u64) -> Self;
fn unpack(self) -> Unpacked;
fn from_int(x: u64) -> Self;
fn short_fast_pow10(e: usize) -> Self;
const CEIL_LOG5_OF_MAX_SIG: i16;
const MAX_NORMAL_DIGITS: usize;
const INF_CUTOFF: i64;
const ZERO_CUTOFF: i64;
const EXP_BITS: u8;
const SIG_BITS: u8;
const EXPLICIT_SIG_BITS: u8;
const MAX_EXP: i16;
const MIN_EXP: i16;
const MAX_EXP_INT: i16;
const MAX_ENCODED_EXP: i16;
const MIN_EXP_INT: i16;
const MAX_SIG: u64;
const MIN_SIG: u64;
}
macro_rules! other_constants {
($type: ident) => {
const EXPLICIT_SIG_BITS: u8 = Self::SIG_BITS - 1;
const MAX_EXP: i16 = (1 << (Self::EXP_BITS - 1)) - 1;
const MIN_EXP: i16 = -Self::MAX_EXP + 1;
const MAX_EXP_INT: i16 = Self::MAX_EXP - (Self::SIG_BITS as i16 - 1);
const MAX_ENCODED_EXP: i16 = (1 << Self::EXP_BITS) - 1;
const MIN_EXP_INT: i16 = Self::MIN_EXP - (Self::SIG_BITS as i16 - 1);
const MAX_SIG: u64 = (1 << Self::SIG_BITS) - 1;
const MIN_SIG: u64 = 1 << (Self::SIG_BITS - 1);
const INFINITY: Self = $crate::$type::INFINITY;
const NAN: Self = $crate::$type::NAN;
const ZERO: Self = 0.0;
}
}
impl RawFloat for f32 {
const SIG_BITS: u8 = 24;
const EXP_BITS: u8 = 8;
const CEIL_LOG5_OF_MAX_SIG: i16 = 11;
const MAX_NORMAL_DIGITS: usize = 35;
const INF_CUTOFF: i64 = 40;
const ZERO_CUTOFF: i64 = -48;
other_constants!(f32);
fn integer_decode(self) -> (u64, i16, i8) {
let bits: u32 = unsafe { transmute(self) };
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
let mantissa = if exponent == 0 {
(bits & 0x7fffff) << 1
} else {
(bits & 0x7fffff) | 0x800000
};
exponent -= 127 + 23;
(mantissa as u64, exponent, sign)
}
fn transmute(self) -> u64 {
let bits: u32 = unsafe { transmute(self) };
bits as u64
}
fn from_bits(bits: u64) -> f32 {
assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");
unsafe { transmute(bits as u32) }
}
fn unpack(self) -> Unpacked {
let (sig, exp, _sig) = self.integer_decode();
Unpacked::new(sig, exp)
}
fn from_int(x: u64) -> f32 {
debug_assert!(x as f32 == fp_to_float(Fp { f: x, e: 0 }));
x as f32
}
fn short_fast_pow10(e: usize) -> Self {
table::F32_SHORT_POWERS[e]
}
}
impl RawFloat for f64 {
const SIG_BITS: u8 = 53;
const EXP_BITS: u8 = 11;
const CEIL_LOG5_OF_MAX_SIG: i16 = 23;
const MAX_NORMAL_DIGITS: usize = 305;
const INF_CUTOFF: i64 = 310;
const ZERO_CUTOFF: i64 = -326;
other_constants!(f64);
fn integer_decode(self) -> (u64, i16, i8) {
let bits: u64 = unsafe { transmute(self) };
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
let mantissa = if exponent == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
exponent -= 1023 + 52;
(mantissa, exponent, sign)
}
fn transmute(self) -> u64 {
let bits: u64 = unsafe { transmute(self) };
bits
}
fn from_bits(bits: u64) -> f64 {
unsafe { transmute(bits) }
}
fn unpack(self) -> Unpacked {
let (sig, exp, _sig) = self.integer_decode();
Unpacked::new(sig, exp)
}
fn from_int(x: u64) -> f64 {
debug_assert!(x as f64 == fp_to_float(Fp { f: x, e: 0 }));
x as f64
}
fn short_fast_pow10(e: usize) -> Self {
table::F64_SHORT_POWERS[e]
}
}
pub fn fp_to_float<T: RawFloat>(x: Fp) -> T {
let x = x.normalize();
let e = x.e + 63;
if e > T::MAX_EXP {
panic!("fp_to_float: exponent {} too large", e)
} else if e > T::MIN_EXP {
encode_normal(round_normal::<T>(x))
} else {
panic!("fp_to_float: exponent {} too small", e)
}
}
pub fn round_normal<T: RawFloat>(x: Fp) -> Unpacked {
let excess = 64 - T::SIG_BITS as i16;
let half: u64 = 1 << (excess - 1);
let (q, rem) = (x.f >> excess, x.f & ((1 << excess) - 1));
assert_eq!(q << excess | rem, x.f);
let k = x.e + excess;
if rem < half {
Unpacked::new(q, k)
} else if rem == half && (q % 2) == 0 {
Unpacked::new(q, k)
} else if q == T::MAX_SIG {
Unpacked::new(T::MIN_SIG, k + 1)
} else {
Unpacked::new(q + 1, k)
}
}
pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
debug_assert!(T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG,
"encode_normal: significand not normalized");
let sig_enc = x.sig & !(1 << T::EXPLICIT_SIG_BITS);
let k_enc = x.k + T::MAX_EXP + T::EXPLICIT_SIG_BITS as i16;
debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP,
"encode_normal: exponent out of range");
let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc;
T::from_bits(bits)
}
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal");
T::from_bits(significand)
}
pub fn big_to_fp(f: &Big) -> Fp {
let end = f.bit_length();
assert!(end != 0, "big_to_fp: unexpectedly, input is zero");
let start = end.saturating_sub(64);
let leading = num::get_bits(f, start, end);
let e = start as i16;
let rounded_down = Fp { f: leading, e: e }.normalize();
match num::compare_with_half_ulp(f, start) {
Less => rounded_down,
Equal if leading % 2 == 0 => rounded_down,
Equal | Greater => match leading.checked_add(1) {
Some(f) => Fp { f: f, e: e }.normalize(),
None => Fp { f: 1 << 63, e: e + 1 },
}
}
}
pub fn prev_float<T: RawFloat>(x: T) -> T {
match x.classify() {
Infinite => panic!("prev_float: argument is infinite"),
Nan => panic!("prev_float: argument is NaN"),
Subnormal => panic!("prev_float: argument is subnormal"),
Zero => panic!("prev_float: argument is zero"),
Normal => {
let Unpacked { sig, k } = x.unpack();
if sig == T::MIN_SIG {
encode_normal(Unpacked::new(T::MAX_SIG, k - 1))
} else {
encode_normal(Unpacked::new(sig - 1, k))
}
}
}
}
pub fn next_float<T: RawFloat>(x: T) -> T {
match x.classify() {
Nan => panic!("next_float: argument is NaN"),
Infinite => T::INFINITY,
Zero | Subnormal | Normal => {
let bits: u64 = x.transmute();
T::from_bits(bits + 1)
}
}
}