malachite_float/conversion/string/
to_string.rs1use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::alloc::string::ToString;
11use crate::{ComparableFloat, ComparableFloatRef, Float};
12use alloc::string::String;
13use core::fmt::{Debug, Display, Formatter, LowerHex, Result, Write};
14use malachite_base::num::arithmetic::traits::{
15 Abs, ModPowerOf2, RoundToMultipleOfPowerOf2, ShrRound,
16};
17use malachite_base::num::conversion::string::options::ToSciOptions;
18use malachite_base::num::conversion::traits::{ExactFrom, ToSci, WrappingFrom};
19use malachite_base::rounding_modes::RoundingMode::*;
20use malachite_q::Rational;
21
22fn replace_exponent_in_hex_string(s: &str, new_exponent: i32) -> String {
23 let exp_index = s.find('E').unwrap_or_else(|| panic!("{s}"));
24 let mut new_s = s[..exp_index].to_string();
25 if new_exponent > 0 {
26 write!(new_s, "E+{new_exponent}").unwrap();
27 } else {
28 write!(new_s, "E{new_exponent}").unwrap();
29 }
30 new_s
31}
32
33impl Display for Float {
34 fn fmt(&self, f: &mut Formatter) -> Result {
35 match self {
36 float_nan!() => write!(f, "NaN"),
37 float_infinity!() => write!(f, "Infinity"),
38 float_negative_infinity!() => write!(f, "-Infinity"),
39 float_zero!() => write!(f, "0.0"),
40 float_negative_zero!() => write!(f, "-0.0"),
41 _ => {
42 let exp = self.get_exponent().unwrap();
43 if exp.unsigned_abs() > 10000 {
44 if *self < 0u32 {
48 write!(f, "-")?;
49 }
50 return write!(f, "{}", if exp >= 0 { "too_big" } else { "too_small" });
51 }
52 let mut lower = self.clone();
53 let mut higher = self.clone();
54 lower.decrement();
55 higher.increment();
56 let self_q = Rational::exact_from(self);
57 let lower_q = Rational::exact_from(lower);
58 let higher_q = Rational::exact_from(higher);
59 let mut options = ToSciOptions::default();
60 for precision in 1.. {
61 options.set_precision(precision);
62 let s = self_q.to_sci_with_options(options).to_string();
63 let s_lower = lower_q.to_sci_with_options(options).to_string();
64 let s_higher = higher_q.to_sci_with_options(options).to_string();
65 if s != s_lower && s != s_higher {
66 return if s.contains('.') {
67 write!(f, "{s}")
68 } else if let Some(i) = s.find('e') {
69 write!(f, "{}.0e{}", &s[..i], &s[i + 1..])
70 } else {
71 write!(f, "{s}.0")
72 };
73 }
74 }
75 panic!();
76 }
77 }
78 }
79}
80
81impl Debug for Float {
82 #[inline]
83 fn fmt(&self, f: &mut Formatter) -> Result {
84 Display::fmt(self, f)
85 }
86}
87
88impl LowerHex for Float {
89 #[inline]
90 fn fmt(&self, f: &mut Formatter) -> Result {
91 match self {
92 float_zero!() => f.write_str(if f.alternate() { "0x0.0" } else { "0.0" }),
93 float_negative_zero!() => f.write_str(if f.alternate() { "-0x0.0" } else { "-0.0" }),
94 Self(Finite {
95 exponent,
96 precision,
97 ..
98 }) => {
99 if self.is_sign_negative() {
100 f.write_char('-')?;
101 }
102 let mut options = ToSciOptions::default();
103 options.set_base(16);
104 let m = u64::from(exponent.mod_power_of_2(2));
105 let mut p = precision.saturating_sub(m).shr_round(2, Ceiling).0;
106 if m != 0 {
107 p += 1;
108 }
109 options.set_precision(p);
110 options.set_e_uppercase();
111 options.set_include_trailing_zeros(true);
112 if f.alternate() {
113 f.write_str("0x")?;
114 }
115 let pr = precision.round_to_multiple_of_power_of_2(5, Up).0;
116 let s = if u64::from(exponent.unsigned_abs()) > (pr << 2) {
117 let new_exponent = if *exponent > 0 {
118 i32::exact_from(pr << 1)
119 } else {
120 -i32::exact_from(pr << 1)
121 } + i32::wrapping_from(exponent.mod_power_of_2(2));
122 let mut s = Rational::exact_from(self >> (exponent - new_exponent))
123 .abs()
124 .to_sci_with_options(options)
125 .to_string();
126 s = replace_exponent_in_hex_string(&s, (exponent - 1).shr_round(2, Floor).0);
127 s
128 } else {
129 Rational::exact_from(self)
130 .abs()
131 .to_sci_with_options(options)
132 .to_string()
133 };
134 if s.contains('.') {
135 write!(f, "{s}")
136 } else if let Some(i) = s.find('E') {
137 write!(f, "{}.0E{}", &s[..i], &s[i + 1..])
138 } else {
139 write!(f, "{s}.0")
140 }
141 }
142 _ => Display::fmt(&self, f),
143 }
144 }
145}
146
147impl Display for ComparableFloat {
148 #[inline]
149 fn fmt(&self, f: &mut Formatter) -> Result {
150 Display::fmt(&ComparableFloatRef(&self.0), f)
151 }
152}
153
154impl Debug for ComparableFloat {
155 #[inline]
156 fn fmt(&self, f: &mut Formatter) -> Result {
157 Debug::fmt(&ComparableFloatRef(&self.0), f)
158 }
159}
160
161impl LowerHex for ComparableFloat {
162 #[inline]
163 fn fmt(&self, f: &mut Formatter) -> Result {
164 LowerHex::fmt(&ComparableFloatRef(&self.0), f)
165 }
166}
167
168impl Display for ComparableFloatRef<'_> {
169 fn fmt(&self, f: &mut Formatter) -> Result {
170 if let x @ Float(Finite { precision, .. }) = &self.0 {
171 write!(f, "{x}")?;
172 f.write_char('#')?;
173 write!(f, "{precision}")
174 } else {
175 Display::fmt(&self.0, f)
176 }
177 }
178}
179
180impl LowerHex for ComparableFloatRef<'_> {
181 fn fmt(&self, f: &mut Formatter) -> Result {
182 if let x @ Float(Finite { precision, .. }) = &self.0 {
183 if f.alternate() {
184 write!(f, "{x:#x}")?;
185 } else {
186 write!(f, "{x:x}")?;
187 }
188 f.write_char('#')?;
189 write!(f, "{precision}")
190 } else {
191 LowerHex::fmt(&self.0, f)
192 }
193 }
194}
195
196impl Debug for ComparableFloatRef<'_> {
197 #[inline]
198 fn fmt(&self, f: &mut Formatter) -> Result {
199 Display::fmt(self, f)
200 }
201}