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}