diff --git a/Cargo.lock b/Cargo.lock index b090ae4..dd6d115 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,24 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + [[package]] name = "calc-math" version = "0.1.0" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/Cargo.toml b/Cargo.toml index 7863318..00e1e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +num-traits = { version = "0.2.19", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 9ff8e23..c9f0ee7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,14 @@ #![no_std] use core::{error::Error, fmt::Display}; +use num_traits::{one, zero, PrimInt, Unsigned}; #[derive(Debug, Clone, Copy)] -pub struct Decimal { +pub struct Decimal { pub minus: bool, pub significant: [u8; S], pub minus_exponent: bool, - pub exponent: u8, + pub exponent: E, } #[derive(Debug)] @@ -53,7 +54,7 @@ impl From for Float { } } -impl TryFrom for Decimal { +impl TryFrom for Decimal { type Error = DecimalError; fn try_from(val: Float) -> Result { @@ -65,12 +66,12 @@ impl TryFrom for Decimal { if minus { f *= -1.0; } - let mut exponent: u8 = 0; + let mut exponent: E = zero(); let minus_exponent = f < 1.0 && f > 0.0; while f > 10.0 { f /= 10.0; exponent = exponent - .checked_add(1u8) + .checked_add(&one()) .ok_or(DecimalError::ExponentOverflow)?; } while f < 1.0 { @@ -79,7 +80,7 @@ impl TryFrom for Decimal { } f *= 10.0; exponent = exponent - .checked_add(1u8) + .checked_add(&one()) .ok_or(DecimalError::ExponentOverflow)?; } let mut significant = [0; S]; @@ -183,7 +184,46 @@ mod tests { #[test] fn float_to_decimal_nan() { - let err = Decimal::<7>::try_from(Float::from(0.0 / 0.0)).unwrap_err(); + let err = Decimal::<7>::try_from(Float::from(f64::NAN)).unwrap_err(); assert!(matches!(err, DecimalError::NotANumber)); } + + #[test] + fn float_to_decimal_max() { + let dec = Decimal::<7>::try_from(Float::from(f64::MAX)).unwrap(); + assert!(!dec.minus); + assert_eq!(dec.significant, [1, 7, 9, 7, 6, 9, 3]); + assert!(!dec.minus_exponent); + assert_eq!(dec.exponent, 308) + } + + #[test] + fn float_to_decimal_max_overflow() { + let err = Decimal::<7, u8>::try_from(Float::from(f64::MAX)).unwrap_err(); + assert!(matches!(err, DecimalError::ExponentOverflow)); + } + + #[test] + fn float_to_decimal_min() { + let dec = Decimal::<7>::try_from(Float::from(f64::MIN)).unwrap(); + assert!(dec.minus); + assert_eq!(dec.significant, [1, 7, 9, 7, 6, 9, 3]); + assert!(!dec.minus_exponent); + assert_eq!(dec.exponent, 308) + } + + #[test] + fn float_to_decimal_min_overflow() { + let err = Decimal::<7, u8>::try_from(Float::from(f64::MIN)).unwrap_err(); + assert!(matches!(err, DecimalError::ExponentOverflow)); + } + + #[test] + fn float_to_decimal_epsilon() { + let dec = Decimal::<7>::try_from(Float::from(f64::EPSILON)).unwrap(); + assert!(!dec.minus); + assert_eq!(dec.significant, [2, 2, 2, 0, 4, 4, 6]); + assert!(dec.minus_exponent); + assert_eq!(dec.exponent, 16) + } }