1#![doc(html_root_url = "https://docs.rs/dtoa/1.0.10")]
35#![no_std]
36#![allow(
37 clippy::cast_lossless,
38 clippy::cast_possible_truncation,
39 clippy::cast_possible_wrap,
40 clippy::cast_precision_loss,
41 clippy::cast_sign_loss,
42 clippy::doc_markdown,
43 clippy::expl_impl_clone_on_copy,
44 clippy::if_not_else,
45 clippy::missing_errors_doc,
46 clippy::must_use_candidate,
47 clippy::needless_doctest_main,
48 clippy::range_plus_one,
49 clippy::semicolon_if_nothing_returned, clippy::shadow_unrelated,
51 clippy::suspicious_else_formatting,
52 clippy::transmute_float_to_int,
53 clippy::unreadable_literal,
54 clippy::unseparated_literal_suffix
55)]
56
57#[macro_use]
58mod diyfp;
59#[macro_use]
60mod dtoa;
61
62use core::mem::{self, MaybeUninit};
63use core::slice;
64use core::str;
65#[cfg(feature = "no-panic")]
66use no_panic::no_panic;
67
68const NAN: &str = "NaN";
69const INFINITY: &str = "inf";
70const NEG_INFINITY: &str = "-inf";
71
72pub struct Buffer {
83 bytes: [MaybeUninit<u8>; 25],
84}
85
86impl Default for Buffer {
87 #[inline]
88 fn default() -> Buffer {
89 Buffer::new()
90 }
91}
92
93impl Copy for Buffer {}
94
95impl Clone for Buffer {
96 #[inline]
97 #[allow(clippy::non_canonical_clone_impl)] fn clone(&self) -> Self {
99 Buffer::new()
100 }
101}
102
103impl Buffer {
104 #[inline]
107 #[cfg_attr(feature = "no-panic", no_panic)]
108 pub fn new() -> Buffer {
109 let bytes = [MaybeUninit::<u8>::uninit(); 25];
110 Buffer { bytes }
111 }
112
113 #[cfg_attr(feature = "no-panic", no_panic)]
125 pub fn format<F: Float>(&mut self, value: F) -> &str {
126 if value.is_nonfinite() {
127 value.format_nonfinite()
128 } else {
129 self.format_finite(value)
130 }
131 }
132
133 #[cfg_attr(feature = "no-panic", no_panic)]
149 pub fn format_finite<F: Float>(&mut self, value: F) -> &str {
150 value.write(self)
151 }
152}
153
154pub trait Float: private::Sealed {}
158
159impl Float for f32 {}
160impl Float for f64 {}
161
162mod private {
164 pub trait Sealed: Copy {
165 fn is_nonfinite(self) -> bool;
166 fn format_nonfinite(self) -> &'static str;
167 fn write(self, buf: &mut crate::Buffer) -> &str;
168 }
169}
170
171impl private::Sealed for f32 {
172 #[inline]
173 #[cfg_attr(feature = "no-panic", no_panic)]
174 fn is_nonfinite(self) -> bool {
175 const EXP_MASK: u32 = 0x7f800000;
176 let bits = self.to_bits();
177 bits & EXP_MASK == EXP_MASK
178 }
179
180 #[cold]
181 #[cfg_attr(feature = "no-panic", no_panic)]
182 fn format_nonfinite(self) -> &'static str {
183 const MANTISSA_MASK: u32 = 0x007fffff;
184 const SIGN_MASK: u32 = 0x80000000;
185 let bits = self.to_bits();
186 if bits & MANTISSA_MASK != 0 {
187 NAN
188 } else if bits & SIGN_MASK != 0 {
189 NEG_INFINITY
190 } else {
191 INFINITY
192 }
193 }
194
195 #[inline]
196 fn write(self, buf: &mut Buffer) -> &str {
197 dtoa! {
198 floating_type: f32,
199 significand_type: u32,
200 exponent_type: i32,
201
202 diy_significand_size: 32,
203 significand_size: 23,
204 exponent_bias: 0x7F,
205 mask_type: u32,
206 exponent_mask: 0x7F800000,
207 significand_mask: 0x007FFFFF,
208 hidden_bit: 0x00800000,
209 cached_powers_f: CACHED_POWERS_F_32,
210 cached_powers_e: CACHED_POWERS_E_32,
211 min_power: (-36),
212 };
213 unsafe { dtoa(buf, self) }
214 }
215}
216
217impl private::Sealed for f64 {
218 #[inline]
219 #[cfg_attr(feature = "no-panic", no_panic)]
220 fn is_nonfinite(self) -> bool {
221 const EXP_MASK: u64 = 0x7ff0000000000000;
222 let bits = self.to_bits();
223 bits & EXP_MASK == EXP_MASK
224 }
225
226 #[cold]
227 #[cfg_attr(feature = "no-panic", no_panic)]
228 fn format_nonfinite(self) -> &'static str {
229 const MANTISSA_MASK: u64 = 0x000fffffffffffff;
230 const SIGN_MASK: u64 = 0x8000000000000000;
231 let bits = self.to_bits();
232 if bits & MANTISSA_MASK != 0 {
233 NAN
234 } else if bits & SIGN_MASK != 0 {
235 NEG_INFINITY
236 } else {
237 INFINITY
238 }
239 }
240
241 #[inline]
242 fn write(self, buf: &mut Buffer) -> &str {
243 dtoa! {
244 floating_type: f64,
245 significand_type: u64,
246 exponent_type: isize,
247
248 diy_significand_size: 64,
249 significand_size: 52,
250 exponent_bias: 0x3FF,
251 mask_type: u64,
252 exponent_mask: 0x7FF0000000000000,
253 significand_mask: 0x000FFFFFFFFFFFFF,
254 hidden_bit: 0x0010000000000000,
255 cached_powers_f: CACHED_POWERS_F_64,
256 cached_powers_e: CACHED_POWERS_E_64,
257 min_power: (-348),
258 };
259 unsafe { dtoa(buf, self) }
260 }
261}
262
263const MAX_DECIMAL_PLACES: isize = 324;
266
267static DEC_DIGITS_LUT: [u8; 200] = *b"\
268 0001020304050607080910111213141516171819\
269 2021222324252627282930313233343536373839\
270 4041424344454647484950515253545556575859\
271 6061626364656667686970717273747576777879\
272 8081828384858687888990919293949596979899";
273
274#[rustfmt::skip]
276static CACHED_POWERS_F_32: [u32; 12] = [
277 0xaa242499, 0xfd87b5f3, 0xbce50865, 0x8cbccc09,
278 0xd1b71759, 0x9c400000, 0xe8d4a510, 0xad78ebc6,
279 0x813f3979, 0xc097ce7c, 0x8f7e32ce, 0xd5d238a5,
280];
281
282#[rustfmt::skip]
283static CACHED_POWERS_E_32: [i16; 12] = [
284 -151, -125, -98, -71, -45, -18, 8, 35, 62, 88, 115, 141,
285];
286
287#[rustfmt::skip]
289static CACHED_POWERS_F_64: [u64; 87] = [
290 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76,
291 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
292 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
293 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
294 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c,
295 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
296 0xea9c227723ee8bcb, 0xaecc49914078536d,
297 0x823c12795db6ce57, 0xc21094364dfb5637,
298 0x9096ea6f3848984f, 0xd77485cb25823ac7,
299 0xa086cfcd97bf97f4, 0xef340a98172aace5,
300 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b,
301 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
302 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6,
303 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
304 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
305 0x964e858c91ba2655, 0xdff9772470297ebd,
306 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94,
307 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
308 0xcdb02555653131b6, 0x993fe2c6d07b7fac,
309 0xe45c10c42a2b3b06, 0xaa242499697392d3,
310 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
311 0x8cbccc096f5088cc, 0xd1b71758e219652c,
312 0x9c40000000000000, 0xe8d4a51000000000,
313 0xad78ebc5ac620000, 0x813f3978f8940984,
314 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70,
315 0xd5d238a4abe98068, 0x9f4f2726179a2245,
316 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
317 0x83c7088e1aab65db, 0xc45d1df942711d9a,
318 0x924d692ca61be758, 0xda01ee641a708dea,
319 0xa26da3999aef774a, 0xf209787bb47d6b85,
320 0xb454e4a179dd1877, 0x865b86925b9bc5c2,
321 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
322 0xde469fbd99a05fe3, 0xa59bc234db398c25,
323 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
324 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5,
325 0x98165af37b2153df, 0xe2a0b5dc971f303a,
326 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c,
327 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
328 0xd01fef10a657842c, 0x9b10a4e5e9913129,
329 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
330 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d,
331 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
332 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9,
333 0xaf87023b9bf0ee6b,
334];
335
336#[rustfmt::skip]
337static CACHED_POWERS_E_64: [i16; 87] = [
338 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
339 -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
340 -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
341 -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
342 -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
343 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
344 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
345 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
346 907, 933, 960, 986, 1013, 1039, 1066,
347];