/rust/registry/src/index.crates.io-1949cf8c6b5b557f/dtoa-1.0.11/src/lib.rs
Line | Count | Source |
1 | | //! [![github]](https://github.com/dtolnay/dtoa) [![crates-io]](https://crates.io/crates/dtoa) [![docs-rs]](https://docs.rs/dtoa) |
2 | | //! |
3 | | //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github |
4 | | //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust |
5 | | //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs |
6 | | //! |
7 | | //! <br> |
8 | | //! |
9 | | //! This crate provides fast conversion of floating point primitives to decimal |
10 | | //! strings. The implementation is a straightforward Rust port of [Milo Yip]'s |
11 | | //! C++ implementation [dtoa.h]. The original C++ code of each function is |
12 | | //! included in comments. |
13 | | //! |
14 | | //! See also [`itoa`] for printing integer primitives. |
15 | | //! |
16 | | //! [Milo Yip]: https://github.com/miloyip |
17 | | //! [dtoa.h]: https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h |
18 | | //! [`itoa`]: https://github.com/dtolnay/itoa |
19 | | //! |
20 | | //! # Example |
21 | | //! |
22 | | //! ``` |
23 | | //! fn main() { |
24 | | //! let mut buffer = dtoa::Buffer::new(); |
25 | | //! let printed = buffer.format(2.71828f64); |
26 | | //! assert_eq!(printed, "2.71828"); |
27 | | //! } |
28 | | //! ``` |
29 | | //! |
30 | | //! ## Performance |
31 | | //! |
32 | | //! The [dtoa-benchmark] compares this library and other Rust floating point |
33 | | //! formatting implementations across a range of precisions. The vertical axis |
34 | | //! in this chart shows nanoseconds taken by a single execution of |
35 | | //! `dtoa::Buffer::new().format_finite(value)` so a lower result indicates a |
36 | | //! faster library. |
37 | | //! |
38 | | //! [dtoa-benchmark]: https://github.com/dtolnay/dtoa-benchmark |
39 | | //! |
40 | | //!  |
41 | | |
42 | | #![doc(html_root_url = "https://docs.rs/dtoa/1.0.11")] |
43 | | #![no_std] |
44 | | #![allow( |
45 | | clippy::cast_lossless, |
46 | | clippy::cast_possible_truncation, |
47 | | clippy::cast_possible_wrap, |
48 | | clippy::cast_precision_loss, |
49 | | clippy::cast_sign_loss, |
50 | | clippy::doc_markdown, |
51 | | clippy::expl_impl_clone_on_copy, |
52 | | clippy::if_not_else, |
53 | | clippy::missing_errors_doc, |
54 | | clippy::must_use_candidate, |
55 | | clippy::needless_doctest_main, |
56 | | clippy::range_plus_one, |
57 | | clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7768 |
58 | | clippy::shadow_unrelated, |
59 | | clippy::suspicious_else_formatting, |
60 | | clippy::unreadable_literal, |
61 | | clippy::unseparated_literal_suffix |
62 | | )] |
63 | | |
64 | | #[macro_use] |
65 | | mod diyfp; |
66 | | #[macro_use] |
67 | | mod dtoa; |
68 | | |
69 | | use core::mem::MaybeUninit; |
70 | | use core::slice; |
71 | | use core::str; |
72 | | #[cfg(feature = "no-panic")] |
73 | | use no_panic::no_panic; |
74 | | |
75 | | const NAN: &str = "NaN"; |
76 | | const INFINITY: &str = "inf"; |
77 | | const NEG_INFINITY: &str = "-inf"; |
78 | | |
79 | | /// A correctly sized stack allocation for the formatted float to be written |
80 | | /// into. |
81 | | /// |
82 | | /// # Example |
83 | | /// |
84 | | /// ``` |
85 | | /// let mut buffer = dtoa::Buffer::new(); |
86 | | /// let printed = buffer.format_finite(2.71828); |
87 | | /// assert_eq!(printed, "2.71828"); |
88 | | /// ``` |
89 | | pub struct Buffer { |
90 | | bytes: [MaybeUninit<u8>; 25], |
91 | | } |
92 | | |
93 | | impl Default for Buffer { |
94 | | #[inline] |
95 | 0 | fn default() -> Buffer { |
96 | 0 | Buffer::new() |
97 | 0 | } |
98 | | } |
99 | | |
100 | | impl Copy for Buffer {} |
101 | | |
102 | | #[allow(clippy::non_canonical_clone_impl)] |
103 | | impl Clone for Buffer { |
104 | | #[inline] |
105 | 0 | fn clone(&self) -> Self { |
106 | 0 | Buffer::new() |
107 | 0 | } |
108 | | } |
109 | | |
110 | | impl Buffer { |
111 | | /// This is a cheap operation; you don't need to worry about reusing buffers |
112 | | /// for efficiency. |
113 | | #[inline] |
114 | | #[cfg_attr(feature = "no-panic", no_panic)] |
115 | 0 | pub fn new() -> Buffer { |
116 | 0 | let bytes = [MaybeUninit::<u8>::uninit(); 25]; |
117 | 0 | Buffer { bytes } |
118 | 0 | } Unexecuted instantiation: <dtoa::Buffer>::new Unexecuted instantiation: <dtoa::Buffer>::new |
119 | | |
120 | | /// Print a floating point number into this buffer and return a reference to |
121 | | /// its string representation within the buffer. |
122 | | /// |
123 | | /// # Special cases |
124 | | /// |
125 | | /// This function formats NaN as the string "NaN", positive infinity as |
126 | | /// "inf", and negative infinity as "-inf" to match std::fmt. |
127 | | /// |
128 | | /// If your input is known to be finite, you may get better performance by |
129 | | /// calling the `format_finite` method instead of `format` to avoid the |
130 | | /// checks for special cases. |
131 | | #[cfg_attr(feature = "no-panic", no_panic)] |
132 | 0 | pub fn format<F: Float>(&mut self, value: F) -> &str { |
133 | 0 | if value.is_nonfinite() { |
134 | 0 | value.format_nonfinite() |
135 | | } else { |
136 | 0 | self.format_finite(value) |
137 | | } |
138 | 0 | } Unexecuted instantiation: <dtoa::Buffer>::format::<f64> Unexecuted instantiation: <dtoa::Buffer>::format::<_> |
139 | | |
140 | | /// Print a floating point number into this buffer and return a reference to |
141 | | /// its string representation within the buffer. |
142 | | /// |
143 | | /// # Special cases |
144 | | /// |
145 | | /// This function **does not** check for NaN or infinity. If the input |
146 | | /// number is not a finite float, the printed representation will be some |
147 | | /// correctly formatted but unspecified numerical value. |
148 | | /// |
149 | | /// Please check [`is_finite`] yourself before calling this function, or |
150 | | /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. |
151 | | /// |
152 | | /// [`is_finite`]: f64::is_finite |
153 | | /// [`is_nan`]: f64::is_nan |
154 | | /// [`is_infinite`]: f64::is_infinite |
155 | | #[cfg_attr(feature = "no-panic", no_panic)] |
156 | 0 | pub fn format_finite<F: Float>(&mut self, value: F) -> &str { |
157 | 0 | value.write(self) |
158 | 0 | } Unexecuted instantiation: <dtoa::Buffer>::format_finite::<f64> Unexecuted instantiation: <dtoa::Buffer>::format_finite::<_> |
159 | | } |
160 | | |
161 | | /// A floating point number that can be written into a [`dtoa::Buffer`][Buffer]. |
162 | | /// |
163 | | /// This trait is sealed and cannot be implemented for types outside of dtoa. |
164 | | pub trait Float: private::Sealed {} |
165 | | |
166 | | impl Float for f32 {} |
167 | | impl Float for f64 {} |
168 | | |
169 | | // Seal to prevent downstream implementations of Float trait. |
170 | | mod private { |
171 | | pub trait Sealed: Copy { |
172 | | fn is_nonfinite(self) -> bool; |
173 | | fn format_nonfinite(self) -> &'static str; |
174 | | fn write(self, buf: &mut crate::Buffer) -> &str; |
175 | | } |
176 | | } |
177 | | |
178 | | impl private::Sealed for f32 { |
179 | | #[inline] |
180 | | #[cfg_attr(feature = "no-panic", no_panic)] |
181 | 0 | fn is_nonfinite(self) -> bool { |
182 | | const EXP_MASK: u32 = 0x7f800000; |
183 | 0 | let bits = self.to_bits(); |
184 | 0 | bits & EXP_MASK == EXP_MASK |
185 | 0 | } |
186 | | |
187 | | #[cold] |
188 | | #[cfg_attr(feature = "no-panic", no_panic)] |
189 | 0 | fn format_nonfinite(self) -> &'static str { |
190 | | const MANTISSA_MASK: u32 = 0x007fffff; |
191 | | const SIGN_MASK: u32 = 0x80000000; |
192 | 0 | let bits = self.to_bits(); |
193 | 0 | if bits & MANTISSA_MASK != 0 { |
194 | 0 | NAN |
195 | 0 | } else if bits & SIGN_MASK != 0 { |
196 | 0 | NEG_INFINITY |
197 | | } else { |
198 | 0 | INFINITY |
199 | | } |
200 | 0 | } |
201 | | |
202 | | #[inline] |
203 | 0 | fn write(self, buf: &mut Buffer) -> &str { |
204 | | dtoa! { |
205 | | floating_type: f32, |
206 | | significand_type: u32, |
207 | | exponent_type: i32, |
208 | | |
209 | | diy_significand_size: 32, |
210 | | significand_size: 23, |
211 | | exponent_bias: 0x7F, |
212 | | mask_type: u32, |
213 | | exponent_mask: 0x7F800000, |
214 | | significand_mask: 0x007FFFFF, |
215 | | hidden_bit: 0x00800000, |
216 | | cached_powers_f: CACHED_POWERS_F_32, |
217 | | cached_powers_e: CACHED_POWERS_E_32, |
218 | | min_power: (-36), |
219 | | }; |
220 | 0 | unsafe { dtoa(buf, self) } |
221 | 0 | } |
222 | | } |
223 | | |
224 | | impl private::Sealed for f64 { |
225 | | #[inline] |
226 | | #[cfg_attr(feature = "no-panic", no_panic)] |
227 | 0 | fn is_nonfinite(self) -> bool { |
228 | | const EXP_MASK: u64 = 0x7ff0000000000000; |
229 | 0 | let bits = self.to_bits(); |
230 | 0 | bits & EXP_MASK == EXP_MASK |
231 | 0 | } Unexecuted instantiation: <f64 as dtoa::private::Sealed>::is_nonfinite Unexecuted instantiation: <f64 as dtoa::private::Sealed>::is_nonfinite |
232 | | |
233 | | #[cold] |
234 | | #[cfg_attr(feature = "no-panic", no_panic)] |
235 | 0 | fn format_nonfinite(self) -> &'static str { |
236 | | const MANTISSA_MASK: u64 = 0x000fffffffffffff; |
237 | | const SIGN_MASK: u64 = 0x8000000000000000; |
238 | 0 | let bits = self.to_bits(); |
239 | 0 | if bits & MANTISSA_MASK != 0 { |
240 | 0 | NAN |
241 | 0 | } else if bits & SIGN_MASK != 0 { |
242 | 0 | NEG_INFINITY |
243 | | } else { |
244 | 0 | INFINITY |
245 | | } |
246 | 0 | } |
247 | | |
248 | | #[inline] |
249 | 0 | fn write(self, buf: &mut Buffer) -> &str { |
250 | | dtoa! { |
251 | | floating_type: f64, |
252 | | significand_type: u64, |
253 | | exponent_type: isize, |
254 | | |
255 | | diy_significand_size: 64, |
256 | | significand_size: 52, |
257 | | exponent_bias: 0x3FF, |
258 | | mask_type: u64, |
259 | | exponent_mask: 0x7FF0000000000000, |
260 | | significand_mask: 0x000FFFFFFFFFFFFF, |
261 | | hidden_bit: 0x0010000000000000, |
262 | | cached_powers_f: CACHED_POWERS_F_64, |
263 | | cached_powers_e: CACHED_POWERS_E_64, |
264 | | min_power: (-348), |
265 | | }; |
266 | 0 | unsafe { dtoa(buf, self) } |
267 | 0 | } Unexecuted instantiation: <f64 as dtoa::private::Sealed>::write Unexecuted instantiation: <f64 as dtoa::private::Sealed>::write |
268 | | } |
269 | | |
270 | | //////////////////////////////////////////////////////////////////////////////// |
271 | | |
272 | | const MAX_DECIMAL_PLACES: isize = 324; |
273 | | |
274 | | static DEC_DIGITS_LUT: [u8; 200] = *b"\ |
275 | | 0001020304050607080910111213141516171819\ |
276 | | 2021222324252627282930313233343536373839\ |
277 | | 4041424344454647484950515253545556575859\ |
278 | | 6061626364656667686970717273747576777879\ |
279 | | 8081828384858687888990919293949596979899"; |
280 | | |
281 | | // 10^-36, 10^-28, ..., 10^52 |
282 | | #[rustfmt::skip] |
283 | | static CACHED_POWERS_F_32: [u32; 12] = [ |
284 | | 0xaa242499, 0xfd87b5f3, 0xbce50865, 0x8cbccc09, |
285 | | 0xd1b71759, 0x9c400000, 0xe8d4a510, 0xad78ebc6, |
286 | | 0x813f3979, 0xc097ce7c, 0x8f7e32ce, 0xd5d238a5, |
287 | | ]; |
288 | | |
289 | | #[rustfmt::skip] |
290 | | static CACHED_POWERS_E_32: [i16; 12] = [ |
291 | | -151, -125, -98, -71, -45, -18, 8, 35, 62, 88, 115, 141, |
292 | | ]; |
293 | | |
294 | | // 10^-348, 10^-340, ..., 10^340 |
295 | | #[rustfmt::skip] |
296 | | static CACHED_POWERS_F_64: [u64; 87] = [ |
297 | | 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, |
298 | | 0x8b16fb203055ac76, 0xcf42894a5dce35ea, |
299 | | 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, |
300 | | 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, |
301 | | 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, |
302 | | 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, |
303 | | 0xea9c227723ee8bcb, 0xaecc49914078536d, |
304 | | 0x823c12795db6ce57, 0xc21094364dfb5637, |
305 | | 0x9096ea6f3848984f, 0xd77485cb25823ac7, |
306 | | 0xa086cfcd97bf97f4, 0xef340a98172aace5, |
307 | | 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, |
308 | | 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, |
309 | | 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, |
310 | | 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8, |
311 | | 0x87625f056c7c4a8b, 0xc9bcff6034c13053, |
312 | | 0x964e858c91ba2655, 0xdff9772470297ebd, |
313 | | 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, |
314 | | 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, |
315 | | 0xcdb02555653131b6, 0x993fe2c6d07b7fac, |
316 | | 0xe45c10c42a2b3b06, 0xaa242499697392d3, |
317 | | 0xfd87b5f28300ca0e, 0xbce5086492111aeb, |
318 | | 0x8cbccc096f5088cc, 0xd1b71758e219652c, |
319 | | 0x9c40000000000000, 0xe8d4a51000000000, |
320 | | 0xad78ebc5ac620000, 0x813f3978f8940984, |
321 | | 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, |
322 | | 0xd5d238a4abe98068, 0x9f4f2726179a2245, |
323 | | 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, |
324 | | 0x83c7088e1aab65db, 0xc45d1df942711d9a, |
325 | | 0x924d692ca61be758, 0xda01ee641a708dea, |
326 | | 0xa26da3999aef774a, 0xf209787bb47d6b85, |
327 | | 0xb454e4a179dd1877, 0x865b86925b9bc5c2, |
328 | | 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3, |
329 | | 0xde469fbd99a05fe3, 0xa59bc234db398c25, |
330 | | 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, |
331 | | 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, |
332 | | 0x98165af37b2153df, 0xe2a0b5dc971f303a, |
333 | | 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, |
334 | | 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a, |
335 | | 0xd01fef10a657842c, 0x9b10a4e5e9913129, |
336 | | 0xe7109bfba19c0c9d, 0xac2820d9623bf429, |
337 | | 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, |
338 | | 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, |
339 | | 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, |
340 | | 0xaf87023b9bf0ee6b, |
341 | | ]; |
342 | | |
343 | | #[rustfmt::skip] |
344 | | static CACHED_POWERS_E_64: [i16; 87] = [ |
345 | | -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, |
346 | | -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, |
347 | | -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, |
348 | | -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, |
349 | | -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, |
350 | | 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, |
351 | | 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, |
352 | | 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, |
353 | | 907, 933, 960, 986, 1013, 1039, 1066, |
354 | | ]; |