extern crate failure;
extern crate typenum;
use std::cmp::min;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::*;
use std::str::FromStr;
use typenum::consts::*;
use typenum::{Bit, Diff, Pow, Sum, UInt, Unsigned};
#[derive(Copy, Clone, Default)]
pub struct Xe<T, B = U10, V = u64>(V, T, B);
pub type Xe0<V = u64> = Xe<U0, U10, V>;
pub type Xe1<V = u64> = Xe<U1, U10, V>;
pub type Xe2<V = u64> = Xe<U2, U10, V>;
pub type Xe3<V = u64> = Xe<U3, U10, V>;
pub type Xe4<V = u64> = Xe<U4, U10, V>;
pub type Xe5<V = u64> = Xe<U5, U10, V>;
pub type Xe6<V = u64> = Xe<U6, U10, V>;
pub type Xe7<V = u64> = Xe<U7, U10, V>;
pub type Xe8<V = u64> = Xe<U8, U10, V>;
pub type Xe9<V = u64> = Xe<U9, U10, V>;
pub type Xe10<V = u64> = Xe<U10, U10, V>;
pub type Xe11<V = u64> = Xe<U11, U10, V>;
pub type Xe12<V = u64> = Xe<U12, U10, V>;
pub type Xe13<V = u64> = Xe<U13, U10, V>;
pub type Xe14<V = u64> = Xe<U14, U10, V>;
pub type Xe15<V = u64> = Xe<U15, U10, V>;
pub type XeN = Xe<u8, U10, u64>;
pub type XeNS = Xe<i8, U10, u64>;
impl<T, B> Xe<T, B> {
#[inline]
pub fn from_parts(n: u64, t: T) -> Self
where
B: Default,
{
Xe(n, t, B::default())
}
#[inline]
pub fn from_str_at_precision(s: &str, t: T) -> Result<Self, ()>
where
B: Default,
isize: From<T>,
T: Copy,
{
let sz = isize::from(t);
if sz >= 0 {
let x = u64::from_str_radix(s, 10).map_err(|_| ())?;
let x = x.checked_div(10u64.pow(sz as u32)).unwrap();
return Ok(Xe(x, t, B::default()));
}
let s = s.as_bytes();
let sz = -sz as usize;
if s.len() < sz + 2 {
return Err(());
}
let (ipart, fpart) = s.split_at(s.len() - 1 - sz);
let (dot, fpart) = fpart.split_first().unwrap();
if *dot != b'.' {
return Err(());
}
let mut x = 0u64;
for c in ipart.into_iter().cloned().chain(fpart.into_iter().cloned()) {
if c < b'0' || c > b'9' {
return Err(());
}
x *= 10;
x += u64::from(c - b'0');
}
Ok(Xe(x, t, B::default()))
}
#[inline]
pub fn from_quanta(n: u64) -> Self
where
T: Default,
B: Default,
{
Xe(n, T::default(), B::default())
}
#[inline]
pub fn from_u64(n: u64) -> Option<Self>
where
T: Default,
B: Default + Pow<T>,
<B as Pow<T>>::Output: Unsigned,
{
n.checked_mul(<B as Pow<T>>::Output::to_u64())
.map(Self::from_quanta)
}
#[inline]
pub fn from_f64(f: f64) -> Option<Self>
where
T: Default,
B: Default + Pow<T>,
<B as Pow<T>>::Output: Unsigned,
{
let f = f * (<B as Pow<T>>::Output::to_u64() as f64);
if f.fract() != 0.0 {
return None;
}
let n = f.trunc() as u64;
Some(Self::from_quanta(n))
}
#[inline]
pub fn truncated_div<T1, T2>(self, other: Xe<T1, B>) -> Xe<T2, B>
where
T1: Add<T2>,
T2: Default,
Sum<T1, T2>: Sub<T>,
Diff<Sum<T1, T2>, T>: Unsigned,
B: Unsigned,
{
let mut n = self.0;
let mut overflow = false;
for _ in 0..Diff::<Sum<T1, T2>, T>::USIZE {
let prev = n;
n *= B::U64;
overflow |= n < prev;
}
assert!(!overflow);
let n = n / other.0;
Xe(n, Default::default(), self.2)
}
#[inline]
pub fn truncated_mul<T1, T2>(self, other: Xe<T1, B>) -> Xe<T2, B>
where
T: Add<T1>,
T2: Default,
Sum<T, T1>: Sub<T2>,
Diff<Sum<T, T1>, T2>: Unsigned,
B: Unsigned,
{
let mut n = self.0.checked_mul(other.0).expect("overflow");
for _ in 0..Diff::<Sum<T, T1>, T2>::USIZE {
n /= B::U64;
}
Xe(n, Default::default(), self.2)
}
#[inline]
pub fn is_zero(self) -> bool
where
T: Add<T>,
T: PartialEq<<T as Add<T>>::Output>,
{
self.0 == self.0 + self.0
}
}
impl<T, B> Add for Xe<T, B> {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self::Output {
let n = self.0.checked_add(other.0).expect("overflow");
Xe(n, self.1, self.2)
}
}
impl<T, B> Sub for Xe<T, B> {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self::Output {
let n = self.0.checked_sub(other.0).expect("underflow");
Xe(n, self.1, self.2)
}
}
impl<T0, T1, B> Mul<Xe<T1, B>> for Xe<T0, B>
where
T0: Add<T1>,
{
type Output = Xe<<T0 as Add<T1>>::Output, B>;
#[inline]
fn mul(self, other: Xe<T1, B>) -> Self::Output {
let n = self.0.checked_mul(other.0).expect("overflow");
Xe(n, self.1 + other.1, self.2)
}
}
pub trait ToIsize {
fn to_isize(&self) -> isize;
}
impl<U, B> ToIsize for UInt<U, B>
where
U: Unsigned,
B: Bit,
{
fn to_isize(&self) -> isize {
<Self as Unsigned>::USIZE as isize
}
}
impl ToIsize for u8 {
fn to_isize(&self) -> isize {
isize::from(*self)
}
}
impl ToIsize for i8 {
fn to_isize(&self) -> isize {
isize::from(*self)
}
}
impl<T, U10> Display for Xe<T, U10>
where
T: ToIsize,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut s = [b'0'; 20];
let mut x = self.0;
let start = {
let mut inserter = s.iter_mut().rev();
for c in inserter.by_ref() {
*c = ((x % 10) as u32 + '0' as u32) as u8;
x /= 10;
if x == 0 {
break;
}
}
inserter.count()
};
let s = unsafe { std::str::from_utf8_unchecked(&s) };
let sz = self.1.to_isize();
if sz > 0 {
return write!(f, "{}e{}", &s[start..], sz);
}
let sz = -sz as usize;
let start = min(start, 19 - sz);
let (ipart, fpart) = s.split_at(20 - sz);
let ipart = &ipart[start..];
write!(f, "{}.{}", ipart, fpart)
}
}
#[derive(Copy, Clone)]
pub struct F64(pub f64);
impl Debug for F64 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use std::fmt::Write;
let n = self.0.to_bits();
let sgn = n & 0x8000_0000_0000_0000;
let exp = (n & 0x7ff0_0000_0000_0000) >> 52;
let mantis = n & 0x000f_ffff_ffff_ffff;
if sgn != 0 {
f.write_char('-')?;
}
let firstbit = if exp == 0x000 || exp == 0x7ff {
if exp == 0x7ff {
return if mantis == 0 {
f.write_str("Inf")
} else {
write!(f, "NaN({:013x})", mantis)
};
}
'0'
} else {
'1'
};
let exp = exp as i32 - 1023;
write!(f, "0x{}.{:013x}p{}", firstbit, mantis, exp)
}
}
impl<T, B> Debug for Xe<T, B>
where
T: Debug,
B: Debug,
Xe<T, B>: Display,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"{}\t=\tXe({:?}, {:?}, {:?})",
self, self.0, self.1, self.2,
)
}
}
impl<T> FromStr for Xe<T, U10>
where
T: Default + Unsigned,
{
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
let s = s.as_bytes();
if s.len() < T::USIZE + 2 {
return Err(());
}
let (ipart, fpart) = s.split_at(s.len() - T::USIZE - 1);
let (dot, fpart) = fpart.split_first().unwrap();
if *dot != b'.' {
return Err(());
}
let mut x = 0u64;
for c in ipart.into_iter().cloned().chain(fpart.into_iter().cloned()) {
if c < b'0' || c > b'9' {
return Err(());
}
x *= 10;
x += u64::from(c - b'0');
}
Ok(Xe::from_quanta(x))
}
}
impl<T, B> PartialEq for Xe<T, B> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T, B> Eq for Xe<T, B> {}
impl<T, B> PartialOrd for Xe<T, B> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<T, B> Ord for Xe<T, B> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
impl<T, B> PartialEq<f64> for Xe<T, B>
where
T: Default,
B: Default + Pow<T>,
<B as Pow<T>>::Output: Unsigned,
{
#[inline]
fn eq(&self, other: &f64) -> bool {
if let Some(other) = Self::from_f64(*other) {
self.eq(&other)
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
let a = Xe2::from_u64(2).unwrap();
let b = Xe::from_quanta(0_02);
let c: Xe2 = "2.02".parse().unwrap();
assert_eq!(a + b, c);
}
#[test]
fn test_mul() {
let a = Xe2::from_u64(2).unwrap();
let b: Xe1 = "0.2".parse().unwrap();
let c = Xe::from_quanta(0_400);
assert_eq!(a * b, c);
}
#[test]
fn test_mul2() {
let a = XeN::from_parts(2, 2);
let b = XeN::from_parts(2, 1);
let c = XeN::from_parts(4, 3);
assert_eq!(a * b, c);
}
#[test]
fn test_fsap() {
let _ = Xe::<i8>::from_str_at_precision("100", 2i8).unwrap();
let _ = Xe::<i8>::from_str_at_precision("1", 0i8).unwrap();
let z = Xe::<i8>::from_str_at_precision("0", 2i8).unwrap();
let _ = Xe::<i8>::from_str_at_precision("0.1", -1i8).unwrap();
let _ = Xe::<i8>::from_str_at_precision("0.01", -2i8).unwrap();
assert!(z.is_zero());
}
#[test]
fn test_bad_parses() {
let a: Result<Xe2, _> = "0.2".parse();
assert!(a.is_err());
let a: Result<Xe1, _> = "0.20".parse();
assert!(a.is_err());
let a: Result<Xe0, _> = ".1".parse();
assert!(a.is_err());
let a: Result<Xe1, _> = ".1".parse();
assert!(a.is_err());
let a: Result<Xe2, _> = ".1".parse();
assert!(a.is_err());
let a: Result<Xe0, _> = "1".parse();
assert!(a.is_err());
let a: Result<Xe1, _> = "1".parse();
assert!(a.is_err());
}
}