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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy