core/num/flt2dec/
mod.rs

1/*!
2
3Floating-point number to decimal conversion routines.
4
5# Problem statement
6
7We are given the floating-point number `v = f * 2^e` with an integer `f`,
8and its bounds `minus` and `plus` such that any number between `v - minus` and
9`v + plus` will be rounded to `v`. For the simplicity we assume that
10this range is exclusive. Then we would like to get the unique decimal
11representation `V = 0.d[0..n-1] * 10^k` such that:
12
13- `d[0]` is non-zero.
14
15- It's correctly rounded when parsed back: `v - minus < V < v + plus`.
16  Furthermore it is shortest such one, i.e., there is no representation
17  with less than `n` digits that is correctly rounded.
18
19- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Note that
20  there might be two representations satisfying this uniqueness requirement,
21  in which case some tie-breaking mechanism is used.
22
23We will call this mode of operation as to the *shortest* mode. This mode is used
24when there is no additional constraint, and can be thought as a "natural" mode
25as it matches the ordinary intuition (it at least prints `0.1f32` as "0.1").
26
27We have two more modes of operation closely related to each other. In these modes
28we are given either the number of significant digits `n` or the last-digit
29limitation `limit` (which determines the actual `n`), and we would like to get
30the representation `V = 0.d[0..n-1] * 10^k` such that:
31
32- `d[0]` is non-zero, unless `n` was zero in which case only `k` is returned.
33
34- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Again,
35  there might be some tie-breaking mechanism.
36
37When `limit` is given but not `n`, we set `n` such that `k - n = limit`
38so that the last digit `d[n-1]` is scaled by `10^(k-n) = 10^limit`.
39If such `n` is negative, we clip it to zero so that we will only get `k`.
40We are also limited by the supplied buffer. This limitation is used to print
41the number up to given number of fractional digits without knowing
42the correct `k` beforehand.
43
44We will call the mode of operation requiring `n` as to the *exact* mode,
45and one requiring `limit` as to the *fixed* mode. The exact mode is a subset of
46the fixed mode: the sufficiently large last-digit limitation will eventually fill
47the supplied buffer and let the algorithm to return.
48
49# Implementation overview
50
51It is easy to get the floating point printing correct but slow (Russ Cox has
52[demonstrated](https://research.swtch.com/ftoa) how it's easy), or incorrect but
53fast (naïve division and modulo). But it is surprisingly hard to print
54floating point numbers correctly *and* efficiently.
55
56There are two classes of algorithms widely known to be correct.
57
58- The "Dragon" family of algorithm is first described by Guy L. Steele Jr. and
59  Jon L. White. They rely on the fixed-size big integer for their correctness.
60  A slight improvement was found later, which is posthumously described by
61  Robert G. Burger and R. Kent Dybvig. David Gay's `dtoa.c` routine is
62  a popular implementation of this strategy.
63
64- The "Grisu" family of algorithm is first described by Florian Loitsch.
65  They use very cheap integer-only procedure to determine the close-to-correct
66  representation which is at least guaranteed to be shortest. The variant,
67  Grisu3, actively detects if the resulting representation is incorrect.
68
69We implement both algorithms with necessary tweaks to suit our requirements.
70In particular, published literatures are short of the actual implementation
71difficulties like how to avoid arithmetic overflows. Each implementation,
72available in `strategy::dragon` and `strategy::grisu` respectively,
73extensively describes all necessary justifications and many proofs for them.
74(It is still difficult to follow though. You have been warned.)
75
76Both implementations expose two public functions:
77
78- `format_shortest(decoded, buf)`, which always needs at least
79  `MAX_SIG_DIGITS` digits of buffer. Implements the shortest mode.
80
81- `format_exact(decoded, buf, limit)`, which accepts as small as
82  one digit of buffer. Implements exact and fixed modes.
83
84They try to fill the `u8` buffer with digits and returns the number of digits
85written and the exponent `k`. They are total for all finite `f32` and `f64`
86inputs (Grisu internally falls back to Dragon if necessary).
87
88The rendered digits are formatted into the actual string form with
89four functions:
90
91- `to_shortest_str` prints the shortest representation, which can be padded by
92  zeroes to make *at least* given number of fractional digits.
93
94- `to_shortest_exp_str` prints the shortest representation, which can be
95  padded by zeroes when its exponent is in the specified ranges,
96  or can be printed in the exponential form such as `1.23e45`.
97
98- `to_exact_exp_str` prints the exact representation with given number of
99  digits in the exponential form.
100
101- `to_exact_fixed_str` prints the fixed representation with *exactly*
102  given number of fractional digits.
103
104They all return a slice of preallocated `Part` array, which corresponds to
105the individual part of strings: a fixed string, a part of rendered digits,
106a number of zeroes or a small (`u16`) number. The caller is expected to
107provide a large enough buffer and `Part` array, and to assemble the final
108string from resulting `Part`s itself.
109
110All algorithms and formatting functions are accompanied by extensive tests
111in `coretests::num::flt2dec` module. It also shows how to use individual
112functions.
113
114*/
115
116// while this is extensively documented, this is in principle private which is
117// only made public for testing. do not expose us.
118#![doc(hidden)]
119#![unstable(
120    feature = "flt2dec",
121    reason = "internal routines only exposed for testing",
122    issue = "none"
123)]
124
125pub use self::decoder::{DecodableFloat, Decoded, FullDecoded, decode};
126use super::fmt::{Formatted, Part};
127use crate::mem::MaybeUninit;
128
129pub mod decoder;
130pub mod estimator;
131
132/// Digit-generation algorithms.
133pub mod strategy {
134    pub mod dragon;
135    pub mod grisu;
136}
137
138/// The minimum size of buffer necessary for the shortest mode.
139///
140/// It is a bit non-trivial to derive, but this is one plus the maximal number of
141/// significant decimal digits from formatting algorithms with the shortest result.
142/// The exact formula is `ceil(# bits in mantissa * log_10 2 + 1)`.
143pub const MAX_SIG_DIGITS: usize = 17;
144
145/// When `d` contains decimal digits, increase the last digit and propagate carry.
146/// Returns a next digit when it causes the length to change.
147#[doc(hidden)]
148pub fn round_up(d: &mut [u8]) -> Option<u8> {
149    match d.iter().rposition(|&c| c != b'9') {
150        Some(i) => {
151            // d[i+1..n] is all nines
152            d[i] += 1;
153            for j in i + 1..d.len() {
154                d[j] = b'0';
155            }
156            None
157        }
158        None if d.len() > 0 => {
159            // 999..999 rounds to 1000..000 with an increased exponent
160            d[0] = b'1';
161            for j in 1..d.len() {
162                d[j] = b'0';
163            }
164            Some(b'0')
165        }
166        None => {
167            // an empty buffer rounds up (a bit strange but reasonable)
168            Some(b'1')
169        }
170    }
171}
172
173/// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form
174/// with at least given number of fractional digits. The result is stored to
175/// the supplied parts array and a slice of written parts is returned.
176///
177/// `frac_digits` can be less than the number of actual fractional digits in `buf`;
178/// it will be ignored and full digits will be printed. It is only used to print
179/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that
180/// it will only print given digits and nothing else.
181fn digits_to_dec_str<'a>(
182    buf: &'a [u8],
183    exp: i16,
184    frac_digits: usize,
185    parts: &'a mut [MaybeUninit<Part<'a>>],
186) -> &'a [Part<'a>] {
187    assert!(!buf.is_empty());
188    assert!(buf[0] > b'0');
189    assert!(parts.len() >= 4);
190
191    // if there is the restriction on the last digit position, `buf` is assumed to be
192    // left-padded with the virtual zeroes. the number of virtual zeroes, `nzeroes`,
193    // equals to `max(0, exp + frac_digits - buf.len())`, so that the position of
194    // the last digit `exp - buf.len() - nzeroes` is no more than `-frac_digits`:
195    //
196    //                       |<-virtual->|
197    //       |<---- buf ---->|  zeroes   |     exp
198    //    0. 1 2 3 4 5 6 7 8 9 _ _ _ _ _ _ x 10
199    //    |                  |           |
200    // 10^exp    10^(exp-buf.len())   10^(exp-buf.len()-nzeroes)
201    //
202    // `nzeroes` is individually calculated for each case in order to avoid overflow.
203
204    if exp <= 0 {
205        // the decimal point is before rendered digits: [0.][000...000][1234][____]
206        let minus_exp = -(exp as i32) as usize;
207        parts[0] = MaybeUninit::new(Part::Copy(b"0."));
208        parts[1] = MaybeUninit::new(Part::Zero(minus_exp));
209        parts[2] = MaybeUninit::new(Part::Copy(buf));
210        if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp {
211            parts[3] = MaybeUninit::new(Part::Zero((frac_digits - buf.len()) - minus_exp));
212            // SAFETY: we just initialized the elements `..4`.
213            unsafe { parts[..4].assume_init_ref() }
214        } else {
215            // SAFETY: we just initialized the elements `..3`.
216            unsafe { parts[..3].assume_init_ref() }
217        }
218    } else {
219        let exp = exp as usize;
220        if exp < buf.len() {
221            // the decimal point is inside rendered digits: [12][.][34][____]
222            parts[0] = MaybeUninit::new(Part::Copy(&buf[..exp]));
223            parts[1] = MaybeUninit::new(Part::Copy(b"."));
224            parts[2] = MaybeUninit::new(Part::Copy(&buf[exp..]));
225            if frac_digits > buf.len() - exp {
226                parts[3] = MaybeUninit::new(Part::Zero(frac_digits - (buf.len() - exp)));
227                // SAFETY: we just initialized the elements `..4`.
228                unsafe { parts[..4].assume_init_ref() }
229            } else {
230                // SAFETY: we just initialized the elements `..3`.
231                unsafe { parts[..3].assume_init_ref() }
232            }
233        } else {
234            // the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__].
235            parts[0] = MaybeUninit::new(Part::Copy(buf));
236            parts[1] = MaybeUninit::new(Part::Zero(exp - buf.len()));
237            if frac_digits > 0 {
238                parts[2] = MaybeUninit::new(Part::Copy(b"."));
239                parts[3] = MaybeUninit::new(Part::Zero(frac_digits));
240                // SAFETY: we just initialized the elements `..4`.
241                unsafe { parts[..4].assume_init_ref() }
242            } else {
243                // SAFETY: we just initialized the elements `..2`.
244                unsafe { parts[..2].assume_init_ref() }
245            }
246        }
247    }
248}
249
250/// Formats the given decimal digits `0.<...buf...> * 10^exp` into the exponential
251/// form with at least the given number of significant digits. When `upper` is `true`,
252/// the exponent will be prefixed by `E`; otherwise that's `e`. The result is
253/// stored to the supplied parts array and a slice of written parts is returned.
254///
255/// `min_digits` can be less than the number of actual significant digits in `buf`;
256/// it will be ignored and full digits will be printed. It is only used to print
257/// additional zeroes after rendered digits. Thus, `min_digits == 0` means that
258/// it will only print the given digits and nothing else.
259fn digits_to_exp_str<'a>(
260    buf: &'a [u8],
261    exp: i16,
262    min_ndigits: usize,
263    upper: bool,
264    parts: &'a mut [MaybeUninit<Part<'a>>],
265) -> &'a [Part<'a>] {
266    assert!(!buf.is_empty());
267    assert!(buf[0] > b'0');
268    assert!(parts.len() >= 6);
269
270    let mut n = 0;
271
272    parts[n] = MaybeUninit::new(Part::Copy(&buf[..1]));
273    n += 1;
274
275    if buf.len() > 1 || min_ndigits > 1 {
276        parts[n] = MaybeUninit::new(Part::Copy(b"."));
277        parts[n + 1] = MaybeUninit::new(Part::Copy(&buf[1..]));
278        n += 2;
279        if min_ndigits > buf.len() {
280            parts[n] = MaybeUninit::new(Part::Zero(min_ndigits - buf.len()));
281            n += 1;
282        }
283    }
284
285    // 0.1234 x 10^exp = 1.234 x 10^(exp-1)
286    let exp = exp as i32 - 1; // avoid underflow when exp is i16::MIN
287    if exp < 0 {
288        parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E-" } else { b"e-" }));
289        parts[n + 1] = MaybeUninit::new(Part::Num(-exp as u16));
290    } else {
291        parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E" } else { b"e" }));
292        parts[n + 1] = MaybeUninit::new(Part::Num(exp as u16));
293    }
294    // SAFETY: we just initialized the elements `..n + 2`.
295    unsafe { parts[..n + 2].assume_init_ref() }
296}
297
298/// Sign formatting options.
299#[derive(Copy, Clone, PartialEq, Eq, Debug)]
300pub enum Sign {
301    /// Prints `-` for any negative value.
302    Minus, // -inf -1 -0  0  1  inf nan
303    /// Prints `-` for any negative value, or `+` otherwise.
304    MinusPlus, // -inf -1 -0 +0 +1 +inf nan
305}
306
307/// Returns the static byte string corresponding to the sign to be formatted.
308/// It can be either `""`, `"+"` or `"-"`.
309fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static str {
310    match (*decoded, sign) {
311        (FullDecoded::Nan, _) => "",
312        (_, Sign::Minus) => {
313            if negative {
314                "-"
315            } else {
316                ""
317            }
318        }
319        (_, Sign::MinusPlus) => {
320            if negative {
321                "-"
322            } else {
323                "+"
324            }
325        }
326    }
327}
328
329/// Formats the given floating point number into the decimal form with at least
330/// given number of fractional digits. The result is stored to the supplied parts
331/// array while utilizing given byte buffer as a scratch. `upper` is currently
332/// unused but left for the future decision to change the case of non-finite values,
333/// i.e., `inf` and `nan`. The first part to be rendered is always a `Part::Sign`
334/// (which can be an empty string if no sign is rendered).
335///
336/// `format_shortest` should be the underlying digit-generation function.
337/// It should return the part of the buffer that it initialized.
338/// You probably would want `strategy::grisu::format_shortest` for this.
339///
340/// `frac_digits` can be less than the number of actual fractional digits in `v`;
341/// it will be ignored and full digits will be printed. It is only used to print
342/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that
343/// it will only print given digits and nothing else.
344///
345/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
346/// There should be at least 4 parts available, due to the worst case like
347/// `[+][0.][0000][2][0000]` with `frac_digits = 10`.
348pub fn to_shortest_str<'a, T, F>(
349    mut format_shortest: F,
350    v: T,
351    sign: Sign,
352    frac_digits: usize,
353    buf: &'a mut [MaybeUninit<u8>],
354    parts: &'a mut [MaybeUninit<Part<'a>>],
355) -> Formatted<'a>
356where
357    T: DecodableFloat,
358    F: FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
359{
360    assert!(parts.len() >= 4);
361    assert!(buf.len() >= MAX_SIG_DIGITS);
362
363    let (negative, full_decoded) = decode(v);
364    let sign = determine_sign(sign, &full_decoded, negative);
365    match full_decoded {
366        FullDecoded::Nan => {
367            parts[0] = MaybeUninit::new(Part::Copy(b"NaN"));
368            // SAFETY: we just initialized the elements `..1`.
369            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
370        }
371        FullDecoded::Infinite => {
372            parts[0] = MaybeUninit::new(Part::Copy(b"inf"));
373            // SAFETY: we just initialized the elements `..1`.
374            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
375        }
376        FullDecoded::Zero => {
377            if frac_digits > 0 {
378                // [0.][0000]
379                parts[0] = MaybeUninit::new(Part::Copy(b"0."));
380                parts[1] = MaybeUninit::new(Part::Zero(frac_digits));
381                Formatted {
382                    sign,
383                    // SAFETY: we just initialized the elements `..2`.
384                    parts: unsafe { parts[..2].assume_init_ref() },
385                }
386            } else {
387                parts[0] = MaybeUninit::new(Part::Copy(b"0"));
388                Formatted {
389                    sign,
390                    // SAFETY: we just initialized the elements `..1`.
391                    parts: unsafe { parts[..1].assume_init_ref() },
392                }
393            }
394        }
395        FullDecoded::Finite(ref decoded) => {
396            let (buf, exp) = format_shortest(decoded, buf);
397            Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) }
398        }
399    }
400}
401
402/// Formats the given floating point number into the decimal form or
403/// the exponential form, depending on the resulting exponent. The result is
404/// stored to the supplied parts array while utilizing given byte buffer
405/// as a scratch. `upper` is used to determine the case of non-finite values
406/// (`inf` and `nan`) or the case of the exponent prefix (`e` or `E`).
407/// The first part to be rendered is always a `Part::Sign` (which can be
408/// an empty string if no sign is rendered).
409///
410/// `format_shortest` should be the underlying digit-generation function.
411/// It should return the part of the buffer that it initialized.
412/// You probably would want `strategy::grisu::format_shortest` for this.
413///
414/// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted
415/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparent* `V`
416/// instead of the actual `v`! Thus any printed exponent in the exponential form
417/// cannot be in this range, avoiding any confusion.
418///
419/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
420/// There should be at least 6 parts available, due to the worst case like
421/// `[+][1][.][2345][e][-][6]`.
422pub fn to_shortest_exp_str<'a, T, F>(
423    mut format_shortest: F,
424    v: T,
425    sign: Sign,
426    dec_bounds: (i16, i16),
427    upper: bool,
428    buf: &'a mut [MaybeUninit<u8>],
429    parts: &'a mut [MaybeUninit<Part<'a>>],
430) -> Formatted<'a>
431where
432    T: DecodableFloat,
433    F: FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
434{
435    assert!(parts.len() >= 6);
436    assert!(buf.len() >= MAX_SIG_DIGITS);
437    assert!(dec_bounds.0 <= dec_bounds.1);
438
439    let (negative, full_decoded) = decode(v);
440    let sign = determine_sign(sign, &full_decoded, negative);
441    match full_decoded {
442        FullDecoded::Nan => {
443            parts[0] = MaybeUninit::new(Part::Copy(b"NaN"));
444            // SAFETY: we just initialized the elements `..1`.
445            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
446        }
447        FullDecoded::Infinite => {
448            parts[0] = MaybeUninit::new(Part::Copy(b"inf"));
449            // SAFETY: we just initialized the elements `..1`.
450            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
451        }
452        FullDecoded::Zero => {
453            parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 {
454                MaybeUninit::new(Part::Copy(b"0"))
455            } else {
456                MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" }))
457            };
458            // SAFETY: we just initialized the elements `..1`.
459            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
460        }
461        FullDecoded::Finite(ref decoded) => {
462            let (buf, exp) = format_shortest(decoded, buf);
463            let vis_exp = exp as i32 - 1;
464            let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 {
465                digits_to_dec_str(buf, exp, 0, parts)
466            } else {
467                digits_to_exp_str(buf, exp, 0, upper, parts)
468            };
469            Formatted { sign, parts }
470        }
471    }
472}
473
474/// Returns a rather crude approximation (upper bound) for the maximum buffer size
475/// calculated from the given decoded exponent.
476///
477/// The exact limit is:
478///
479/// - when `exp < 0`, the maximum length is `ceil(log_10 (5^-exp * (2^64 - 1)))`.
480/// - when `exp >= 0`, the maximum length is `ceil(log_10 (2^exp * (2^64 - 1)))`.
481///
482/// `ceil(log_10 (x^exp * (2^64 - 1)))` is less than `ceil(log_10 (2^64 - 1)) +
483/// ceil(exp * log_10 x)`, which is in turn less than `20 + (1 + exp * log_10 x)`.
484/// We use the facts that `log_10 2 < 5/16` and `log_10 5 < 12/16`, which is
485/// enough for our purposes.
486///
487/// Why do we need this? `format_exact` functions will fill the entire buffer
488/// unless limited by the last digit restriction, but it is possible that
489/// the number of digits requested is ridiculously large (say, 30,000 digits).
490/// The vast majority of buffer will be filled with zeroes, so we don't want to
491/// allocate all the buffer beforehand. Consequently, for any given arguments,
492/// 826 bytes of buffer should be sufficient for `f64`. Compare this with
493/// the actual number for the worst case: 770 bytes (when `exp = -1074`).
494fn estimate_max_buf_len(exp: i16) -> usize {
495    21 + ((if exp < 0 { -12 } else { 5 } * exp as i32) as usize >> 4)
496}
497
498/// Formats given floating point number into the exponential form with
499/// exactly given number of significant digits. The result is stored to
500/// the supplied parts array while utilizing given byte buffer as a scratch.
501/// `upper` is used to determine the case of the exponent prefix (`e` or `E`).
502/// The first part to be rendered is always a `Part::Sign` (which can be
503/// an empty string if no sign is rendered).
504///
505/// `format_exact` should be the underlying digit-generation function.
506/// It should return the part of the buffer that it initialized.
507/// You probably would want `strategy::grisu::format_exact` for this.
508///
509/// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is
510/// so large that only the fixed number of digits will be ever written.
511/// (The tipping point for `f64` is about 800, so 1000 bytes should be enough.)
512/// There should be at least 6 parts available, due to the worst case like
513/// `[+][1][.][2345][e][-][6]`.
514pub fn to_exact_exp_str<'a, T, F>(
515    mut format_exact: F,
516    v: T,
517    sign: Sign,
518    ndigits: usize,
519    upper: bool,
520    buf: &'a mut [MaybeUninit<u8>],
521    parts: &'a mut [MaybeUninit<Part<'a>>],
522) -> Formatted<'a>
523where
524    T: DecodableFloat,
525    F: FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
526{
527    assert!(parts.len() >= 6);
528    assert!(ndigits > 0);
529
530    let (negative, full_decoded) = decode(v);
531    let sign = determine_sign(sign, &full_decoded, negative);
532    match full_decoded {
533        FullDecoded::Nan => {
534            parts[0] = MaybeUninit::new(Part::Copy(b"NaN"));
535            // SAFETY: we just initialized the elements `..1`.
536            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
537        }
538        FullDecoded::Infinite => {
539            parts[0] = MaybeUninit::new(Part::Copy(b"inf"));
540            // SAFETY: we just initialized the elements `..1`.
541            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
542        }
543        FullDecoded::Zero => {
544            if ndigits > 1 {
545                // [0.][0000][e0]
546                parts[0] = MaybeUninit::new(Part::Copy(b"0."));
547                parts[1] = MaybeUninit::new(Part::Zero(ndigits - 1));
548                parts[2] = MaybeUninit::new(Part::Copy(if upper { b"E0" } else { b"e0" }));
549                Formatted {
550                    sign,
551                    // SAFETY: we just initialized the elements `..3`.
552                    parts: unsafe { parts[..3].assume_init_ref() },
553                }
554            } else {
555                parts[0] = MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" }));
556                Formatted {
557                    sign,
558                    // SAFETY: we just initialized the elements `..1`.
559                    parts: unsafe { parts[..1].assume_init_ref() },
560                }
561            }
562        }
563        FullDecoded::Finite(ref decoded) => {
564            let maxlen = estimate_max_buf_len(decoded.exp);
565            assert!(buf.len() >= ndigits || buf.len() >= maxlen);
566
567            let trunc = if ndigits < maxlen { ndigits } else { maxlen };
568            let (buf, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN);
569            Formatted { sign, parts: digits_to_exp_str(buf, exp, ndigits, upper, parts) }
570        }
571    }
572}
573
574/// Formats given floating point number into the decimal form with exactly
575/// given number of fractional digits. The result is stored to the supplied parts
576/// array while utilizing given byte buffer as a scratch. `upper` is currently
577/// unused but left for the future decision to change the case of non-finite values,
578/// i.e., `inf` and `nan`. The first part to be rendered is always a `Part::Sign`
579/// (which can be an empty string if no sign is rendered).
580///
581/// `format_exact` should be the underlying digit-generation function.
582/// It should return the part of the buffer that it initialized.
583/// You probably would want `strategy::grisu::format_exact` for this.
584///
585/// The byte buffer should be enough for the output unless `frac_digits` is
586/// so large that only the fixed number of digits will be ever written.
587/// (The tipping point for `f64` is about 800, and 1000 bytes should be enough.)
588/// There should be at least 4 parts available, due to the worst case like
589/// `[+][0.][0000][2][0000]` with `frac_digits = 10`.
590pub fn to_exact_fixed_str<'a, T, F>(
591    mut format_exact: F,
592    v: T,
593    sign: Sign,
594    frac_digits: usize,
595    buf: &'a mut [MaybeUninit<u8>],
596    parts: &'a mut [MaybeUninit<Part<'a>>],
597) -> Formatted<'a>
598where
599    T: DecodableFloat,
600    F: FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
601{
602    assert!(parts.len() >= 4);
603
604    let (negative, full_decoded) = decode(v);
605    let sign = determine_sign(sign, &full_decoded, negative);
606    match full_decoded {
607        FullDecoded::Nan => {
608            parts[0] = MaybeUninit::new(Part::Copy(b"NaN"));
609            // SAFETY: we just initialized the elements `..1`.
610            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
611        }
612        FullDecoded::Infinite => {
613            parts[0] = MaybeUninit::new(Part::Copy(b"inf"));
614            // SAFETY: we just initialized the elements `..1`.
615            Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } }
616        }
617        FullDecoded::Zero => {
618            if frac_digits > 0 {
619                // [0.][0000]
620                parts[0] = MaybeUninit::new(Part::Copy(b"0."));
621                parts[1] = MaybeUninit::new(Part::Zero(frac_digits));
622                Formatted {
623                    sign,
624                    // SAFETY: we just initialized the elements `..2`.
625                    parts: unsafe { parts[..2].assume_init_ref() },
626                }
627            } else {
628                parts[0] = MaybeUninit::new(Part::Copy(b"0"));
629                Formatted {
630                    sign,
631                    // SAFETY: we just initialized the elements `..1`.
632                    parts: unsafe { parts[..1].assume_init_ref() },
633                }
634            }
635        }
636        FullDecoded::Finite(ref decoded) => {
637            let maxlen = estimate_max_buf_len(decoded.exp);
638            assert!(buf.len() >= maxlen);
639
640            // it *is* possible that `frac_digits` is ridiculously large.
641            // `format_exact` will end rendering digits much earlier in this case,
642            // because we are strictly limited by `maxlen`.
643            let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN };
644            let (buf, exp) = format_exact(decoded, &mut buf[..maxlen], limit);
645            if exp <= limit {
646                // the restriction couldn't been met, so this should render like zero no matter
647                // `exp` was. this does not include the case that the restriction has been met
648                // only after the final rounding-up; it's a regular case with `exp = limit + 1`.
649                debug_assert_eq!(buf.len(), 0);
650                if frac_digits > 0 {
651                    // [0.][0000]
652                    parts[0] = MaybeUninit::new(Part::Copy(b"0."));
653                    parts[1] = MaybeUninit::new(Part::Zero(frac_digits));
654                    Formatted {
655                        sign,
656                        // SAFETY: we just initialized the elements `..2`.
657                        parts: unsafe { parts[..2].assume_init_ref() },
658                    }
659                } else {
660                    parts[0] = MaybeUninit::new(Part::Copy(b"0"));
661                    Formatted {
662                        sign,
663                        // SAFETY: we just initialized the elements `..1`.
664                        parts: unsafe { parts[..1].assume_init_ref() },
665                    }
666                }
667            } else {
668                Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) }
669            }
670        }
671    }
672}