core/fmt/
float.rs

1use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
2use crate::mem::MaybeUninit;
3use crate::num::{flt2dec, fmt as numfmt};
4
5#[doc(hidden)]
6trait GeneralFormat: PartialOrd {
7    /// Determines if a value should use exponential based on its magnitude, given the precondition
8    /// that it will not be rounded any further before it is displayed.
9    fn already_rounded_value_should_use_exponential(&self) -> bool;
10}
11
12macro_rules! impl_general_format {
13    ($($t:ident)*) => {
14        $(impl GeneralFormat for $t {
15            fn already_rounded_value_should_use_exponential(&self) -> bool {
16                let abs = $t::abs(*self);
17                (abs != 0.0 && abs < 1e-4) || abs >= 1e+16
18            }
19        })*
20    }
21}
22
23#[cfg(target_has_reliable_f16)]
24impl_general_format! { f16 }
25impl_general_format! { f32 f64 }
26
27// Don't inline this so callers don't use the stack space this function
28// requires unless they have to.
29#[inline(never)]
30fn float_to_decimal_common_exact<T>(
31    fmt: &mut Formatter<'_>,
32    num: &T,
33    sign: flt2dec::Sign,
34    precision: u16,
35) -> Result
36where
37    T: flt2dec::DecodableFloat,
38{
39    let mut buf: [MaybeUninit<u8>; 1024] = [MaybeUninit::uninit(); 1024]; // enough for f32 and f64
40    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = [MaybeUninit::uninit(); 4];
41    let formatted = flt2dec::to_exact_fixed_str(
42        flt2dec::strategy::grisu::format_exact,
43        *num,
44        sign,
45        precision.into(),
46        &mut buf,
47        &mut parts,
48    );
49    // SAFETY: `to_exact_fixed_str` and `format_exact` produce only ASCII characters.
50    unsafe { fmt.pad_formatted_parts(&formatted) }
51}
52
53// Don't inline this so callers that call both this and the above won't wind
54// up using the combined stack space of both functions in some cases.
55#[inline(never)]
56fn float_to_decimal_common_shortest<T>(
57    fmt: &mut Formatter<'_>,
58    num: &T,
59    sign: flt2dec::Sign,
60    precision: u16,
61) -> Result
62where
63    T: flt2dec::DecodableFloat,
64{
65    // enough for f32 and f64
66    let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] =
67        [MaybeUninit::uninit(); flt2dec::MAX_SIG_DIGITS];
68    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = [MaybeUninit::uninit(); 4];
69    let formatted = flt2dec::to_shortest_str(
70        flt2dec::strategy::grisu::format_shortest,
71        *num,
72        sign,
73        precision.into(),
74        &mut buf,
75        &mut parts,
76    );
77    // SAFETY: `to_shortest_str` and `format_shortest` produce only ASCII characters.
78    unsafe { fmt.pad_formatted_parts(&formatted) }
79}
80
81fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
82where
83    T: flt2dec::DecodableFloat,
84{
85    let force_sign = fmt.sign_plus();
86    let sign = match force_sign {
87        false => flt2dec::Sign::Minus,
88        true => flt2dec::Sign::MinusPlus,
89    };
90
91    if let Some(precision) = fmt.options.get_precision() {
92        float_to_decimal_common_exact(fmt, num, sign, precision)
93    } else {
94        let min_precision = 0;
95        float_to_decimal_common_shortest(fmt, num, sign, min_precision)
96    }
97}
98
99// Don't inline this so callers don't use the stack space this function
100// requires unless they have to.
101#[inline(never)]
102fn float_to_exponential_common_exact<T>(
103    fmt: &mut Formatter<'_>,
104    num: &T,
105    sign: flt2dec::Sign,
106    precision: u16,
107    upper: bool,
108) -> Result
109where
110    T: flt2dec::DecodableFloat,
111{
112    let mut buf: [MaybeUninit<u8>; 1024] = [MaybeUninit::uninit(); 1024]; // enough for f32 and f64
113    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = [MaybeUninit::uninit(); 6];
114    let formatted = flt2dec::to_exact_exp_str(
115        flt2dec::strategy::grisu::format_exact,
116        *num,
117        sign,
118        precision.into(),
119        upper,
120        &mut buf,
121        &mut parts,
122    );
123    // SAFETY: `to_exact_exp_str` and `format_exact` produce only ASCII characters.
124    unsafe { fmt.pad_formatted_parts(&formatted) }
125}
126
127// Don't inline this so callers that call both this and the above won't wind
128// up using the combined stack space of both functions in some cases.
129#[inline(never)]
130fn float_to_exponential_common_shortest<T>(
131    fmt: &mut Formatter<'_>,
132    num: &T,
133    sign: flt2dec::Sign,
134    upper: bool,
135) -> Result
136where
137    T: flt2dec::DecodableFloat,
138{
139    // enough for f32 and f64
140    let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] =
141        [MaybeUninit::uninit(); flt2dec::MAX_SIG_DIGITS];
142    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = [MaybeUninit::uninit(); 6];
143    let formatted = flt2dec::to_shortest_exp_str(
144        flt2dec::strategy::grisu::format_shortest,
145        *num,
146        sign,
147        (0, 0),
148        upper,
149        &mut buf,
150        &mut parts,
151    );
152    // SAFETY: `to_shortest_exp_str` and `format_shortest` produce only ASCII characters.
153    unsafe { fmt.pad_formatted_parts(&formatted) }
154}
155
156// Common code of floating point LowerExp and UpperExp.
157fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
158where
159    T: flt2dec::DecodableFloat,
160{
161    let force_sign = fmt.sign_plus();
162    let sign = match force_sign {
163        false => flt2dec::Sign::Minus,
164        true => flt2dec::Sign::MinusPlus,
165    };
166
167    if let Some(precision) = fmt.options.get_precision() {
168        // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
169        float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
170    } else {
171        float_to_exponential_common_shortest(fmt, num, sign, upper)
172    }
173}
174
175fn float_to_general_debug<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
176where
177    T: flt2dec::DecodableFloat + GeneralFormat,
178{
179    let force_sign = fmt.sign_plus();
180    let sign = match force_sign {
181        false => flt2dec::Sign::Minus,
182        true => flt2dec::Sign::MinusPlus,
183    };
184
185    if let Some(precision) = fmt.options.get_precision() {
186        // this behavior of {:.PREC?} predates exponential formatting for {:?}
187        float_to_decimal_common_exact(fmt, num, sign, precision)
188    } else {
189        // since there is no precision, there will be no rounding
190        if num.already_rounded_value_should_use_exponential() {
191            let upper = false;
192            float_to_exponential_common_shortest(fmt, num, sign, upper)
193        } else {
194            let min_precision = 1;
195            float_to_decimal_common_shortest(fmt, num, sign, min_precision)
196        }
197    }
198}
199
200macro_rules! floating {
201    ($($ty:ident)*) => {
202        $(
203            #[stable(feature = "rust1", since = "1.0.0")]
204            impl Debug for $ty {
205                fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
206                    float_to_general_debug(fmt, self)
207                }
208            }
209
210            #[stable(feature = "rust1", since = "1.0.0")]
211            impl Display for $ty {
212                fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
213                    float_to_decimal_display(fmt, self)
214                }
215            }
216
217            #[stable(feature = "rust1", since = "1.0.0")]
218            impl LowerExp for $ty {
219                fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
220                    float_to_exponential_common(fmt, self, false)
221                }
222            }
223
224            #[stable(feature = "rust1", since = "1.0.0")]
225            impl UpperExp for $ty {
226                fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
227                    float_to_exponential_common(fmt, self, true)
228                }
229            }
230        )*
231    };
232}
233
234floating! { f32 f64 }
235
236#[cfg(target_has_reliable_f16)]
237floating! { f16 }
238
239// FIXME(f16_f128): A fallback is used when the backend+target does not support f16 well, in order
240// to avoid ICEs.
241
242#[cfg(not(target_has_reliable_f16))]
243#[stable(feature = "rust1", since = "1.0.0")]
244impl Debug for f16 {
245    #[inline]
246    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
247        write!(f, "{:#06x}", self.to_bits())
248    }
249}
250
251#[cfg(not(target_has_reliable_f16))]
252#[stable(feature = "rust1", since = "1.0.0")]
253impl Display for f16 {
254    #[inline]
255    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
256        Debug::fmt(self, fmt)
257    }
258}
259
260#[cfg(not(target_has_reliable_f16))]
261#[stable(feature = "rust1", since = "1.0.0")]
262impl LowerExp for f16 {
263    #[inline]
264    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
265        Debug::fmt(self, fmt)
266    }
267}
268
269#[cfg(not(target_has_reliable_f16))]
270#[stable(feature = "rust1", since = "1.0.0")]
271impl UpperExp for f16 {
272    #[inline]
273    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
274        Debug::fmt(self, fmt)
275    }
276}
277
278#[stable(feature = "rust1", since = "1.0.0")]
279impl Debug for f128 {
280    #[inline]
281    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
282        write!(f, "{:#034x}", self.to_bits())
283    }
284}