From 65c7e3a0cf0cb2517903f8d84d0a0bce65841a68 Mon Sep 17 00:00:00 2001 From: Hexa Dust Date: Fri, 18 Jul 2025 21:19:30 +0100 Subject: [PATCH] Decimal to f64 --- src/lib.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d59e7e1..6f6a554 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,29 @@ #![no_std] use core::{error::Error, fmt::Display}; +#[cfg(not(test))] +use num_traits::float::FloatCore; 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: E, } +impl Default for Decimal { + fn default() -> Self { + Decimal { + minus: false, + significant: [0; S], + minus_exponent: false, + exponent: zero(), + } + } +} + #[derive(Debug)] pub enum DecimalError { ExponentOverflow, @@ -57,7 +70,7 @@ impl TryFrom for Decimal { } let mut significant = [0; S]; for i in 0..S { - let s = f as u8; //TODO: handle NaN etc. + let s = f as u8; f *= 10.0; f -= (s * 10) as f64; significant[i] = s; @@ -71,6 +84,39 @@ impl TryFrom for Decimal { } } +impl TryFrom> for f64 { + type Error = DecimalError; + + fn try_from(val: Decimal) -> Result { + let Decimal { + minus, + significant, + minus_exponent, + exponent, + } = val; + + let mut f: f64 = 0.0; + + let e = if minus_exponent { + 10.0f64.powi(-exponent.to_i32().ok_or(DecimalError::ExponentOverflow)?) + } else { + 10.0f64.powi(exponent.to_i32().ok_or(DecimalError::ExponentOverflow)?) + }; + + for i in (0..S).rev() { + f /= 10.0; + let s = significant[i]; + f += (s as f64) * e; + } + + if minus { + f *= -1.0; + } + + Ok(f) + } +} + #[cfg(test)] mod tests { use super::*; @@ -164,4 +210,52 @@ mod tests { assert!(dec.minus_exponent); assert_eq!(dec.exponent, 16) } + + #[test] + fn decimal_to_float_zero() { + let dec = Decimal::<5, u8>::default(); + assert_eq!(f64::try_from(dec).unwrap(), 0.0); + } + + #[test] + fn decimal_to_float_big() { + let mut dec = Decimal::<7, u8>::default(); + dec.significant = [1, 3, 3, 7, 4, 2, 0]; + dec.exponent = 3; + assert_eq!(f64::try_from(dec).unwrap(), 1337.42); + } + + #[test] + fn decimal_to_float_small() { + let mut dec = Decimal::<7, u8>::default(); + dec.significant = [1, 3, 3, 7, 4, 2, 0]; + dec.minus_exponent = true; + dec.exponent = 2; + assert_eq!(f64::try_from(dec).unwrap(), 0.0133742); + } + + #[test] + fn decimal_to_float_neg_big() { + let mut dec = Decimal::<7, u8>::default(); + dec.minus = true; + dec.significant = [1, 3, 3, 7, 4, 2, 0]; + dec.exponent = 3; + assert_eq!(f64::try_from(dec).unwrap(), -1337.42); + } + + #[test] + fn decimal_to_float_neg_small() { + let mut dec = Decimal::<7, u8>::default(); + dec.minus = true; + dec.significant = [1, 3, 3, 7, 4, 2, 0]; + dec.minus_exponent = true; + dec.exponent = 2; + assert_eq!(f64::try_from(dec).unwrap(), -0.0133742); + } + + // #[test] + // fn decimal_to_float_max() { + // let dec = Decimal::<16>::try_from(f64::MAX / 2.0).unwrap(); + // assert_eq!(f64::try_from(dec).unwrap(), f64::MAX / 2.0); + // } }