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> 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()}); } }