use std::{ ops, fmt, f32, f64 };
use std::convert::{TryFrom, Infallible};
use std::num::{FpCategory, TryFromIntError};
use crate::util::grisu2;
use crate::util::print_dec;
pub const NAN: Number = Number {
category: NAN_MASK,
mantissa: 0,
exponent: 0
};
const NEGATIVE: u8 = 0;
const POSITIVE: u8 = 1;
const NAN_MASK: u8 = !1;
#[derive(Copy, Clone, Debug)]
pub struct Number {
category: u8,
exponent: i16,
mantissa: u64,
}
impl Number {
#[inline]
pub unsafe fn from_parts_unchecked(positive: bool, mantissa: u64, exponent: i16) -> Self {
Number {
category: positive as u8,
exponent: exponent,
mantissa: mantissa,
}
}
#[inline]
pub fn from_parts(positive: bool, mut mantissa: u64, mut exponent: i16) -> Self {
while exponent < 0 && mantissa % 10 == 0 {
exponent += 1;
mantissa /= 10;
}
unsafe { Number::from_parts_unchecked(positive, mantissa, exponent) }
}
#[inline]
pub fn as_parts(&self) -> (bool, u64, i16) {
(self.category == POSITIVE, self.mantissa, self.exponent)
}
#[inline]
pub fn is_sign_positive(&self) -> bool {
self.category == POSITIVE
}
#[inline]
pub fn is_zero(&self) -> bool {
self.mantissa == 0 && !self.is_nan()
}
#[inline]
pub fn is_nan(&self) -> bool {
self.category & NAN_MASK != 0
}
#[inline]
pub fn is_empty(&self) -> bool {
self.mantissa == 0 || self.is_nan()
}
pub fn as_fixed_point_u64(&self, point: u16) -> Option<u64> {
if self.category != POSITIVE {
return None;
}
let e_diff = point as i16 + self.exponent;
Some(if e_diff == 0 {
self.mantissa
} else if e_diff < 0 {
self.mantissa.wrapping_div(decimal_power(-e_diff as u16))
} else {
self.mantissa.wrapping_mul(decimal_power(e_diff as u16))
})
}
pub fn as_fixed_point_i64(&self, point: u16) -> Option<i64> {
if self.is_nan() {
return None;
}
let num = if self.is_sign_positive() {
self.mantissa as i64
} else {
-(self.mantissa as i64)
};
let e_diff = point as i16 + self.exponent;
Some(if e_diff == 0 {
num
} else if e_diff < 0 {
num.wrapping_div(decimal_power(-e_diff as u16) as i64)
} else {
num.wrapping_mul(decimal_power(e_diff as u16) as i64)
})
}
}
impl PartialEq for Number {
#[inline]
fn eq(&self, other: &Number) -> bool {
if self.is_zero() && other.is_zero()
|| self.is_nan() && other.is_nan() {
return true;
}
if self.category != other.category {
return false;
}
let e_diff = self.exponent - other.exponent;
if e_diff == 0 {
return self.mantissa == other.mantissa;
} else if e_diff > 0 {
let power = decimal_power(e_diff as u16);
self.mantissa.wrapping_mul(power) == other.mantissa
} else {
let power = decimal_power(-e_diff as u16);
self.mantissa == other.mantissa.wrapping_mul(power)
}
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
if self.is_nan() {
return f.write_str("nan")
}
let (positive, mantissa, exponent) = self.as_parts();
let mut buf = Vec::new();
print_dec::write(&mut buf, positive, mantissa, exponent).unwrap();
f.write_str(&String::from_utf8_unchecked(buf))
}
}
}
fn exponentiate_f64(n: f64, e: i16) -> f64 {
static CACHE_POWERS: [f64; 23] = [
1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
];
if e >= 0 {
let index = e as usize;
n * if index < 23 {
CACHE_POWERS[index]
} else {
10f64.powf(index as f64)
}
} else {
let index = -e as usize;
n / if index < 23 {
CACHE_POWERS[index]
} else {
10f64.powf(index as f64)
}
}
}
fn exponentiate_f32(n: f32, e: i16) -> f32 {
static CACHE_POWERS: [f32; 23] = [
1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
];
if e >= 0 {
let index = e as usize;
n * if index < 23 {
CACHE_POWERS[index]
} else {
10f32.powf(index as f32)
}
} else {
let index = -e as usize;
n / if index < 23 {
CACHE_POWERS[index]
} else {
10f32.powf(index as f32)
}
}
}
impl From<Number> for f64 {
fn from(num: Number) -> f64 {
if num.is_nan() { return f64::NAN; }
let mut n = num.mantissa as f64;
let mut e = num.exponent;
if e < -308 {
n = exponentiate_f64(n, e + 308);
e = -308;
}
let f = exponentiate_f64(n, e);
if num.is_sign_positive() { f } else { -f }
}
}
impl From<Number> for f32 {
fn from(num: Number) -> f32 {
if num.is_nan() { return f32::NAN; }
let mut n = num.mantissa as f32;
let mut e = num.exponent;
if e < -127 {
n = exponentiate_f32(n, e + 127);
e = -127;
}
let f = exponentiate_f32(n, e);
if num.is_sign_positive() { f } else { -f }
}
}
impl From<f64> for Number {
fn from(float: f64) -> Number {
match float.classify() {
FpCategory::Infinite | FpCategory::Nan => return NAN,
_ => {}
}
if !float.is_sign_positive() {
let (mantissa, exponent) = grisu2::convert(-float);
Number::from_parts(false, mantissa, exponent)
} else {
let (mantissa, exponent) = grisu2::convert(float);
Number::from_parts(true, mantissa, exponent)
}
}
}
impl From<f32> for Number {
fn from(float: f32) -> Number {
match float.classify() {
FpCategory::Infinite | FpCategory::Nan => return NAN,
_ => {}
}
if !float.is_sign_positive() {
let (mantissa, exponent) = grisu2::convert(-float as f64);
Number::from_parts(false, mantissa, exponent)
} else {
let (mantissa, exponent) = grisu2::convert(float as f64);
Number::from_parts(true, mantissa, exponent)
}
}
}
impl PartialEq<f64> for Number {
fn eq(&self, other: &f64) -> bool {
f64::from(*self) == *other
}
}
impl PartialEq<f32> for Number {
fn eq(&self, other: &f32) -> bool {
f32::from(*self) == *other
}
}
impl PartialEq<Number> for f64 {
fn eq(&self, other: &Number) -> bool {
f64::from(*other) == *self
}
}
impl PartialEq<Number> for f32 {
fn eq(&self, other: &Number) -> bool {
f32::from(*other) == *self
}
}
#[derive(Clone, Copy)]
pub struct NumberOutOfScope;
impl From<Infallible> for NumberOutOfScope {
fn from(_: Infallible) -> NumberOutOfScope {
NumberOutOfScope
}
}
impl From<TryFromIntError> for NumberOutOfScope {
fn from(_: TryFromIntError) -> NumberOutOfScope {
NumberOutOfScope
}
}
macro_rules! impl_unsigned {
($( $t:ty ),*) => ($(
impl From<$t> for Number {
#[inline]
fn from(num: $t) -> Number {
Number {
category: POSITIVE,
exponent: 0,
mantissa: num as u64,
}
}
}
impl TryFrom<Number> for $t {
type Error = NumberOutOfScope;
fn try_from(num: Number) -> Result<Self, Self::Error> {
let (positive, mantissa, exponent) = num.as_parts();
if !positive || exponent != 0 {
return Err(NumberOutOfScope);
}
TryFrom::try_from(mantissa).map_err(Into::into)
}
}
impl_integer!($t);
)*)
}
macro_rules! impl_signed {
($( $t:ty ),*) => ($(
impl From<$t> for Number {
fn from(num: $t) -> Number {
if num < 0 {
Number {
category: NEGATIVE,
exponent: 0,
mantissa: -num as u64,
}
} else {
Number {
category: POSITIVE,
exponent: 0,
mantissa: num as u64,
}
}
}
}
impl TryFrom<Number> for $t {
type Error = NumberOutOfScope;
fn try_from(num: Number) -> Result<Self, Self::Error> {
let (positive, mantissa, exponent) = num.as_parts();
if exponent != 0 {
return Err(NumberOutOfScope);
}
let mantissa = if positive {
mantissa as i64
} else {
-(mantissa as i64)
};
TryFrom::try_from(mantissa).map_err(Into::into)
}
}
impl_integer!($t);
)*)
}
macro_rules! impl_integer {
($t:ty) => {
impl PartialEq<$t> for Number {
fn eq(&self, other: &$t) -> bool {
*self == Number::from(*other)
}
}
impl PartialEq<Number> for $t {
fn eq(&self, other: &Number) -> bool {
Number::from(*self) == *other
}
}
}
}
impl_signed!(isize, i8, i16, i32, i64);
impl_unsigned!(usize, u8, u16, u32, u64);
impl ops::Neg for Number {
type Output = Number;
#[inline]
fn neg(self) -> Number {
Number {
category: self.category ^ POSITIVE,
exponent: self.exponent,
mantissa: self.mantissa,
}
}
}
#[inline]
fn decimal_power(mut e: u16) -> u64 {
static CACHED: [u64; 20] = [
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
];
if e < 20 {
CACHED[e as usize]
} else {
let mut pow = 1u64;
while e >= 20 {
pow = pow.saturating_mul(CACHED[(e % 20) as usize]);
e /= 20;
}
pow
}
}