#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub const DECIMAL_PARTS: usize = 10;
pub const I64_MAX: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 8070, 4775, 3685, 3720, 9223],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: -(DECIMAL_POSITIONS as i8 - 19),
};
pub const I64_MIN: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 8080, 4775, 3685, 3720, 9223],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_NEG,
e: -(DECIMAL_POSITIONS as i8 - 19),
};
pub const U64_MAX: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 1615, 955, 737, 6744, 1844],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: -(DECIMAL_POSITIONS as i8 - 20),
};
pub const I128_MAX: BigFloatNum = BigFloatNum {
m: [7270, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: -1,
};
pub const I128_MIN: BigFloatNum = BigFloatNum {
m: [7280, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_NEG,
e: -1,
};
pub const U128_MAX: BigFloatNum = BigFloatNum {
m: [4550, 8211, 3176, 6074, 3374, 6346, 9384, 6920, 8236, 3402],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: -1,
};
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BigFloatNum {
pub(crate) sign: i8, pub(crate) e: i8, pub(crate) n: i16, pub(crate) m: [i16; DECIMAL_PARTS], }
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Error {
ExponentOverflow(i8),
DivisionByZero,
ArgumentIsNegative,
InvalidArgument,
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum RoundingMode {
Up,
Down,
ToZero,
FromZero,
ToEven,
ToOdd,
}
pub const DECIMAL_BASE_LOG10: usize = 4; pub const DECIMAL_POSITIONS: usize = DECIMAL_PARTS * DECIMAL_BASE_LOG10;
pub const DECIMAL_BASE: usize = 10000; pub const DECIMAL_SIGN_POS: i8 = 1; pub const DECIMAL_SIGN_NEG: i8 = -1; pub const DECIMAL_MIN_EXPONENT: i8 = -128; pub const DECIMAL_MAX_EXPONENT: i8 = 127; pub const ZEROED_MANTISSA: [i16; DECIMAL_PARTS] = [0; DECIMAL_PARTS];
pub const ZERO: BigFloatNum = BigFloatNum {
m: ZEROED_MANTISSA,
n: 0,
sign: DECIMAL_SIGN_POS,
e: 0,
};
pub const ONE: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: 1 - (DECIMAL_POSITIONS as i8),
};
pub const TWO: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 2000],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: 1 - (DECIMAL_POSITIONS as i8),
};
pub const E: BigFloatNum = BigFloatNum {
m: [7757, 6249, 3526, 7471, 6028, 2353, 9045, 2845, 2818, 2718],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: 1 - (DECIMAL_POSITIONS as i8),
};
pub const PI: BigFloatNum = BigFloatNum {
m: [4197, 288, 2795, 3383, 6264, 2384, 9793, 5358, 5926, 3141],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: 1 - (DECIMAL_POSITIONS as i8),
};
pub const MAX: BigFloatNum = BigFloatNum {
m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_POS,
e: DECIMAL_MAX_EXPONENT,
};
pub const MIN: BigFloatNum = BigFloatNum {
m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999],
n: DECIMAL_POSITIONS as i16,
sign: DECIMAL_SIGN_NEG,
e: DECIMAL_MAX_EXPONENT,
};
pub const MIN_POSITIVE: BigFloatNum = BigFloatNum {
m: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
n: 1,
sign: DECIMAL_SIGN_POS,
e: DECIMAL_MIN_EXPONENT,
};
pub const MIN_POSITIVE_NORMAL: BigFloatNum = BigFloatNum {
m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000],
n: 1,
sign: DECIMAL_SIGN_POS,
e: DECIMAL_MIN_EXPONENT,
};
impl BigFloatNum {
pub fn new() -> Self {
BigFloatNum {
sign: DECIMAL_SIGN_POS,
e: 0,
n: 0,
m: ZEROED_MANTISSA,
}
}
pub fn one() -> Self {
let mut val = Self::new();
val.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10;
val.n = DECIMAL_POSITIONS as i16;
val.e = 1 - DECIMAL_POSITIONS as i8;
val
}
pub fn from_bytes(bytes: &[u8], sign: i8, exponent: i8) -> BigFloatNum {
let mut mantissa = ZEROED_MANTISSA;
let mut n: usize = 0;
let mut p: i16 = 1;
let d = if bytes.len() > DECIMAL_POSITIONS { DECIMAL_POSITIONS } else { bytes.len() };
for i in 1..d + 1 {
mantissa[n] += (bytes[d - i] % 10) as i16 * p;
p *= 10;
if p == DECIMAL_BASE as i16 {
n += 1;
p = 1;
}
}
BigFloatNum {
sign: if sign >= 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG },
e: exponent,
n: Self::num_digits(&mantissa),
m: mantissa,
}
}
pub fn get_mantissa_bytes(&self, bytes: &mut [u8]) {
let mut n: usize = 0;
let mut p: i16 = 1;
let d = if bytes.len() < self.n as usize { bytes.len() } else { self.n as usize };
for i in 1..d + 1 {
bytes[d - i] = ((self.m[n] / p) % 10) as u8;
p *= 10;
if p == DECIMAL_BASE as i16 {
n += 1;
p = 1;
}
}
}
pub fn get_mantissa_len(&self) -> usize {
self.n as usize
}
pub fn is_zero(&self) -> bool {
self.n == 0
}
pub fn is_int_even(&self) -> bool {
let int = self.int();
if int.e < 0 {
let p = int.n + int.e as i16;
let mut d = int.m[p as usize / DECIMAL_BASE_LOG10];
let mut i = p % DECIMAL_BASE_LOG10 as i16;
while i > 0 {
d /= 10;
i -= 1;
}
d & 1 == 0
} else if int.e == 0 {
int.m[0] & 1 == 0
} else {
true
}
}
pub fn is_subnormal(&self) -> bool {
self.n < DECIMAL_POSITIONS as i16 && self.e == DECIMAL_MIN_EXPONENT
}
}