125 lines
2.7 KiB
Rust
125 lines
2.7 KiB
Rust
use super::{
|
|
StrInt,
|
|
StringInt,
|
|
PrimitiveInt,
|
|
PrimitiveIntValue
|
|
};
|
|
|
|
pub struct StrSigExp<'a> {
|
|
sig: StrInt<'a>,
|
|
exp: StrInt<'a>
|
|
}
|
|
|
|
impl<'a> StrSigExp<'a> {
|
|
#[inline]
|
|
pub fn from_parts(sig: StrInt<'a>, exp: StrInt<'a>) -> Self {
|
|
Self {
|
|
sig,
|
|
exp
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<StrSigExp<'a>> for SigExp {
|
|
fn from(raw: StrSigExp<'a>) -> SigExp {
|
|
let raw_exp_digits = raw.exp.digits();
|
|
|
|
if raw_exp_digits.len() <= I16_MAX_DIGITS {
|
|
raw_exp_digits
|
|
}
|
|
|
|
|
|
if let PrimitiveInt(sig) = PrimitiveInt::from_str_int(raw.sig) {
|
|
let raw_exp_digits = raw.exp.digits();
|
|
|
|
if raw_exp_digits.len() <= I16_MAX_DIGITS {
|
|
raw_exp_digits
|
|
}
|
|
|
|
if let PrimitiveInt(exp) = PrimitiveInt::from_str_int() {
|
|
SigExp::Fit {
|
|
sig,
|
|
exp
|
|
}
|
|
} else {
|
|
SigExp::Fat {
|
|
sig: raw.sig.to_string_int(),
|
|
exp: raw.sig.to_string_int()
|
|
}
|
|
}
|
|
} else {
|
|
SigExp::Massive {
|
|
sig: raw.sig.to_string_int(),
|
|
exp: raw.sig.to_string_int()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum SigExp {
|
|
/// When both `sig` AND `exp` can be
|
|
/// represented by fast primitive
|
|
/// types without loss of precision.
|
|
Fit {
|
|
sig: PrimitiveIntValue,
|
|
exp: i16
|
|
},
|
|
/// When `sig` can NOT be represented
|
|
/// by a fast primitive type
|
|
/// without loss of precision.
|
|
Fat {
|
|
sig: StringInt,
|
|
exp: i16
|
|
},
|
|
/// When both `sig` OR `exp` can NOT be
|
|
/// represented by fast primitive types
|
|
/// without loss of precision.
|
|
// #[feature(massive_sig_exp)]
|
|
Massive {
|
|
sig: StringInt,
|
|
exp: StringInt
|
|
}
|
|
}
|
|
|
|
impl SigExp {
|
|
// pub fn is_fit(&self) -> f64 {
|
|
|
|
// }
|
|
// pub fn map_approx_f64(&self) -> f64 {
|
|
// match self {
|
|
// SigExp::Fit { sig, exp } => {
|
|
|
|
// }
|
|
// }
|
|
// }
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_str_sig_exp_to_sig_exp_fit() {
|
|
let sig_str_int = StrInt::new("+1").unwrap();
|
|
let exp_str_int = StrInt::new("+1").unwrap();
|
|
let sig_exp = SigExp::from(StrSigExp::from_parts(sig_str_int, exp_str_int));
|
|
assert_eq!(sig_exp, SigExp::Fit{sig: 1, exp: 1});
|
|
}
|
|
|
|
#[test]
|
|
fn test_str_sig_exp_to_sig_exp_fat() {
|
|
let sig_str_int = StrInt::new("+10000000000000000000").unwrap();
|
|
let exp_str_int = StrInt::new("+1").unwrap();
|
|
let sig_exp = SigExp::from(StrSigExp::from_parts(sig_str_int, exp_str_int));
|
|
assert_eq!(sig_exp, SigExp::Fat{sig: sig_str_int.to_string_int(), exp: 1});
|
|
}
|
|
|
|
#[test]
|
|
fn test_str_sig_exp_to_sig_exp_massive() {
|
|
let sig_str_int = StrInt::new("+10000000000000000000").unwrap();
|
|
let exp_str_int = StrInt::new("+10000000000000000000").unwrap();
|
|
let sig_exp = SigExp::from(StrSigExp::from_parts(sig_str_int, exp_str_int));
|
|
assert_eq!(sig_exp, SigExp::Massive{sig: sig_str_int.to_string_int(), exp: exp_str_int.to_string_int()});
|
|
}
|
|
} |