Skip to main content

malachite_float/float/conversion/string/
from_string.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8//
9// The inverse of `to_string.rs`: reads back what `Float` and `ComparableFloat` write.
10//
11// A `ComparableFloat` writes a precision after a `#`, since the digits alone do not determine one
12// (`0xff.0#8` has three hex digits, or twelve bits, but a precision of 8). That suffix is what
13// makes the round trip exact, in every base. Without it the precision is inferred from the digits,
14// as `from_sci_string.rs` describes.
15
16use crate::float::conversion::string::from_sci_string::float_from_string_base;
17use crate::{ComparableFloat, Float};
18use core::str::FromStr;
19use malachite_base::num::conversion::traits::FromStringBase;
20
21impl FromStringBase for Float {
22    /// Converts a string, in a specified base, to a [`Float`].
23    ///
24    /// This reads back what [`Float`] and [`ComparableFloat`] write, so it is the inverse of
25    /// [`to_string_base`](malachite_base::num::conversion::traits::ToStringBase::to_string_base)
26    /// and of the formatting impls: an optional `-`, an optional base prefix (`0b`, `0o`, or `0x`,
27    /// which the `{:#b}`-style formats write and the plain ones omit), the digits, and optionally
28    /// `#` and a precision.
29    ///
30    /// The `#` suffix is what makes the round trip exact, because the digits alone do not determine
31    /// a precision: `0xff.0#8` has three hexadecimal digits, or twelve bits, but a precision of 8.
32    /// With the suffix the precision is exactly what it says; without it the precision is inferred
33    /// from the digits, which is coarse for short strings — see [`Float`]'s
34    /// [`FromSciString`](malachite_base::num::conversion::traits::FromSciString) impl for why.
35    /// Since the special values and zeros carry no precision, a `#` suffix on one of them is
36    /// rejected.
37    ///
38    /// Apart from the sign, the prefix, and the suffix, the grammar is the one described by
39    /// [`from_sci_string_with_options_prec`](Float::from_sci_string_with_options_prec). The value
40    /// is rounded to nearest.
41    ///
42    /// # Worst-case complexity
43    /// $T(n) = O(n (\log n)^2 \log\log n)$
44    ///
45    /// $M(n) = O(n \log n)$
46    ///
47    /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
48    ///
49    /// # Panics
50    /// Panics if `base` is less than 2 or greater than 36. This is checked before the string, so an
51    /// unparseable string does not mask an impossible base.
52    ///
53    /// # Examples
54    /// ```
55    /// use malachite_base::num::conversion::traits::FromStringBase;
56    /// use malachite_float::{ComparableFloat, Float};
57    ///
58    /// let s = |base, s| Float::from_string_base(base, s).map(|x| x.to_string());
59    ///
60    /// // With a `#` suffix the precision is exact, so this round-trips whatever the base.
61    /// assert_eq!(s(10, "1.5#10"), Some("1.5000".to_string()));
62    /// assert_eq!(s(16, "0xff.0#8"), Some("255.0".to_string()));
63    /// assert_eq!(s(8, "0o7.7#6"), Some("7.88".to_string()));
64    /// // The base prefix is optional, since `{:x}` omits it and `{:#x}` writes it.
65    /// assert_eq!(s(2, "0b1.01#3"), Some("1.2".to_string()));
66    /// assert_eq!(s(2, "1.01#3"), Some("1.2".to_string()));
67    ///
68    /// // Without the suffix the precision is inferred from the digits.
69    /// assert_eq!(s(10, "1.0"), Some("1.0".to_string()));
70    ///
71    /// // The specials and the zeros are spelled the same in every base and carry no precision, so
72    /// // a suffix on one is not something `ComparableFloat` wrote.
73    /// assert_eq!(s(16, "NaN"), Some("NaN".to_string()));
74    /// assert_eq!(s(16, "-0x0.0"), Some("-0.0".to_string()));
75    /// assert_eq!(s(10, "NaN#5"), None);
76    ///
77    /// // A precision of zero is not a `Float` precision.
78    /// assert_eq!(s(10, "1.0#0"), None);
79    /// assert_eq!(s(10, "abc"), None);
80    ///
81    /// // The round trip that the suffix exists for.
82    /// let x = Float::from(1.5);
83    /// let written = format!("{:#x}", ComparableFloat(x.clone()));
84    /// assert_eq!(written, "0x1.8#2");
85    /// assert_eq!(Float::from_string_base(16, &written).unwrap(), x);
86    /// ```
87    #[inline]
88    fn from_string_base(base: u8, s: &str) -> Option<Self> {
89        float_from_string_base(base, s)
90    }
91}
92
93impl FromStr for Float {
94    type Err = ();
95
96    /// Converts a string to a [`Float`].
97    ///
98    /// This is [`from_string_base`](Float::from_string_base) in base 10, so it reads what
99    /// [`Display`](std::fmt::Display) writes, and also accepts the `#` precision suffix that
100    /// [`ComparableFloat`]'s [`Display`](std::fmt::Display) adds. Without that suffix the precision
101    /// is inferred from the digits, so `Float::from_str(&x.to_string())` recovers the value of `x`
102    /// but not necessarily its precision; go through [`ComparableFloat`] for that.
103    ///
104    /// # Worst-case complexity
105    /// $T(n) = O(n (\log n)^2 \log\log n)$
106    ///
107    /// $M(n) = O(n \log n)$
108    ///
109    /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
110    ///
111    /// # Examples
112    /// ```
113    /// use malachite_float::Float;
114    /// use std::str::FromStr;
115    ///
116    /// assert_eq!(Float::from_str("1.5#10").unwrap().to_string(), "1.5000");
117    /// assert_eq!(Float::from_str("NaN").unwrap().to_string(), "NaN");
118    /// assert_eq!(
119    ///     Float::from_str("-Infinity").unwrap().to_string(),
120    ///     "-Infinity"
121    /// );
122    /// // Zero keeps its sign.
123    /// assert_eq!(Float::from_str("-0.0").unwrap().to_string(), "-0.0");
124    ///
125    /// assert!(Float::from_str("abc").is_err());
126    /// ```
127    #[inline]
128    fn from_str(s: &str) -> Result<Self, ()> {
129        float_from_string_base(10, s).ok_or(())
130    }
131}
132
133impl FromStr for ComparableFloat {
134    type Err = ();
135
136    /// Converts a string to a [`ComparableFloat`].
137    ///
138    /// This is [`Float`]'s [`FromStr`] with the result wrapped, so it accepts exactly the same
139    /// strings. It is the inverse of [`ComparableFloat`]'s [`Display`](std::fmt::Display), which
140    /// writes the `#` precision suffix: with that suffix the round trip preserves the precision as
141    /// well as the value, which is what makes two [`ComparableFloat`]s that were written and read
142    /// back compare equal.
143    ///
144    /// # Worst-case complexity
145    /// $T(n) = O(n (\log n)^2 \log\log n)$
146    ///
147    /// $M(n) = O(n \log n)$
148    ///
149    /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
150    ///
151    /// # Examples
152    /// ```
153    /// use malachite_float::{ComparableFloat, Float};
154    /// use std::str::FromStr;
155    ///
156    /// // The round trip preserves the precision, which comparing as `ComparableFloat`s requires.
157    /// let x = ComparableFloat(Float::from(1.5));
158    /// assert_eq!(x.to_string(), "1.5#2");
159    /// assert_eq!(ComparableFloat::from_str(&x.to_string()).unwrap(), x);
160    ///
161    /// // Without the suffix the precision is inferred, which here happens to agree.
162    /// assert_eq!(ComparableFloat::from_str("1.5").unwrap(), x);
163    ///
164    /// assert!(ComparableFloat::from_str("abc").is_err());
165    /// ```
166    #[inline]
167    fn from_str(s: &str) -> Result<Self, ()> {
168        float_from_string_base(10, s).map(ComparableFloat).ok_or(())
169    }
170}