Skip to main content

zenith_float_num/
radix_float.rs

1//! Arbitrary-radix float wrapper around [`ExactNum`].
2//!
3//! Arithmetic uses the binary [`ExactNum`] kernel; the radix affects parse/format only.
4
5use crate::defs::Error;
6use crate::ext::ExactNum;
7use crate::Consts;
8use crate::Radix;
9use crate::RoundingMode;
10use core::ops::{Deref, DerefMut};
11
12#[cfg(not(feature = "std"))]
13use alloc::string::String;
14
15/// A floating-point value with an associated parse/format radix.
16#[derive(Debug, Clone)]
17pub struct RadixFloat {
18    value: ExactNum,
19    radix: Radix,
20}
21
22impl RadixFloat {
23    /// Wraps `value` with radix `radix`.
24    ///
25    /// ## Errors
26    ///
27    ///  - InvalidArgument: `radix` is outside 2..=36.
28    pub fn new(value: ExactNum, radix: Radix) -> Result<Self, Error> {
29        let _ = Radix::try_new(radix.value())?;
30        Ok(Self { value, radix })
31    }
32
33    /// Wraps `value` with `radix` without validating the radix (for const radix constants).
34    pub fn with_radix(value: ExactNum, radix: Radix) -> Self {
35        Self { value, radix }
36    }
37
38    /// Returns the numeric value.
39    pub fn value(&self) -> &ExactNum {
40        &self.value
41    }
42
43    /// Returns the associated radix.
44    pub const fn radix(&self) -> Radix {
45        self.radix
46    }
47
48    /// Consumes `self` and returns the inner [`ExactNum`].
49    pub fn into_inner(self) -> ExactNum {
50        self.value
51    }
52
53    /// Parses `s` in `radix`.
54    pub fn parse(
55        s: &str,
56        radix: Radix,
57        p: usize,
58        rm: RoundingMode,
59        cc: &mut Consts,
60    ) -> Result<Self, Error> {
61        Radix::try_new(radix.value())?;
62        Ok(Self {
63            value: ExactNum::parse(s, radix, p, rm, cc),
64            radix,
65        })
66    }
67
68    /// Formats using the associated radix.
69    pub fn format(&self, rm: RoundingMode, cc: &mut Consts) -> Result<String, Error> {
70        self.value.format(self.radix, rm, cc)
71    }
72}
73
74impl Deref for RadixFloat {
75    type Target = ExactNum;
76
77    fn deref(&self) -> &ExactNum {
78        &self.value
79    }
80}
81
82impl DerefMut for RadixFloat {
83    fn deref_mut(&mut self) -> &mut ExactNum {
84        &mut self.value
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_radix_float_roundtrip() {
94        let mut cc = Consts::new().unwrap();
95        let rdx = Radix::try_new(12).unwrap();
96        let p = 128;
97        let rm = RoundingMode::ToEven;
98        let n = ExactNum::parse("10.5", Radix::Dec, p, rm, &mut cc);
99        let rf = RadixFloat::with_radix(n.clone(), rdx);
100        let s = rf.format(rm, &mut cc).unwrap();
101        let g = RadixFloat::parse(&s, rdx, p, rm, &mut cc).unwrap();
102        assert_eq!(n.cmp(g.value()), Some(0));
103    }
104}