1#![no_std]
45#![doc(html_root_url = "https://docs.rs/zmij/1.0.23")]
46#![deny(unsafe_op_in_unsafe_fn)]
47#![allow(non_camel_case_types, non_snake_case)]
48#![allow(
49 clippy::blocks_in_conditions,
50 clippy::cast_possible_truncation,
51 clippy::cast_possible_wrap,
52 clippy::cast_ptr_alignment,
53 clippy::cast_sign_loss,
54 clippy::doc_markdown,
55 clippy::incompatible_msrv,
56 clippy::items_after_statements,
57 clippy::manual_ilog2,
58 clippy::many_single_char_names,
59 clippy::modulo_one,
60 clippy::must_use_candidate,
61 clippy::needless_doctest_main,
62 clippy::needless_late_init,
63 clippy::never_loop,
64 clippy::redundant_else,
65 clippy::similar_names,
66 clippy::too_many_arguments,
67 clippy::too_many_lines,
68 clippy::unreadable_literal,
69 clippy::used_underscore_items,
70 clippy::while_immutable_condition,
71 clippy::wildcard_imports
72)]
73
74use self::{const_array::ConstArray, const_range::ConstRange};
75
76#[cfg(any())]
77#[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
78mod stdarch_x86;
79#[cfg(test)]
80mod tests;
81mod traits;
82
83mod const_array;
84mod const_range;
85
86#[cfg(any())]
87#[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
88use crate::stdarch_x86::{
89 __m128i, _mm_add_epi64, _mm_cmpgt_epi8, _mm_cvtsi128_si64, _mm_load_si128, _mm_movemask_epi8,
90 _mm_mul_epu32, _mm_mulhi_epu16, _mm_mullo_epi16, _mm_or_si128, _mm_set_epi64x,
91 _mm_setzero_si128, _mm_srli_epi64,
92};
93#[cfg(any())]
94#[cfg(all(
95 target_arch = "x86_64",
96 target_feature = "sse2",
97 target_feature = "sse4.1",
98 not(miri)
99))]
100use crate::stdarch_x86::{
101 _mm_insert_epi64, _mm_mullo_epi32, _mm_shuffle_epi8, _mm_srli_epi32, _mm_storeu_si128,
102};
103#[cfg(any())]
104#[cfg(all(
105 target_arch = "x86_64",
106 target_feature = "sse2",
107 not(target_feature = "sse4.1"),
108 not(miri)
109))]
110use crate::stdarch_x86::{
111 _mm_shuffle_epi32, _mm_slli_epi16, _mm_slli_epi32, _mm_srli_epi16, _mm_sub_epi16, _MM_SHUFFLE,
112};
113use crate::traits::Float as _;
114#[cfg(any())] #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
116use core::arch::aarch64::{
117 int16x8_t, int32x2_t, int32x4_t, uint16x8_t, uint64x1_t, uint8x16_t, vaddq_u16, vcgtzq_s8,
118 vcombine_s32, vcreate_u64, vdup_n_s32, vdupq_n_s8, vdupq_n_u8, vget_lane_u64, vget_low_u8,
119 vld1q_u8, vmla_n_s32, vmlaq_n_s16, vmlaq_n_s32, vorrq_u8, vqdmulh_n_s32, vqdmulhq_n_s16,
120 vqdmulhq_n_s32, vqtbl1q_u8, vreinterpret_s32_u32, vreinterpret_s32_u64, vreinterpret_u16_s32,
121 vreinterpret_u32_s32, vreinterpret_u64_u8, vreinterpretq_s16_s32, vreinterpretq_s32_u32,
122 vreinterpretq_s8_u8, vreinterpretq_u16_s8, vreinterpretq_u16_u8, vreinterpretq_u64_u8,
123 vreinterpretq_u8_s16, vreinterpretq_u8_u64, vrev64q_u8, vsetq_lane_u64, vshll_n_u16,
124 vshr_n_u32, vshrn_n_u16, vst1q_u8,
125};
126#[cfg(any())]
127#[cfg(all(any(target_arch = "aarch64", target_arch = "x86_64"), not(miri)))]
128use core::arch::asm;
129use core::mem::{self, MaybeUninit};
130use core::ops::RangeInclusive;
131use core::ptr;
132use core::slice;
133use core::str;
134#[cfg(feature = "no-panic")]
135use no_panic::no_panic;
136
137const BUFFER_SIZE: usize = 24;
138const NAN: &str = "NaN";
139const INFINITY: &str = "inf";
140const NEG_INFINITY: &str = "-inf";
141
142struct AArch64Mem<const VALUE: u64> {
145 #[cfg(target_arch = "aarch64")]
146 value: u64,
147}
148
149impl<const VALUE: u64> AArch64Mem<VALUE> {
150 const fn new() -> Self {
151 AArch64Mem {
152 #[cfg(target_arch = "aarch64")]
153 value: VALUE,
154 }
155 }
156
157 #[cfg_attr(not(target_arch = "aarch64"), allow(clippy::unused_self))]
158 const fn get(&self) -> u64 {
159 #[cfg(target_arch = "aarch64")]
160 {
161 self.value
162 }
163
164 #[cfg(not(target_arch = "aarch64"))]
165 {
166 VALUE
167 }
168 }
169}
170
171#[derive(#[automatically_derived]
impl ::core::marker::Copy for uint128 { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for uint128 { }
#[automatically_derived]
impl ::core::clone::Clone for uint128 {
#[inline]
fn clone(&self) -> uint128 {
let _: ::core::clone::AssertParamIsClone<u64>;
*self
}
}Clone)]
172#[cfg_attr(test, derive(Debug, PartialEq))]
173struct uint128 {
174 hi: u64,
175 lo: u64,
176}
177
178const USE_UMUL128_HI64: bool = falsecfg!(target_vendor = "apple");
180
181const fn umul128(x: u64, y: u64) -> u128 {
183 x as u128 * y as u128
184}
185
186#[inline]
187const fn umul128_hi64(x: u64, y: u64) -> u64 {
188 (umul128(x, y) >> 64) as u64
189}
190
191#[cfg_attr(feature = "no-panic", no_panic)]
193#[rustfmt::skip]
194const
195fn umul128_add_hi64(x: u64, y: u64, c: u64) -> u64 {
196 mod u128 {
197 pub(crate) const fn from(v: u64) -> u128 {
198 v as _
199 }
200 }
201
202 ((u128::from(x) * u128::from(y) + u128::from(c)) >> 64) as u64
203}
204
205#[cfg_attr(feature = "no-panic", no_panic)]
206#[rustfmt::skip]
207const
208fn umul192_hi128(x_hi: u64, x_lo: u64, y: u64) -> uint128 {
209 mod u64 {
210 pub(crate) const fn from(v: bool) -> u64 {
211 v as _
212 }
213 }
214
215 let p = umul128(x_hi, y);
216 let lo = (p as u64).wrapping_add((umul128(x_lo, y) >> 64) as u64);
217 uint128 {
218 hi: (p >> 64) as u64 + u64::from(lo < p as u64),
219 lo,
220 }
221}
222
223#[cfg_attr(feature = "no-panic", no_panic)]
225#[rustfmt::skip]
226const
227fn div10(x: u64) -> u64 {
228 if true {
if !(x < (1 << 62)) {
::core::panicking::panic("assertion failed: x < (1 << 62)")
};
};debug_assert!(x < (1 << 62));
229 const DIV10_SIG64: u64 = (1 << 63) / 5 + 1;
231 umul128_hi64(x, DIV10_SIG64)
232}
233
234const fn compute_dec_exp(bin_exp: i32, regular: bool) -> i32 {
237 if true {
if !(bin_exp >= -1334 && bin_exp <= 2620) {
::core::panicking::panic("assertion failed: bin_exp >= -1334 && bin_exp <= 2620")
};
};debug_assert!(bin_exp >= -1334 && bin_exp <= 2620);
238 const LOG10_3_OVER_4_SIG: i32 = 131_072;
240 const LOG10_2_SIG: i32 = 315_653;
242 const LOG10_2_EXP: i32 = 20;
243 (bin_exp * LOG10_2_SIG - !regular as i32 * LOG10_3_OVER_4_SIG) >> LOG10_2_EXP
244}
245
246#[derive(#[automatically_derived]
impl<F: ::core::clone::Clone> ::core::clone::Clone for ConstFloat<F> {
#[inline]
fn clone(&self) -> ConstFloat<F> {
ConstFloat(::core::clone::Clone::clone(&self.0))
}
}Clone, #[automatically_derived]
impl<F: ::core::marker::Copy> ::core::marker::Copy for ConstFloat<F> { }Copy)]
247struct ConstFloat<F>(F);
248
249impl<F: traits::Float> traits::Float for ConstFloat<F> {
250 const MANTISSA_DIGITS: u32 = F::MANTISSA_DIGITS;
251 const MIN_10_EXP: i32 = F::MIN_10_EXP;
252 const MAX_10_EXP: i32 = F::MAX_10_EXP;
253 const MAX_DIGITS10: u32 = F::MAX_DIGITS10;
254}
255
256trait FloatTraits: traits::Float {
257 const FIXED_DEC_EXP: RangeInclusive<i32>;
259
260 const NUM_BITS: i32;
261 const NUM_SIG_BITS: i32 = Self::MANTISSA_DIGITS as i32 - 1;
262 const NUM_EXP_BITS: i32 = Self::NUM_BITS - Self::NUM_SIG_BITS - 1;
263 const EXP_MASK: i32 = (1 << Self::NUM_EXP_BITS) - 1;
264 const EXP_BIAS: i32 = (1 << (Self::NUM_EXP_BITS - 1)) - 1;
265 const EXP_OFFSET: i32 = Self::EXP_BIAS + Self::NUM_SIG_BITS;
266
267 type SigType: traits::UInt;
268 const IMPLICIT_BIT: Self::SigType;
269
270 type DecDigitsType: Copy;
271
272 #[cfg(any())]
273 #[cfg(any(
274 all(target_arch = "aarch64", target_feature = "neon", not(miri)),
275 all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)),
276 ))]
277 type DecUnshuffledType;
278}
279
280macro_rules! impl_for_floats {
281 ({
282 #[common]
283 {$($common_items:tt)*}
284 $($rest:tt)*
285 }) => {
286 const _: () = {
287 $($common_items)*
288 impl_for_floats! {{ $($rest)* }}
289 };
290 };
291 ({
292 {$($f32_items:tt)*}
293 {$($f64_items:tt)*}
294
295 $($imp:tt)*
296 }) => {
297 const _: () = {
298 $($f32_items)*
299 $($imp)*
300 };
301 const _: () = {
302 $($f64_items)*
303 $($imp)*
304 };
305 };
306}
307
308const _: () =
{
use f32 as FLOAT;
type SelfSigType = <ConstFloat<FLOAT> as FloatTraits>::SigType;
impl ConstFloat<FLOAT> {
const fn SigType_from(v: u8) -> SelfSigType { v as _ }
}
struct SigTypeIntoU64(SelfSigType);
impl SigTypeIntoU64 {
const fn into(self) -> u64 { self.0 as _ }
}
#[rustfmt::skip]
impl ConstFloat<FLOAT> {
#[inline]
const fn to_bits(self) -> SelfSigType { self.0.to_bits() }
const fn is_negative(bits: SelfSigType) -> bool {
(bits >> (Self::NUM_BITS - 1)) != Self::SigType_from(0)
}
const fn get_sig(bits: SelfSigType) -> SelfSigType {
bits & (Self::IMPLICIT_BIT - Self::SigType_from(1))
}
const fn get_exp(bits: SelfSigType) -> i64 {
SigTypeIntoU64(bits << 1u8 >> (Self::NUM_SIG_BITS + 1)).into()
as i64
}
}
};
const _: () =
{
use f64 as FLOAT;
type SelfSigType = <ConstFloat<FLOAT> as FloatTraits>::SigType;
impl ConstFloat<FLOAT> {
const fn SigType_from(v: u8) -> SelfSigType { v as _ }
}
struct SigTypeIntoU64(SelfSigType);
impl SigTypeIntoU64 {
const fn into(self) -> u64 { self.0 as _ }
}
#[rustfmt::skip]
impl ConstFloat<FLOAT> {
#[inline]
const fn to_bits(self) -> SelfSigType { self.0.to_bits() }
const fn is_negative(bits: SelfSigType) -> bool {
(bits >> (Self::NUM_BITS - 1)) != Self::SigType_from(0)
}
const fn get_sig(bits: SelfSigType) -> SelfSigType {
bits & (Self::IMPLICIT_BIT - Self::SigType_from(1))
}
const fn get_exp(bits: SelfSigType) -> i64 {
SigTypeIntoU64(bits << 1u8 >> (Self::NUM_SIG_BITS + 1)).into()
as i64
}
}
};impl_for_floats!({
309 {
310 use f32 as FLOAT;
311 }
312 {
313 use f64 as FLOAT;
314 }
315
316 type SelfSigType = <ConstFloat<FLOAT> as FloatTraits>::SigType;
317
318 impl ConstFloat<FLOAT> {
319 const fn SigType_from(v: u8) -> SelfSigType {
320 v as _
321 }
322 }
323
324 struct SigTypeIntoU64(SelfSigType);
325
326 impl SigTypeIntoU64 {
327 const fn into(self) -> u64 {
328 self.0 as _
329 }
330 }
331
332 #[rustfmt::skip]
333impl ConstFloat<FLOAT> {
334 #[inline]
335 const fn to_bits(self) -> SelfSigType {
336 self.0.to_bits()
337 }
338
339 const fn is_negative(bits: SelfSigType) -> bool {
340 (bits >> (Self::NUM_BITS - 1)) != Self::SigType_from(0)
341 }
342
343 const fn get_sig(bits: SelfSigType) -> SelfSigType {
344 bits & (Self::IMPLICIT_BIT - Self::SigType_from(1))
345 }
346
347 const fn get_exp(bits: SelfSigType) -> i64 {
348 SigTypeIntoU64(bits << 1u8 >> (Self::NUM_SIG_BITS + 1)).into() as i64
349 }
350
351 }
356});
357
358#[rustfmt::skip]
359const _: () = {
360 type f32 = ConstFloat<::core::primitive::f32>;
361
362impl FloatTraits for f32 {
363 const FIXED_DEC_EXP: RangeInclusive<i32> = -6..=12;
365
366 const NUM_BITS: i32 = 32;
367 const IMPLICIT_BIT: u32 = 1 << Self::NUM_SIG_BITS;
368
369 type SigType = u32;
370
371 type DecDigitsType = u64;
372
373 #[cfg(any())]
374 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
375 type DecUnshuffledType = uint8x16_t;
376 #[cfg(any())]
377 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)))]
378 type DecUnshuffledType = __m128i;
379}
380};
381
382impl ConstFloat<f32> {
383 #[inline]
384 #[rustfmt::skip]
385 const
386 fn to_digits(value: u64, d: &Data) -> DecDigits<Self> {
387 Self::
388 to_digits_32(value, d)
389 }
390
391 #[inline]
392 #[rustfmt::skip]
393 const
394 unsafe fn write_exp_float_simd(
395 buffer: *mut u8,
396 dig: &DecDigits<Self>,
397 last_digit: i32,
398 has_last_digit: bool,
399 has_extra_digit: bool,
400 exp_data: u64,
401 d: &Data,
402 ) -> *mut u8 {
403 unsafe {
404 Self::
405 write_exp_float_simd_32(
406 buffer,
407 dig,
408 last_digit,
409 has_last_digit,
410 has_extra_digit,
411 exp_data,
412 d,
413 )
414 }
415 }
416}
417
418#[rustfmt::skip]
419const _: () = {
420 type f64 = ConstFloat<::core::primitive::f64>;
421
422impl FloatTraits for f64 {
423 const FIXED_DEC_EXP: RangeInclusive<i32> = -5..=15;
425
426 const NUM_BITS: i32 = 64;
427 const IMPLICIT_BIT: u64 = 1 << Self::NUM_SIG_BITS;
428
429 type SigType = u64;
430
431 #[cfg(any())]
432 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
433 type DecDigitsType = uint16x8_t;
434 #[cfg(any())]
435 #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
436 type DecDigitsType = __m128i;
437 type DecDigitsType = [u64; 2];
444
445 #[cfg(any())]
446 #[cfg(any(
447 all(target_arch = "aarch64", target_feature = "neon", not(miri)),
448 all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)),
449 ))]
450 type DecUnshuffledType = ();
451}
452};
453
454impl ConstFloat<f64> {
455 #[inline]
456 #[rustfmt::skip]
457 const
458 fn to_digits(value: u64, d: &Data) -> DecDigits<Self> {
459 Self::
460 to_digits_64(value, d)
461 }
462
463 #[inline]
464 #[rustfmt::skip]
465 const
466 unsafe fn write_exp_float_simd(
467 _buffer: *mut u8,
468 _dig: &DecDigits<Self>,
469 _last_digit: i32,
470 _has_last_digit: bool,
471 _has_extra_digit: bool,
472 _exp_data: u64,
473 _d: &Data,
474 ) -> *mut u8 {
475 ptr::null_mut()
476 }
477}
478
479#[rustfmt::skip]
480const POW10_MINOR: [u64; 28] = [
481 0x8000000000000000, 0xa000000000000000, 0xc800000000000000,
482 0xfa00000000000000, 0x9c40000000000000, 0xc350000000000000,
483 0xf424000000000000, 0x9896800000000000, 0xbebc200000000000,
484 0xee6b280000000000, 0x9502f90000000000, 0xba43b74000000000,
485 0xe8d4a51000000000, 0x9184e72a00000000, 0xb5e620f480000000,
486 0xe35fa931a0000000, 0x8e1bc9bf04000000, 0xb1a2bc2ec5000000,
487 0xde0b6b3a76400000, 0x8ac7230489e80000, 0xad78ebc5ac620000,
488 0xd8d726b7177a8000, 0x878678326eac9000, 0xa968163f0a57b400,
489 0xd3c21bcecceda100, 0x84595161401484a0, 0xa56fa5b99019a5c8,
490 0xcecb8f27f4200f3a,
491];
492
493#[rustfmt::skip]
494const POW10_MAJOR: [uint128; 23] = [
495 uint128 { hi: 0xaf8e5410288e1b6f, lo: 0x07ecf0ae5ee44dda }, uint128 { hi: 0xb1442798f49ffb4a, lo: 0x99cd11cfdf41779d }, uint128 { hi: 0xb2fe3f0b8599ef07, lo: 0x861fa7e6dcb4aa15 }, uint128 { hi: 0xb4bca50b065abe63, lo: 0x0fed077a756b53aa }, uint128 { hi: 0xb67f6455292cbf08, lo: 0x1a3bc84c17b1d543 }, uint128 { hi: 0xb84687c269ef3bfb, lo: 0x3d5d514f40eea742 }, uint128 { hi: 0xba121a4650e4ddeb, lo: 0x92f34d62616ce413 }, uint128 { hi: 0xbbe226efb628afea, lo: 0x890489f70a55368c }, uint128 { hi: 0xbdb6b8e905cb600f, lo: 0x5400e987bbc1c921 }, uint128 { hi: 0xbf8fdb78849a5f96, lo: 0xde98520472bdd034 }, uint128 { hi: 0xc16d9a0095928a27, lo: 0x75b7053c0f178294 }, uint128 { hi: 0xc350000000000000, lo: 0x0000000000000000 }, uint128 { hi: 0xc5371912364ce305, lo: 0x6c28000000000000 }, uint128 { hi: 0xc722f0ef9d80aad6, lo: 0x424d3ad2b7b97ef6 }, uint128 { hi: 0xc913936dd571c84c, lo: 0x03bc3a19cd1e38ea }, uint128 { hi: 0xcb090c8001ab551c, lo: 0x5cadf5bfd3072cc6 }, uint128 { hi: 0xcd036837130890a1, lo: 0x36dba887c37a8c10 }, uint128 { hi: 0xcf02b2c21207ef2e, lo: 0x94f967e45e03f4bc }, uint128 { hi: 0xd106f86e69d785c7, lo: 0xe13336d701beba52 }, uint128 { hi: 0xd31045a8341ca07c, lo: 0x1ede48111209a051 }, uint128 { hi: 0xd51ea6fa85785631, lo: 0x552a74227f3ea566 }, uint128 { hi: 0xd732290fbacaf133, lo: 0xa97c177947ad4096 }, uint128 { hi: 0xd94ad8b1c7380874, lo: 0x18375281ae7822bc }, ];
519
520#[rustfmt::skip]
521const POW10_FIXUPS: [u32; 20] = [
522 0x0a4e363f, 0x00001840, 0x00006400, 0x24200040, 0x00000000,
523 0x0c000000, 0x82c81380, 0x5e4ce01f, 0xd730f60f, 0x0000001b,
524 0x00000000, 0xcdf7fffc, 0x6e8201d8, 0x40cd3fd1, 0xdb642501,
525 0x00000d0d, 0x14042400, 0x53713840, 0x11781db4, 0x00000000,
526];
527
528#[repr(C, align(64))]
530struct Pow10SignificandTable {
531 data: [u64; if Self::COMPRESS {
532 0
533 } else {
534 Self::NUM_POW10S * 2
535 }],
536}
537
538impl Pow10SignificandTable {
539 const COMPRESS: bool = falsecfg!(opt_level = "s");
540 const SPLIT_TABLES: bool = !Self::COMPRESS && falsecfg!(target_arch = "aarch64");
541 const NUM_POW10S: usize = 618;
542
543 #[inline]
545 const fn compute(i: u32) -> uint128 {
546 const STRIDE: u32 = POW10_MINOR.len() as u32;
547 let m = unsafe { *POW10_MINOR.as_ptr().add(((i + 10) % STRIDE) as usize) };
548 let h = unsafe { *POW10_MAJOR.as_ptr().add(((i + 10) / STRIDE) as usize) };
549
550 let h1 = umul128_hi64(h.lo, m);
551
552 let c0 = h.lo.wrapping_mul(m);
553 let c1 = h1.wrapping_add(h.hi.wrapping_mul(m));
554 let c2 = (c1 < h1) as u64 + umul128_hi64(h.hi, m);
555
556 let mut result = if (c2 >> 63) != 0 {
557 uint128 { hi: c2, lo: c1 }
558 } else {
559 uint128 {
560 hi: (c2 << 1) | (c1 >> 63),
561 lo: (c1 << 1) | (c0 >> 63),
562 }
563 };
564 result.lo -=
565 ((unsafe { *POW10_FIXUPS.as_ptr().add((i >> 5) as usize) } >> (i & 31)) & 1) as u64;
566 result
567 }
568
569 const fn new() -> Self {
570 let mut data = [0; if Self::COMPRESS {
571 0
572 } else {
573 Self::NUM_POW10S * 2
574 }];
575
576 let mut i = 0;
577 while i < Self::NUM_POW10S && !Self::COMPRESS {
578 let result = Self::compute(i as u32);
579 if Self::SPLIT_TABLES {
580 data[Self::NUM_POW10S - i - 1] = result.hi;
581 data[Self::NUM_POW10S * 2 - i - 1] = result.lo;
582 } else {
583 data[i * 2] = result.hi;
584 data[i * 2 + 1] = result.lo;
585 }
586 i += 1;
587 }
588
589 Pow10SignificandTable { data }
590 }
591
592 #[inline]
593 #[rustfmt::skip]
594 const
595 unsafe fn get_unchecked(&self, dec_exp: i32) -> uint128 {
596 const DEC_EXP_MIN: i32 = -293;
597 let i = dec_exp - DEC_EXP_MIN;
598 if Self::COMPRESS {
599 return Self::compute(i as u32);
600 }
601 if !Self::SPLIT_TABLES {
602 let p = unsafe { self.data.as_ptr().add((i * 2) as usize) };
603 return uint128 {
604 hi: unsafe { *p },
605 lo: unsafe { *p.add(1) },
606 };
607 }
608
609 unsafe {
610 #[allow(unused_mut)]
620 let mut p = self
621 .data
622 .as_ptr()
623 .offset(Self::NUM_POW10S as isize + DEC_EXP_MIN as isize);
624 uint128 {
629 hi: *p.offset(!(dec_exp as isize)),
630 lo: *p.offset(!(dec_exp as isize) + Self::NUM_POW10S as isize),
631 }
632 }
633 }
634
635 #[cfg(test)]
636 fn get(&self, dec_exp: i32) -> uint128 {
637 const DEC_EXP_MIN: i32 = -292;
638 assert!((DEC_EXP_MIN..DEC_EXP_MIN + Self::NUM_POW10S as i32).contains(&dec_exp));
639 unsafe { self.get_unchecked(dec_exp) }
640 }
641}
642
643#[inline]
654const fn compute_exp_shift(bin_exp: i32, dec_exp: i32) -> u8 {
655 if true {
if !(dec_exp >= -350 && dec_exp <= 350) {
::core::panicking::panic("assertion failed: dec_exp >= -350 && dec_exp <= 350")
};
};debug_assert!(dec_exp >= -350 && dec_exp <= 350);
656 const LOG2_POW10_SIG: i32 = 217_707;
658 const LOG2_POW10_EXP: i32 = 16;
659 let pow10_bin_exp = (-dec_exp * LOG2_POW10_SIG) >> LOG2_POW10_EXP;
661 (bin_exp + pow10_bin_exp + 1) as u8
663}
664
665struct ExpShiftTable {
666 data: ConstArray<
667 [u8; if Self::ENABLE {
668 <ConstFloat<f64> as FloatTraits>::EXP_MASK as usize + 1
669 } else {
670 0
671 }],
672 >,
673}
674
675const _: () = {
676 type f64 = ConstFloat<::core::primitive::f64>;
677
678 #[rustfmt::skip]
679impl ExpShiftTable {
680 const ENABLE: bool = truecfg!(not(opt_level = "s"));
681 const EXTRA_SHIFT: usize = 6;
684
685 const fn new() -> Self {
686 let mut data = [0u8; if Self::ENABLE {
687 f64::EXP_MASK as usize + 1
688 } else {
689 0
690 }];
691
692 let mut raw_exp = 0;
693 while raw_exp < data.len() && Self::ENABLE {
694 let mut bin_exp = raw_exp as i32 - f64::EXP_OFFSET;
695 if raw_exp == 0 {
696 bin_exp += 1;
697 }
698 let dec_exp = compute_dec_exp(bin_exp, true);
699 data[raw_exp] =
700 compute_exp_shift(bin_exp, dec_exp + 1).wrapping_add(Self::EXTRA_SHIFT as u8);
701 raw_exp += 1;
702 }
703
704 let data = ConstArray(data);
705
706 ExpShiftTable { data }
707 }
708}
709};
710
711struct ExpStringTable {
714 data: ConstArray<
715 [u64; if Self::ENABLE {
716 (f64::MAX_10_EXP - Self::MIN_DEC_EXP + 1) as usize
717 } else {
718 0
719 }],
720 >,
721}
722
723impl ExpStringTable {
724 const ENABLE: bool = truecfg!(not(opt_level = "s"));
725 const MIN_DEC_EXP: i32 = f64::MIN_10_EXP - f64::MAX_DIGITS10 as i32;
726 const OFFSET: i32 = -Self::MIN_DEC_EXP;
727
728 const fn new() -> Self {
729 let mut data = [0u64; if Self::ENABLE {
730 (f64::MAX_10_EXP - Self::MIN_DEC_EXP + 1) as usize
731 } else {
732 0
733 }];
734
735 let mut e = Self::MIN_DEC_EXP;
736 while e <= f64::MAX_10_EXP && Self::ENABLE {
737 let abs_e = e.unsigned_abs() as u64;
738 let mut val = abs_e % 10 + b'0' as u64;
739 if abs_e >= 10 {
740 val = (val << 8) | (abs_e / 10 % 10 + b'0' as u64);
741 }
742 if abs_e >= 100 {
743 val = (val << 8) | (abs_e / 100 + b'0' as u64);
744 }
745 let len = 3 + (abs_e >= 10) as u64 + (abs_e >= 100) as u64;
746 data[(e + Self::OFFSET) as usize] = (len << 48)
747 | (val << 16)
748 | (if e >= 0 { b'+' as u64 } else { b'-' as u64 } << 8)
749 | b'e' as u64;
750 e += 1;
751 }
752
753 let data = ConstArray(data);
754
755 ExpStringTable { data }
756 }
757}
758
759#[repr(C, align(16))]
770struct ExpFloatShuffleTable {
771 data: ConstArray<[u8; if Self::ENABLE { 32 * 16 } else { 0 }]>,
772}
773
774struct ExpFloatShuffleTableEntry {
775 #[allow(dead_code)]
785 shuffle: *const u8,
786 length: u8,
787}
788
789impl ExpFloatShuffleTable {
790 #[cfg(any())]
791 const ENABLE: bool = cfg!(any(
792 all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)),
793 all(target_arch = "aarch64", target_feature = "neon", not(miri)),
794 )) && ExpStringTable::ENABLE;
795 const ENABLE: bool = false;
796
797 const EXP_POS: u8 = 8;
798 const LAST_DIGIT_POS: u8 = 12;
799 const POINT_POS: u8 = 13;
800
801 #[rustfmt::skip]
802 const
803 unsafe fn get_entry(
804 &self,
805 num_digits: i32,
806 has_last_digit: bool,
807 has_extra_digit: bool,
808 ) -> ExpFloatShuffleTableEntry {
809 mod i32 {
810 pub(crate) const fn from(v: bool) -> i32 {
811 v as _
812 }
813 }
814 let idx = (num_digits - 1) * 4 + i32::from(has_last_digit) * 2 + i32::from(has_extra_digit);
815 ExpFloatShuffleTableEntry {
816 shuffle: unsafe { self.data.as_ptr().add(idx as usize * 16) },
817 length: *unsafe { self.data.get_unchecked(idx as usize * 16 + 15) },
818 }
819 }
820
821 const fn new() -> Self {
822 let mut data = [0u8; if Self::ENABLE { 32 * 16 } else { 0 }];
823
824 let mut idx = 0;
825 while idx < 32 && Self::ENABLE {
826 let num_digits = (idx >> 2) + 1;
827 let has_last_digit = ((idx >> 1) & 1) != 0;
828 let has_extra_digit = (idx & 1) != 0;
829
830 let out = idx * 16;
831 let mut i = 0;
832 while i < 16 {
833 data[out + i] = 0x80; i += 1;
835 }
836 let leading_digit_pos = if has_extra_digit { 7 } else { 6 };
837 let mut length = 0;
838 if has_last_digit {
839 data[out + length] = leading_digit_pos;
843 length += 1;
844 data[out + length] = Self::POINT_POS;
845 length += 1;
846 let mut i = leading_digit_pos - 1;
847 loop {
848 data[out + length] = i;
849 length += 1;
850 if i == 0 {
851 break;
852 }
853 i -= 1;
854 }
855 data[out + length] = Self::LAST_DIGIT_POS;
856 length += 1;
857 } else {
858 length = num_digits + has_extra_digit as usize;
859 if length == 2 {
861 length = 1;
862 }
863 data[out] = leading_digit_pos;
864 data[out + 1] = Self::POINT_POS;
865 let mut i = 2;
866 while i < length {
867 data[out + i] = leading_digit_pos + 1 - i as u8;
868 i += 1;
869 }
870 }
871 let mut i = 0;
872 while i < 4 {
873 data[out + length] = Self::EXP_POS + i;
874 length += 1;
875 i += 1;
876 }
877 data[out + 15] = length as u8;
878 idx += 1;
879 }
880
881 let data = ConstArray(data);
882
883 ExpFloatShuffleTable { data }
884 }
885}
886
887#[cfg_attr(feature = "no-panic", no_panic)]
897#[rustfmt::skip]
898const
899fn count_trailing_nonzeros(x: u64) -> usize {
900 (70 - ((x.to_le() << 1) | 1).leading_zeros() as usize) / 8
913}
914
915#[repr(C, align(2))]
918struct Digits2([u8; 200]);
919
920static DIGITS2: Digits2 = Digits2(
921 *b"0001020304050607080910111213141516171819\
922 2021222324252627282930313233343536373839\
923 4041424344454647484950515253545556575859\
924 6061626364656667686970717273747576777879\
925 8081828384858687888990919293949596979899",
926);
927
928#[cfg_attr(feature = "no-panic", no_panic)]
931#[rustfmt::skip]
932const
933unsafe fn digits2(value: usize) -> &'static u16 {
934 if true {
if !(value < 100) {
::core::panicking::panic("assertion failed: value < 100")
};
};debug_assert!(value < 100);
935
936 #[allow(clippy::cast_ptr_alignment)]
937 unsafe {
938 &*DIGITS2.0.as_ptr().cast::<u16>().add(value)
939 }
940}
941
942const DIV10K_EXP: i32 = 40;
943const DIV10K_SIG: u32 = ((1u64 << DIV10K_EXP) / 10000 + 1) as u32;
944const NEG10K: u32 = ((1u64 << 32) - 10000) as u32;
945
946const DIV100_EXP: i32 = 19;
947const DIV100_SIG: u32 = (1 << DIV100_EXP) / 100 + 1;
948const NEG100: u32 = (1 << 16) - 100;
957
958const DIV10_EXP: i32 = 10;
965const DIV10_SIG: u32 = (1 << DIV10_EXP) / 10 + 1;
972const NEG10: u32 = (1 << 8) - 10;
976
977const ZEROS: u64 = 0x0101010101010101 * b'0' as u64;
978
979#[rustfmt::skip]
980#[repr(C, align(64))]
981struct Data {
982 threshold: AArch64Mem<1_000_000_000_000_000>,
983 biased_half: AArch64Mem<{ (1 << 63) + 6 }>,
985
986 exp_shifts: ExpShiftTable,
1031 exp_strings: ExpStringTable,
1032 pow10_significands: Pow10SignificandTable,
1033 exp_float_shuffles: ExpFloatShuffleTable,
1034}
1035
1036#[cfg(any())]
1037impl Data {
1038 #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1039 const fn splat64(x: u64) -> u128 {
1040 ((x as u128) << 64) | x as u128
1041 }
1042
1043 #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1044 const fn splat32(x: u32) -> u128 {
1045 Self::splat64(((x as u64) << 32) | x as u64)
1046 }
1047
1048 #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1049 const fn splat16(x: u16) -> u128 {
1050 Self::splat32(((x as u32) << 16) | x as u32)
1051 }
1052
1053 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)))]
1054 const fn pack8(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) -> u64 {
1055 ((h as u64) << 56)
1056 | ((g as u64) << 48)
1057 | ((f as u64) << 40)
1058 | ((e as u64) << 32)
1059 | ((d as u64) << 24)
1060 | ((c as u64) << 16)
1061 | ((b as u64) << 8)
1062 | a as u64
1063 }
1064
1065 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1066 const NEG10K: i32 = 0x10000 - 10000;
1067}
1068
1069#[rustfmt::skip]
1070static STATIC_DATA: Data = Data {
1071 threshold: AArch64Mem::new(),
1072 biased_half: AArch64Mem::new(),
1073
1074 exp_shifts: ExpShiftTable::new(),
1127 exp_strings: ExpStringTable::new(),
1128 pow10_significands: Pow10SignificandTable::new(),
1129 exp_float_shuffles: ExpFloatShuffleTable::new(),
1130};
1131
1132#[cfg(any())]
1134#[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1135#[cfg_attr(feature = "no-panic", no_panic)]
1136fn to_bcd_4x4(mut efgh_abcd_mnop_ijkl: int32x4_t, d: &Data) -> uint8x16_t {
1137 unsafe {
1138 asm!("/*{:v}*/", inout(vreg) efgh_abcd_mnop_ijkl);
1141
1142 let ef_ab_mn_ij: int32x4_t = vqdmulhq_n_s32(
1143 efgh_abcd_mnop_ijkl,
1144 mem::transmute::<int32x4_t, [i32; 4]>(d.multipliers32)[2],
1145 );
1146 let gh_ef_cd_ab_op_mn_kl_ij: int16x8_t = vreinterpretq_s16_s32(vmlaq_n_s32(
1147 efgh_abcd_mnop_ijkl,
1148 ef_ab_mn_ij,
1149 mem::transmute::<int32x4_t, [i32; 4]>(d.multipliers32)[3],
1150 ));
1151 let high_10s: int16x8_t = vqdmulhq_n_s16(
1152 gh_ef_cd_ab_op_mn_kl_ij,
1153 mem::transmute::<int16x8_t, [i16; 8]>(d.multipliers16)[0],
1154 );
1155 vreinterpretq_u8_s16(vmlaq_n_s16(
1156 gh_ef_cd_ab_op_mn_kl_ij,
1157 high_10s,
1158 mem::transmute::<int16x8_t, [i16; 8]>(d.multipliers16)[1],
1159 ))
1160 }
1161}
1162
1163#[cfg(any())]
1165#[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1166#[cfg_attr(feature = "no-panic", no_panic)]
1167#[inline]
1168fn to_unshuffled_digits(value: u64, d: &Data) -> uint8x16_t {
1169 let mut hundred_million = d.hundred_million;
1170
1171 unsafe {
1173 asm!("/*{0}*/", inout(reg) hundred_million);
1174 }
1175
1176 let abcdefgh = (umul128(value, d.mul_const) >> 90) as u64;
1178 let ijklmnop = value - abcdefgh * hundred_million;
1179
1180 unsafe {
1181 let ijklmnop_abcdefgh_64: uint64x1_t =
1182 mem::transmute::<u64, uint64x1_t>((ijklmnop << 32) | abcdefgh);
1183 let abcdefgh_ijklmnop: int32x2_t = vreinterpret_s32_u64(ijklmnop_abcdefgh_64);
1184
1185 let abcd_ijkl: int32x2_t = vreinterpret_s32_u32(vshr_n_u32(
1186 vreinterpret_u32_s32(vqdmulh_n_s32(
1187 abcdefgh_ijklmnop,
1188 mem::transmute::<int32x4_t, [i32; 4]>(d.multipliers32)[0],
1189 )),
1190 9,
1191 ));
1192 let efgh_abcd_mnop_ijkl_32: int32x2_t = vmla_n_s32(
1193 abcdefgh_ijklmnop,
1194 abcd_ijkl,
1195 mem::transmute::<int32x4_t, [i32; 4]>(d.multipliers32)[1],
1196 );
1197
1198 let efgh_abcd_mnop_ijkl: int32x4_t =
1199 vreinterpretq_s32_u32(vshll_n_u16(vreinterpret_u16_s32(efgh_abcd_mnop_ijkl_32), 0));
1200
1201 to_bcd_4x4(efgh_abcd_mnop_ijkl, d)
1202 }
1203}
1204
1205#[cfg(any())]
1208#[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1209#[cfg_attr(feature = "no-panic", no_panic)]
1210fn to_bcd_4x4(y: __m128i, d: &Data) -> __m128i {
1211 unsafe {
1212 let div100 = _mm_load_si128(ptr::addr_of!(d.div100).cast::<__m128i>());
1213 let div10 = _mm_load_si128(ptr::addr_of!(d.div10).cast::<__m128i>());
1214
1215 #[cfg(target_feature = "sse4.1")]
1216 {
1217 let neg100 = _mm_load_si128(ptr::addr_of!(d.neg100).cast::<__m128i>());
1218 let neg10 = _mm_load_si128(ptr::addr_of!(d.neg10).cast::<__m128i>());
1219
1220 let z: __m128i = _mm_add_epi64(
1222 y,
1223 _mm_mullo_epi32(neg100, _mm_srli_epi32(_mm_mulhi_epu16(y, div100), 3)),
1224 );
1225 _mm_add_epi64(z, _mm_mullo_epi16(neg10, _mm_mulhi_epu16(z, div10)))
1226 }
1227
1228 #[cfg(not(target_feature = "sse4.1"))]
1229 {
1230 let hundred = _mm_load_si128(ptr::addr_of!(d.hundred).cast::<__m128i>());
1231 let moddiv10 = _mm_load_si128(ptr::addr_of!(d.moddiv10).cast::<__m128i>());
1232
1233 let y_div_100: __m128i = _mm_srli_epi16(_mm_mulhi_epu16(y, div100), 3);
1234 let y_mod_100: __m128i = _mm_sub_epi16(y, _mm_mullo_epi16(y_div_100, hundred));
1235 let z: __m128i = _mm_or_si128(_mm_slli_epi32(y_mod_100, 16), y_div_100);
1236 _mm_sub_epi16(
1237 _mm_slli_epi16(z, 8),
1238 _mm_mullo_epi16(moddiv10, _mm_mulhi_epu16(z, div10)),
1239 )
1240 }
1241 }
1242}
1243
1244struct BcdResult {
1251 bcd: u64,
1252 len: usize,
1253}
1254
1255#[cfg_attr(feature = "no-panic", no_panic)]
1262#[rustfmt::skip]
1263const
1264fn to_bcd8(abcdefgh: u64) -> BcdResult {
1265 mod u64 {
1266 pub(crate) const fn from(v: u32) -> u64 {
1267 v as _
1268 }
1269 }
1270
1271 let bcd = {
1275 let abcd_efgh =
1283 abcdefgh + u64::from(NEG10K) * ((abcdefgh * u64::from(DIV10K_SIG)) >> DIV10K_EXP);
1284 let ab_cd_ef_gh = abcd_efgh
1285 + u64::from(NEG100)
1286 * (((abcd_efgh * u64::from(DIV100_SIG)) >> DIV100_EXP) & 0x7f0000007f);
1287 let a_b_c_d_e_f_g_h = ab_cd_ef_gh
1288 + u64::from(NEG10)
1289 * (((ab_cd_ef_gh * u64::from(DIV10_SIG)) >> DIV10_EXP) & 0xf000f000f000f);
1290 a_b_c_d_e_f_g_h.to_be()
1291 };
1292
1293 #[cfg(any())] #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1295 let bcd = {
1296 let mut d = ptr::addr_of!(STATIC_DATA);
1298 let d = unsafe {
1299 asm!("/*{0}*/", inout(reg) d);
1300 &*d
1301 };
1302
1303 let abcd_efgh = (abcdefgh << 32)
1306 - ((10000u64 << 32) - 1) * ((abcdefgh * u64::from(DIV10K_SIG)) >> DIV10K_EXP);
1307 let v: __m128i = to_bcd_4x4(_mm_set_epi64x(0, abcd_efgh as i64), d);
1308 (unsafe { _mm_cvtsi128_si64(v) }) as u64
1309 };
1310
1311 BcdResult {
1312 bcd,
1313 len: count_trailing_nonzeros(bcd),
1314 }
1315}
1316
1317struct DecDigits<Float: FloatTraits> {
1318 digits: Float::DecDigitsType,
1319 num_digits: usize,
1328}
1329
1330#[rustfmt::skip]
1331const _: () = {
1332 type f64 = ConstFloat<::core::primitive::f64>;
1333
1334 impl f64 {
1335#[cfg_attr(feature = "no-panic", no_panic)]
1336#[inline]
1337const
1338fn to_digits_64(value: u64, #[allow(unused_variables)] d: &Data) -> DecDigits<f64> {
1339 {
1346 let hi = (value / 100_000_000) as u32;
1347 let lo = (value % 100_000_000) as u32;
1348 let hi_bcd = to_bcd8(hi as u64);
1349 if lo == 0 {
1350 return DecDigits {
1351 digits: [hi_bcd.bcd + ZEROS, ZEROS],
1352 num_digits: hi_bcd.len,
1353 };
1354 }
1355 let lo_bcd = to_bcd8(lo as u64);
1356 DecDigits {
1357 digits: [hi_bcd.bcd + ZEROS, lo_bcd.bcd + ZEROS],
1358 num_digits: 8 + lo_bcd.len,
1359 }
1360 }
1361
1362 #[cfg(any())]
1363 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1364 {
1365 unsafe {
1366 let unshuffled_digits = to_unshuffled_digits(value, d);
1367 let digits: uint8x16_t = vrev64q_u8(unshuffled_digits);
1368 let str: uint16x8_t = vaddq_u16(
1369 vreinterpretq_u16_u8(digits),
1370 vreinterpretq_u16_s8(vdupq_n_s8(b'0' as i8)),
1371 );
1372 let is_not_zero: uint16x8_t =
1373 vreinterpretq_u16_u8(vcgtzq_s8(vreinterpretq_s8_u8(digits)));
1374 let nonzero_mask: u64 =
1375 vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(is_not_zero, 4)), 0);
1376 DecDigits {
1377 digits: str,
1378 unshuffled: (),
1379 num_digits: 16 - (nonzero_mask.leading_zeros() as usize >> 2),
1380 }
1381 }
1382 }
1383
1384 #[cfg(any())]
1385 #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))]
1386 {
1387 let hi = (value / 100_000_000) as u32;
1388 let lo = (value % 100_000_000) as u32;
1389
1390 unsafe {
1391 let div10k = _mm_load_si128(ptr::addr_of!(d.div10k).cast::<__m128i>());
1392 let neg10k = _mm_load_si128(ptr::addr_of!(d.neg10k).cast::<__m128i>());
1393 let x: __m128i = _mm_set_epi64x(i64::from(hi), i64::from(lo));
1394 #[cfg_attr(target_feature = "sse4.1", allow(unused_mut))]
1395 let mut y: __m128i = _mm_add_epi64(
1396 x,
1397 _mm_mul_epu32(neg10k, _mm_srli_epi64(_mm_mul_epu32(x, div10k), DIV10K_EXP)),
1398 );
1399
1400 #[cfg(not(target_feature = "sse4.1"))]
1402 {
1403 y = _mm_shuffle_epi32(y, _MM_SHUFFLE(0, 1, 2, 3));
1404 }
1405
1406 #[cfg_attr(not(target_feature = "sse4.1"), allow(unused_mut))]
1407 let mut bcd: __m128i = to_bcd_4x4(y, d);
1408 let zeros = _mm_load_si128(ptr::addr_of!(d.zeros).cast::<__m128i>());
1409
1410 let mask = _mm_movemask_epi8(_mm_cmpgt_epi8(bcd, _mm_setzero_si128())) as u64;
1414 let len = if cfg!(target_feature = "sse4.1") {
1417 16 - mask.trailing_zeros()
1418 } else {
1419 64 - mask.leading_zeros()
1420 };
1421
1422 #[cfg(target_feature = "sse4.1")]
1423 {
1424 bcd = _mm_shuffle_epi8(
1425 bcd,
1426 _mm_load_si128(ptr::addr_of!(d.bswap).cast::<__m128i>()),
1427 ); }
1429
1430 DecDigits {
1431 digits: _mm_or_si128(bcd, zeros),
1432 #[cfg(target_feature = "sse4.1")]
1433 unshuffled: (),
1434 num_digits: len as usize,
1435 }
1436 }
1437 }
1438}
1439
1440 }
1441
1442 type f32 = ConstFloat<::core::primitive::f32>;
1443 impl f32 {
1444#[cfg_attr(feature = "no-panic", no_panic)]
1445#[inline]
1446const
1447fn to_digits_32(value: u64, #[allow(unused_variables)] d: &Data) -> DecDigits<f32> {
1448 #[cfg(any())]
1449 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)))]
1450 {
1451 let abcd_efgh = value + u64::from(NEG10K) * ((value * u64::from(DIV10K_SIG)) >> DIV10K_EXP);
1454 let bcd_xmm = to_bcd_4x4(_mm_set_epi64x(0, abcd_efgh as i64), d);
1455 let unshuffled_bcd = unsafe { _mm_cvtsi128_si64(bcd_xmm) } as u64;
1456 let len = if unshuffled_bcd != 0 {
1457 8 - unshuffled_bcd.trailing_zeros() / 8
1458 } else {
1459 0
1460 };
1461 DecDigits {
1462 digits: unshuffled_bcd.swap_bytes() + ZEROS,
1463 unshuffled: bcd_xmm,
1464 num_digits: len as usize,
1465 }
1466 }
1467
1468 #[cfg(any())]
1469 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1470 {
1471 let abcd_efgh = value + u64::from(NEG10K) * ((value * u64::from(DIV10K_SIG)) >> DIV10K_EXP);
1475 let unshuffled: uint8x16_t = unsafe {
1476 let input: int32x4_t =
1477 vcombine_s32(vreinterpret_s32_u64(vcreate_u64(abcd_efgh)), vdup_n_s32(0));
1478 to_bcd_4x4(input, d)
1479 };
1480 let unshuffled_bcd =
1481 unsafe { vget_lane_u64(vreinterpret_u64_u8(vget_low_u8(unshuffled)), 0) };
1482 let len = if unshuffled_bcd != 0 {
1483 8 - unshuffled_bcd.trailing_zeros() / 8
1484 } else {
1485 0
1486 };
1487 DecDigits {
1488 digits: unshuffled_bcd.swap_bytes() + ZEROS,
1489 unshuffled,
1490 num_digits: len as usize,
1491 }
1492 }
1493
1494 {
1501 let result = to_bcd8(value);
1502 DecDigits {
1503 digits: result.bcd + ZEROS,
1504 num_digits: result.len,
1505 }
1506 }
1507}
1508
1509#[cfg_attr(feature = "no-panic", no_panic)]
1510const
1511unsafe fn write_exp_float_simd_32(
1512 buffer: *mut u8,
1513 dig: &DecDigits<f32>,
1514 last_digit: i32,
1515 has_last_digit: bool,
1516 has_extra_digit: bool,
1517 exp_data: u64,
1518 d: &Data,
1519) -> *mut u8 {
1520 mod u32 {
1521 pub(crate) const fn from(v: u8) -> u32 {
1522 v as _
1523 }
1524 }
1525 mod u64 {
1526 pub(crate) const fn from(v: u32) -> u64 {
1527 v as _
1528 }
1529 }
1530 mod usize {
1531 pub(crate) const fn from(v: bool) -> usize {
1532 v as _
1533 }
1534 }
1535
1536 let prefix = (u32::from(b'.') << 8) + u32::from(b'0') + last_digit as u32;
1541 #[allow(unused_variables)]
1551 let tail = exp_data | (u64::from(prefix) << 32);
1552 let entry = unsafe {
1553 d.exp_float_shuffles
1554 .get_entry(dig.num_digits as i32, has_last_digit, has_extra_digit)
1555 };
1556
1557 #[cfg(any())]
1558 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.1", not(miri)))]
1559 unsafe {
1560 let ascii: __m128i = _mm_or_si128(
1561 dig.unshuffled,
1562 _mm_load_si128(ptr::addr_of!(d.zeros).cast::<__m128i>()),
1563 );
1564 let src: __m128i = _mm_insert_epi64(ascii, tail as i64, 1);
1565 let shuffle: __m128i = _mm_load_si128(entry.shuffle.cast::<__m128i>());
1566 let out: __m128i = _mm_shuffle_epi8(src, shuffle);
1567 _mm_storeu_si128(buffer.cast::<__m128i>(), out);
1568 }
1569
1570 #[cfg(any())]
1571 #[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
1572 unsafe {
1573 let ascii: uint8x16_t = vorrq_u8(dig.unshuffled, vdupq_n_u8(b'0'));
1574 let src: uint8x16_t =
1575 vreinterpretq_u8_u64(vsetq_lane_u64(tail, vreinterpretq_u64_u8(ascii), 1));
1576 let shuffle: uint8x16_t = vld1q_u8(entry.shuffle);
1577 let out: uint8x16_t = vqtbl1q_u8(src, shuffle);
1578 vst1q_u8(buffer, out);
1579 }
1580
1581 let length = entry.length as usize - usize::from((exp_data & 0xff000000) == 0);
1582 unsafe { buffer.add(length) }
1583}
1584
1585 }
1586};
1587
1588struct ToDecimalResult {
1589 sig: i64,
1590 exp: i32,
1591 last_digit: u8,
1592 has_last_digit: bool,
1593}
1594
1595const _: () =
{
mod i64 {
pub(crate) const fn from(v: i32) -> i64 { v as _ }
}
mod u64 {
pub(crate) const fn from(v: bool) -> u64 { v as _ }
}
const _: () =
{
use f32 as FLOAT;
type Float = ConstFloat<FLOAT>;
type UInt = <ConstFloat<FLOAT> as FloatTraits>::SigType;
const fn UInt_from(v: u8) -> UInt { v as _ }
struct UIntIntoU64(UInt);
impl UIntIntoU64 {
const fn into(self) -> u64 { self.0 as _ }
}
impl ConstFloat<FLOAT> {
#[inline]
const fn to_decimal(bin_sig: UInt, raw_exp: i64,
regular: bool, d: &Data) -> ToDecimalResult {
let bin_exp = raw_exp - i64::from(Float::EXP_OFFSET);
let num_bits = mem::size_of::<UInt>() as i32 * 8;
const EXTRA_SHIFT: usize = ExpShiftTable::EXTRA_SHIFT;
if !regular {
let dec_exp = compute_dec_exp(bin_exp as i32, false);
let shift =
compute_exp_shift(bin_exp as i32,
dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8);
let pow10 =
unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
let p =
umul192_hi128(pow10.hi, pow10.lo,
UIntIntoU64(bin_sig << shift).into());
let mut integral = p.hi >> EXTRA_SHIFT;
let fractional =
(p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
let half_ulp =
pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize);
let round_up = half_ulp > u64::MAX - fractional;
let round_down = (half_ulp >> 1) > fractional;
integral += u64::from(round_up);
let mut digit =
umul128_add_hi64(fractional, 10, (1 << 63) - 1) as i32;
let lo =
umul128_add_hi64(fractional.wrapping_sub(half_ulp >> 1), 10,
!0) as i32;
if digit < lo { digit = lo; }
return ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
};
}
const LOG10_2_SIG: u64 = 78_913;
const LOG10_2_EXP: i32 = 18;
#[allow(unused_mut)]
let mut dec_exp =
if USE_UMUL128_HI64 {
umul128_hi64(bin_exp as u64,
LOG10_2_SIG << (64 - LOG10_2_EXP)) as i32
} else { compute_dec_exp(bin_exp as i32, true) };
let mut shift =
if ExpShiftTable::ENABLE {
type f64 = ConstFloat<::core::primitive::f64>;
*unsafe {
d.exp_shifts.data.get_unchecked((bin_exp +
i64::from(f64::EXP_OFFSET)) as usize)
}
} else {
compute_exp_shift(bin_exp as i32,
dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8)
};
let even = UInt_from(1) - (bin_sig & UInt_from(1));
if num_bits == 32 {
const EXTRA_SHIFT: usize = 34;
shift += (EXTRA_SHIFT - ExpShiftTable::EXTRA_SHIFT) as u8;
let pow10_hi =
unsafe {
d.pow10_significands.get_unchecked(-dec_exp - 1)
}.hi;
let p =
umul128_hi64(pow10_hi + 1,
UIntIntoU64(bin_sig).into() << shift);
let mut integral = p >> EXTRA_SHIFT;
let fractional = p & ((1u64 << EXTRA_SHIFT) - 1);
let half_ulp =
(pow10_hi >> (65 - shift as usize)) +
UIntIntoU64(even).into();
let round_up =
((fractional + half_ulp) >> EXTRA_SHIFT) != 0;
let round_down = half_ulp > fractional;
integral += u64::from(round_up);
let mut digit =
((fractional * 10 + (1u64 << (EXTRA_SHIFT - 1))) >>
EXTRA_SHIFT) as i32;
if fractional == (1u64 << (EXTRA_SHIFT - 2)) { digit = 2; }
return ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
};
}
let pow10 =
unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
let p =
umul192_hi128(pow10.hi, pow10.lo,
UIntIntoU64(bin_sig << shift).into());
let mut integral = p.hi >> EXTRA_SHIFT;
let fractional =
(p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
let half_ulp =
(pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize)) +
UIntIntoU64(even).into();
let round_up =
fractional.wrapping_add(half_ulp) < fractional;
let round_down = half_ulp > fractional;
integral += u64::from(round_up);
let mut digit =
umul128_add_hi64(fractional, 10, d.biased_half.get()) as
i32;
if fractional == (1u64 << 62) { digit = 2; }
ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
}
}
}
};
const _: () =
{
use f64 as FLOAT;
type Float = ConstFloat<FLOAT>;
type UInt = <ConstFloat<FLOAT> as FloatTraits>::SigType;
const fn UInt_from(v: u8) -> UInt { v as _ }
struct UIntIntoU64(UInt);
impl UIntIntoU64 {
const fn into(self) -> u64 { self.0 as _ }
}
impl ConstFloat<FLOAT> {
#[inline]
const fn to_decimal(bin_sig: UInt, raw_exp: i64,
regular: bool, d: &Data) -> ToDecimalResult {
let bin_exp = raw_exp - i64::from(Float::EXP_OFFSET);
let num_bits = mem::size_of::<UInt>() as i32 * 8;
const EXTRA_SHIFT: usize = ExpShiftTable::EXTRA_SHIFT;
if !regular {
let dec_exp = compute_dec_exp(bin_exp as i32, false);
let shift =
compute_exp_shift(bin_exp as i32,
dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8);
let pow10 =
unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
let p =
umul192_hi128(pow10.hi, pow10.lo,
UIntIntoU64(bin_sig << shift).into());
let mut integral = p.hi >> EXTRA_SHIFT;
let fractional =
(p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
let half_ulp =
pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize);
let round_up = half_ulp > u64::MAX - fractional;
let round_down = (half_ulp >> 1) > fractional;
integral += u64::from(round_up);
let mut digit =
umul128_add_hi64(fractional, 10, (1 << 63) - 1) as i32;
let lo =
umul128_add_hi64(fractional.wrapping_sub(half_ulp >> 1), 10,
!0) as i32;
if digit < lo { digit = lo; }
return ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
};
}
const LOG10_2_SIG: u64 = 78_913;
const LOG10_2_EXP: i32 = 18;
#[allow(unused_mut)]
let mut dec_exp =
if USE_UMUL128_HI64 {
umul128_hi64(bin_exp as u64,
LOG10_2_SIG << (64 - LOG10_2_EXP)) as i32
} else { compute_dec_exp(bin_exp as i32, true) };
let mut shift =
if ExpShiftTable::ENABLE {
type f64 = ConstFloat<::core::primitive::f64>;
*unsafe {
d.exp_shifts.data.get_unchecked((bin_exp +
i64::from(f64::EXP_OFFSET)) as usize)
}
} else {
compute_exp_shift(bin_exp as i32,
dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8)
};
let even = UInt_from(1) - (bin_sig & UInt_from(1));
if num_bits == 32 {
const EXTRA_SHIFT: usize = 34;
shift += (EXTRA_SHIFT - ExpShiftTable::EXTRA_SHIFT) as u8;
let pow10_hi =
unsafe {
d.pow10_significands.get_unchecked(-dec_exp - 1)
}.hi;
let p =
umul128_hi64(pow10_hi + 1,
UIntIntoU64(bin_sig).into() << shift);
let mut integral = p >> EXTRA_SHIFT;
let fractional = p & ((1u64 << EXTRA_SHIFT) - 1);
let half_ulp =
(pow10_hi >> (65 - shift as usize)) +
UIntIntoU64(even).into();
let round_up =
((fractional + half_ulp) >> EXTRA_SHIFT) != 0;
let round_down = half_ulp > fractional;
integral += u64::from(round_up);
let mut digit =
((fractional * 10 + (1u64 << (EXTRA_SHIFT - 1))) >>
EXTRA_SHIFT) as i32;
if fractional == (1u64 << (EXTRA_SHIFT - 2)) { digit = 2; }
return ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
};
}
let pow10 =
unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
let p =
umul192_hi128(pow10.hi, pow10.lo,
UIntIntoU64(bin_sig << shift).into());
let mut integral = p.hi >> EXTRA_SHIFT;
let fractional =
(p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
let half_ulp =
(pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize)) +
UIntIntoU64(even).into();
let round_up =
fractional.wrapping_add(half_ulp) < fractional;
let round_down = half_ulp > fractional;
integral += u64::from(round_up);
let mut digit =
umul128_add_hi64(fractional, 10, d.biased_half.get()) as
i32;
if fractional == (1u64 << 62) { digit = 2; }
ToDecimalResult {
sig: integral as i64,
exp: dec_exp,
last_digit: digit as u8,
has_last_digit: !(round_up || round_down),
}
}
}
};
};impl_for_floats! {{
1596 #[common]
1597 {
1598 mod i64 {
1599 pub(crate) const fn from(v: i32) -> i64 {
1600 v as _
1601 }
1602 }
1603 mod u64 {
1604 pub(crate) const fn from(v: bool) -> u64 {
1605 v as _
1606 }
1607 }
1608 }
1609 {
1610 use f32 as FLOAT;
1611 }
1612 {
1613 use f64 as FLOAT;
1614 }
1615
1616 type Float = ConstFloat<FLOAT>;
1617
1618 type UInt = <ConstFloat<FLOAT> as FloatTraits>::SigType;
1619 const fn UInt_from(v: u8) -> UInt {
1620 v as _
1621 }
1622
1623 struct UIntIntoU64(UInt);
1624 impl UIntIntoU64 {
1625 const fn into(self) -> u64 {
1626 self.0 as _
1627 }
1628 }
1629
1630impl ConstFloat<FLOAT> {
1631#[cfg_attr(feature = "no-panic", no_panic)]
1635#[inline]
1636const fn to_decimal(bin_sig: UInt, raw_exp: i64, regular: bool, d: &Data) -> ToDecimalResult
1637{
1638 let bin_exp = raw_exp - i64::from(Float::EXP_OFFSET);
1639 let num_bits = mem::size_of::<UInt>() as i32 * 8;
1640 const EXTRA_SHIFT: usize = ExpShiftTable::EXTRA_SHIFT;
1641
1642 if !regular {
1643 let dec_exp = compute_dec_exp(bin_exp as i32, false);
1644 let shift = compute_exp_shift(bin_exp as i32, dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8);
1645 let pow10 = unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
1646 let p = umul192_hi128(pow10.hi, pow10.lo, UIntIntoU64(bin_sig << shift).into());
1647
1648 let mut integral = p.hi >> EXTRA_SHIFT;
1649 let fractional = (p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
1650
1651 let half_ulp = pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize);
1652 let round_up = half_ulp > u64::MAX - fractional;
1653 let round_down = (half_ulp >> 1) > fractional;
1654 integral += u64::from(round_up);
1655
1656 let mut digit = umul128_add_hi64(fractional, 10, (1 << 63) - 1) as i32;
1657 let lo = umul128_add_hi64(fractional.wrapping_sub(half_ulp >> 1), 10, !0) as i32;
1658 if digit < lo {
1659 digit = lo;
1660 }
1661 return ToDecimalResult {
1662 sig: integral as i64,
1663 exp: dec_exp,
1664 last_digit: digit as u8,
1665 has_last_digit: !(round_up || round_down),
1666 };
1667 }
1668
1669 const LOG10_2_SIG: u64 = 78_913;
1670 const LOG10_2_EXP: i32 = 18;
1671 #[allow(unused_mut)]
1672 let mut dec_exp = if USE_UMUL128_HI64 {
1673 umul128_hi64(bin_exp as u64, LOG10_2_SIG << (64 - LOG10_2_EXP)) as i32
1674 } else {
1675 compute_dec_exp(bin_exp as i32, true)
1676 };
1677
1678 #[cfg(any())] #[cfg(not(miri))]
1680 #[allow(unused_unsafe)]
1681 unsafe {
1682 #[cfg(target_arch = "x86_64")]
1684 asm!("/*{0:e}*/", inout(reg) dec_exp);
1685 #[cfg(target_arch = "aarch64")]
1686 asm!("/*{0:w}*/", inout(reg) dec_exp);
1687 }
1688 let mut shift = if ExpShiftTable::ENABLE {
1689 type f64 = ConstFloat<::core::primitive::f64>;
1690
1691 *unsafe {
1692 d.exp_shifts
1693 .data
1694 .get_unchecked((bin_exp + i64::from(f64::EXP_OFFSET)) as usize)
1695 }
1696 } else {
1697 compute_exp_shift(bin_exp as i32, dec_exp + 1).wrapping_add(EXTRA_SHIFT as u8)
1698 };
1699 let even = UInt_from(1) - (bin_sig & UInt_from(1));
1700
1701 if num_bits == 32 {
1702 const EXTRA_SHIFT: usize = 34;
1703 shift += (EXTRA_SHIFT - ExpShiftTable::EXTRA_SHIFT) as u8;
1704 let pow10_hi = unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) }.hi;
1705 let p = umul128_hi64(pow10_hi + 1, UIntIntoU64(bin_sig).into() << shift);
1706
1707 let mut integral = p >> EXTRA_SHIFT;
1708 let fractional = p & ((1u64 << EXTRA_SHIFT) - 1);
1709
1710 let half_ulp = (pow10_hi >> (65 - shift as usize)) + UIntIntoU64(even).into();
1711 let round_up = ((fractional + half_ulp) >> EXTRA_SHIFT) != 0;
1712 let round_down = half_ulp > fractional;
1713 integral += u64::from(round_up);
1714
1715 let mut digit = ((fractional * 10 + (1u64 << (EXTRA_SHIFT - 1))) >> EXTRA_SHIFT) as i32;
1716 if fractional == (1u64 << (EXTRA_SHIFT - 2)) {
1717 digit = 2; }
1719 return ToDecimalResult {
1720 sig: integral as i64,
1721 exp: dec_exp,
1722 last_digit: digit as u8,
1723 has_last_digit: !(round_up || round_down),
1724 };
1725 }
1726
1727 let pow10 = unsafe { d.pow10_significands.get_unchecked(-dec_exp - 1) };
1751 let p = umul192_hi128(pow10.hi, pow10.lo, UIntIntoU64(bin_sig << shift).into());
1752
1753 let mut integral = p.hi >> EXTRA_SHIFT;
1754 let fractional = (p.hi << (64 - EXTRA_SHIFT)) | (p.lo >> EXTRA_SHIFT);
1755
1756 let half_ulp = (pow10.hi >> (EXTRA_SHIFT + 1 - shift as usize)) + UIntIntoU64(even).into();
1757 let round_up = fractional.wrapping_add(half_ulp) < fractional;
1758 let round_down = half_ulp > fractional;
1759 integral += u64::from(round_up); let mut digit = umul128_add_hi64(fractional, 10, d.biased_half.get()) as i32;
1763 if fractional == (1u64 << 62) {
1764 digit = 2; }
1766 ToDecimalResult {
1767 sig: integral as i64,
1768 exp: dec_exp,
1769 last_digit: digit as u8,
1770 has_last_digit: !(round_up || round_down),
1771 }
1772}
1773
1774}
1775}}
1776
1777const _: () =
{
mod usize {
pub(crate) const fn from(v: bool) -> usize { v as _ }
}
mod i64 {
pub(crate) const fn from_bool(v: bool) -> i64 { v as _ }
pub(crate) const fn from(v: u8) -> i64 { v as _ }
}
mod i32 {
pub(crate) const fn from(v: bool) -> i32 { v as _ }
}
mod u16 {
pub(crate) const fn from(v: u8) -> u16 { v as _ }
}
const _: () =
{
use f32 as FLOAT;
type Float = ConstFloat<FLOAT>;
type FloatDecDigitsType =
<Float as FloatTraits>::DecDigitsType;
impl Float {
const FIXED_DEC_EXP: ConstRange<RangeInclusive<i32>> =
ConstRange(<Self as FloatTraits>::FIXED_DEC_EXP);
#[doc =
r" Writes the shortest correctly rounded decimal representation of `value` to"]
#[doc =
r" `buffer`. `buffer` should point to a buffer of size `buffer_size` or larger."]
const unsafe fn write_to_zmij_buffer(self,
mut buffer: *mut u8) -> *mut u8 {
let value = self;
let bits = value.to_bits();
let bin_exp = Float::get_exp(bits);
let bin_sig = Float::get_sig(bits);
unsafe { *buffer = b'-'; }
buffer =
unsafe {
buffer.add(usize::from(Float::is_negative(bits)))
};
#[allow(unused_mut)]
let mut d = &raw const STATIC_DATA;
let d = unsafe { &*d };
let threshold =
if Float::NUM_BITS == 64 {
d.threshold.get()
} else { 10_000_000 };
let mut dec;
if bin_exp == 0 {
if bin_sig == Float::SigType_from(0) {
return unsafe {
*buffer = b'0';
*buffer.add(1) = b'.';
*buffer.add(2) = b'0';
buffer.add(3)
};
}
dec = Float::to_decimal(bin_sig, 1, true, d);
let mut dec_sig =
dec.sig * 10 +
(-i64::from_bool(dec.has_last_digit) &
i64::from(dec.last_digit));
let mut dec_exp = dec.exp;
while dec_sig < threshold as i64 {
dec_sig *= 10;
dec_exp -= 1;
}
let d = div10(dec_sig as u64);
let last_digit = dec_sig - d as i64 * 10;
dec =
ToDecimalResult {
sig: d as i64,
exp: dec_exp,
last_digit: last_digit as u8,
has_last_digit: last_digit != 0,
};
} else {
dec =
Float::to_decimal(bin_sig | Float::IMPLICIT_BIT, bin_exp,
bin_sig != Float::SigType_from(0), d);
}
let mut has_last_digit = dec.has_last_digit;
let has_extra_digit = dec.sig >= threshold as i64;
let mut dec_exp =
dec.exp + Float::MAX_DIGITS10 as i32 - 2 +
i32::from(has_extra_digit);
if Float::NUM_BITS == 32 && dec.sig < 1_000_000 {
dec.sig =
10 * dec.sig +
(-i64::from_bool(has_last_digit) &
i64::from(dec.last_digit));
has_last_digit = false;
dec_exp -= 1;
}
let dig = Float::to_digits(dec.sig as u64, d);
if Float::NUM_BITS == 32 && ExpFloatShuffleTable::ENABLE &&
!Float::FIXED_DEC_EXP.contains(&dec_exp) {
mod i32 {
pub(crate) const fn from(v: u8) -> i32 { v as _ }
}
unsafe {
let exp_data =
*d.exp_strings.data.get_unchecked((dec_exp +
ExpStringTable::OFFSET) as usize);
return Float::write_exp_float_simd(buffer, &dig,
i32::from(dec.last_digit), has_last_digit, has_extra_digit,
exp_data, d);
}
}
let bcd_size = if Float::NUM_BITS == 64 { 16 } else { 8 };
unsafe {
buffer.add(usize::from(has_extra_digit)).cast::<FloatDecDigitsType>().write_unaligned(dig.digits);
buffer.add(usize::from(has_extra_digit) +
bcd_size).write(b'0' + dec.last_digit);
}
let length =
usize::from(has_extra_digit) +
if has_last_digit { bcd_size + 1 } else { dig.num_digits } -
1;
if Float::FIXED_DEC_EXP.contains(&dec_exp) {
if length as i32 - 1 <= dec_exp {
return unsafe {
ptr::copy(buffer.add(1), buffer, length);
ptr::write_bytes(buffer.add(length), b'0',
dec_exp as usize + 3 - length);
*buffer.add(dec_exp as usize + 1) = b'.';
buffer.add(dec_exp as usize + 3)
};
} else if 0 <= dec_exp {
return unsafe {
ptr::copy(buffer.add(1), buffer, dec_exp as usize + 1);
*buffer.add(dec_exp as usize + 1) = b'.';
buffer.add(length + 1)
};
} else {
return unsafe {
ptr::copy(buffer.add(1), buffer.add((1 - dec_exp) as usize),
length);
ptr::write_bytes(buffer, b'0', (1 - dec_exp) as usize);
*buffer.add(1) = b'.';
buffer.add((1 - dec_exp) as usize + length)
};
}
}
unsafe { *buffer = *buffer.add(1); *buffer.add(1) = b'.'; }
buffer =
unsafe { buffer.add(length + usize::from(length > 1)) };
if ExpStringTable::ENABLE {
let mut exp_data =
unsafe {
*d.exp_strings.data.get_unchecked((dec_exp +
ExpStringTable::OFFSET) as usize)
};
let len = (exp_data >> 48) as usize;
exp_data = exp_data.to_le();
unsafe {
ptr::copy_nonoverlapping((&raw const exp_data).cast::<u8>(),
buffer, if Float::MAX_10_EXP >= 100 { 5 } else { 4 });
return buffer.add(len);
}
}
let sign_ptr = buffer;
let e_sign =
if dec_exp >= 0 {
(u16::from(b'+') << 8) | u16::from(b'e')
} else { (u16::from(b'-') << 8) | u16::from(b'e') };
buffer = unsafe { buffer.add(1) };
dec_exp = if dec_exp >= 0 { dec_exp } else { -dec_exp };
buffer = unsafe { buffer.add(usize::from(dec_exp >= 10)) };
if Float::MAX_10_EXP >= 100 {
let digit =
if USE_UMUL128_HI64 {
umul128_hi64(dec_exp as u64, 0x290000000000000) as u32
} else { (dec_exp as u32 * DIV100_SIG) >> DIV100_EXP };
unsafe { *buffer = b'0' + digit as u8; }
buffer = unsafe { buffer.add(usize::from(dec_exp >= 100)) };
dec_exp -= (digit * 100) as i32;
}
unsafe {
buffer.cast::<u16>().write_unaligned(*digits2(dec_exp as
usize));
sign_ptr.cast::<u16>().write_unaligned(e_sign.to_le());
buffer.add(2)
}
}
}
};
const _: () =
{
use f64 as FLOAT;
type Float = ConstFloat<FLOAT>;
type FloatDecDigitsType =
<Float as FloatTraits>::DecDigitsType;
impl Float {
const FIXED_DEC_EXP: ConstRange<RangeInclusive<i32>> =
ConstRange(<Self as FloatTraits>::FIXED_DEC_EXP);
#[doc =
r" Writes the shortest correctly rounded decimal representation of `value` to"]
#[doc =
r" `buffer`. `buffer` should point to a buffer of size `buffer_size` or larger."]
const unsafe fn write_to_zmij_buffer(self,
mut buffer: *mut u8) -> *mut u8 {
let value = self;
let bits = value.to_bits();
let bin_exp = Float::get_exp(bits);
let bin_sig = Float::get_sig(bits);
unsafe { *buffer = b'-'; }
buffer =
unsafe {
buffer.add(usize::from(Float::is_negative(bits)))
};
#[allow(unused_mut)]
let mut d = &raw const STATIC_DATA;
let d = unsafe { &*d };
let threshold =
if Float::NUM_BITS == 64 {
d.threshold.get()
} else { 10_000_000 };
let mut dec;
if bin_exp == 0 {
if bin_sig == Float::SigType_from(0) {
return unsafe {
*buffer = b'0';
*buffer.add(1) = b'.';
*buffer.add(2) = b'0';
buffer.add(3)
};
}
dec = Float::to_decimal(bin_sig, 1, true, d);
let mut dec_sig =
dec.sig * 10 +
(-i64::from_bool(dec.has_last_digit) &
i64::from(dec.last_digit));
let mut dec_exp = dec.exp;
while dec_sig < threshold as i64 {
dec_sig *= 10;
dec_exp -= 1;
}
let d = div10(dec_sig as u64);
let last_digit = dec_sig - d as i64 * 10;
dec =
ToDecimalResult {
sig: d as i64,
exp: dec_exp,
last_digit: last_digit as u8,
has_last_digit: last_digit != 0,
};
} else {
dec =
Float::to_decimal(bin_sig | Float::IMPLICIT_BIT, bin_exp,
bin_sig != Float::SigType_from(0), d);
}
let mut has_last_digit = dec.has_last_digit;
let has_extra_digit = dec.sig >= threshold as i64;
let mut dec_exp =
dec.exp + Float::MAX_DIGITS10 as i32 - 2 +
i32::from(has_extra_digit);
if Float::NUM_BITS == 32 && dec.sig < 1_000_000 {
dec.sig =
10 * dec.sig +
(-i64::from_bool(has_last_digit) &
i64::from(dec.last_digit));
has_last_digit = false;
dec_exp -= 1;
}
let dig = Float::to_digits(dec.sig as u64, d);
if Float::NUM_BITS == 32 && ExpFloatShuffleTable::ENABLE &&
!Float::FIXED_DEC_EXP.contains(&dec_exp) {
mod i32 {
pub(crate) const fn from(v: u8) -> i32 { v as _ }
}
unsafe {
let exp_data =
*d.exp_strings.data.get_unchecked((dec_exp +
ExpStringTable::OFFSET) as usize);
return Float::write_exp_float_simd(buffer, &dig,
i32::from(dec.last_digit), has_last_digit, has_extra_digit,
exp_data, d);
}
}
let bcd_size = if Float::NUM_BITS == 64 { 16 } else { 8 };
unsafe {
buffer.add(usize::from(has_extra_digit)).cast::<FloatDecDigitsType>().write_unaligned(dig.digits);
buffer.add(usize::from(has_extra_digit) +
bcd_size).write(b'0' + dec.last_digit);
}
let length =
usize::from(has_extra_digit) +
if has_last_digit { bcd_size + 1 } else { dig.num_digits } -
1;
if Float::FIXED_DEC_EXP.contains(&dec_exp) {
if length as i32 - 1 <= dec_exp {
return unsafe {
ptr::copy(buffer.add(1), buffer, length);
ptr::write_bytes(buffer.add(length), b'0',
dec_exp as usize + 3 - length);
*buffer.add(dec_exp as usize + 1) = b'.';
buffer.add(dec_exp as usize + 3)
};
} else if 0 <= dec_exp {
return unsafe {
ptr::copy(buffer.add(1), buffer, dec_exp as usize + 1);
*buffer.add(dec_exp as usize + 1) = b'.';
buffer.add(length + 1)
};
} else {
return unsafe {
ptr::copy(buffer.add(1), buffer.add((1 - dec_exp) as usize),
length);
ptr::write_bytes(buffer, b'0', (1 - dec_exp) as usize);
*buffer.add(1) = b'.';
buffer.add((1 - dec_exp) as usize + length)
};
}
}
unsafe { *buffer = *buffer.add(1); *buffer.add(1) = b'.'; }
buffer =
unsafe { buffer.add(length + usize::from(length > 1)) };
if ExpStringTable::ENABLE {
let mut exp_data =
unsafe {
*d.exp_strings.data.get_unchecked((dec_exp +
ExpStringTable::OFFSET) as usize)
};
let len = (exp_data >> 48) as usize;
exp_data = exp_data.to_le();
unsafe {
ptr::copy_nonoverlapping((&raw const exp_data).cast::<u8>(),
buffer, if Float::MAX_10_EXP >= 100 { 5 } else { 4 });
return buffer.add(len);
}
}
let sign_ptr = buffer;
let e_sign =
if dec_exp >= 0 {
(u16::from(b'+') << 8) | u16::from(b'e')
} else { (u16::from(b'-') << 8) | u16::from(b'e') };
buffer = unsafe { buffer.add(1) };
dec_exp = if dec_exp >= 0 { dec_exp } else { -dec_exp };
buffer = unsafe { buffer.add(usize::from(dec_exp >= 10)) };
if Float::MAX_10_EXP >= 100 {
let digit =
if USE_UMUL128_HI64 {
umul128_hi64(dec_exp as u64, 0x290000000000000) as u32
} else { (dec_exp as u32 * DIV100_SIG) >> DIV100_EXP };
unsafe { *buffer = b'0' + digit as u8; }
buffer = unsafe { buffer.add(usize::from(dec_exp >= 100)) };
dec_exp -= (digit * 100) as i32;
}
unsafe {
buffer.cast::<u16>().write_unaligned(*digits2(dec_exp as
usize));
sign_ptr.cast::<u16>().write_unaligned(e_sign.to_le());
buffer.add(2)
}
}
}
};
};impl_for_floats! {{
1778 #[common]
1779 {
1780 mod usize {
1781 pub(crate) const fn from(v: bool) -> usize {
1782 v as _
1783 }
1784 }
1785 mod i64 {
1786 pub(crate) const fn from_bool(v: bool) -> i64 {
1787 v as _
1788 }
1789 pub(crate) const fn from(v: u8) -> i64 {
1790 v as _
1791 }
1792 }
1793 mod i32 {
1794 pub(crate) const fn from(v: bool) -> i32 {
1795 v as _
1796 }
1797 }
1798 mod u16 {
1799 pub(crate) const fn from(v: u8) -> u16 {
1800 v as _
1801 }
1802 }
1803 }
1804 {
1805 use f32 as FLOAT;
1806 }
1807 {
1808 use f64 as FLOAT;
1809 }
1810
1811 type Float = ConstFloat<FLOAT>;
1812
1813 type FloatDecDigitsType = <Float as FloatTraits>::DecDigitsType;
1814
1815 impl Float {
1816 const FIXED_DEC_EXP: ConstRange<RangeInclusive<i32>> = ConstRange(<Self as FloatTraits>::FIXED_DEC_EXP);
1817
1818#[cfg_attr(feature = "no-panic", no_panic)]
1821const unsafe fn write_to_zmij_buffer(self, mut buffer: *mut u8) -> *mut u8
1822{
1823 let value = self;
1824 let bits = value.to_bits();
1825 let bin_exp = Float::get_exp(bits); let bin_sig = Float::get_sig(bits); unsafe {
1830 *buffer = b'-';
1831 }
1832 buffer = unsafe { buffer.add(usize::from(Float::is_negative(bits))) };
1833
1834 #[allow(unused_mut)]
1835 let mut d = ptr::addr_of!(STATIC_DATA);
1836 let d = unsafe {
1837 #[cfg(any())] #[cfg(all(any(target_arch = "aarch64", target_arch = "x86_64"), not(miri)))]
1840 asm!("/*{0}*/", inout(reg) d);
1841 &*d
1842 };
1843 let threshold = if Float::NUM_BITS == 64 {
1844 d.threshold.get()
1845 } else {
1846 10_000_000
1847 };
1848
1849 let mut dec;
1850 if bin_exp == 0 {
1851 if bin_sig == Float::SigType_from(0) {
1852 return unsafe {
1853 *buffer = b'0';
1854 *buffer.add(1) = b'.';
1855 *buffer.add(2) = b'0';
1856 buffer.add(3)
1857 };
1858 }
1859 dec = Float::to_decimal(bin_sig, 1, true, d);
1860 let mut dec_sig =
1861 dec.sig * 10 + (-i64::from_bool(dec.has_last_digit) & i64::from(dec.last_digit));
1862 let mut dec_exp = dec.exp;
1863 while dec_sig < threshold as i64 {
1864 dec_sig *= 10;
1865 dec_exp -= 1;
1866 }
1867 let d = div10(dec_sig as u64);
1868 let last_digit = dec_sig - d as i64 * 10;
1869 dec = ToDecimalResult {
1870 sig: d as i64,
1871 exp: dec_exp,
1872 last_digit: last_digit as u8,
1873 has_last_digit: last_digit != 0,
1874 };
1875 } else {
1876 dec = Float::to_decimal(
1877 bin_sig | Float::IMPLICIT_BIT,
1878 bin_exp,
1879 bin_sig != Float::SigType_from(0),
1880 d,
1881 );
1882 }
1883 let mut has_last_digit = dec.has_last_digit;
1884 let has_extra_digit = dec.sig >= threshold as i64;
1885 let mut dec_exp = dec.exp + Float::MAX_DIGITS10 as i32 - 2 + i32::from(has_extra_digit);
1886 if Float::NUM_BITS == 32 && dec.sig < 1_000_000 {
1887 dec.sig = 10 * dec.sig + (-i64::from_bool(has_last_digit) & i64::from(dec.last_digit));
1888 has_last_digit = false;
1889 dec_exp -= 1;
1890 }
1891
1892 let dig = Float::to_digits(dec.sig as u64, d);
1894
1895 if Float::NUM_BITS == 32
1896 && ExpFloatShuffleTable::ENABLE
1897 && !Float::FIXED_DEC_EXP.contains(&dec_exp)
1898 {
1899 mod i32 {
1900 pub(crate) const fn from(v: u8) -> i32 {
1901 v as _
1902 }
1903 }
1904 unsafe {
1905 let exp_data = *d
1906 .exp_strings
1907 .data
1908 .get_unchecked((dec_exp + ExpStringTable::OFFSET) as usize);
1909 return Float::write_exp_float_simd(
1910 buffer,
1911 &dig,
1912 i32::from(dec.last_digit),
1913 has_last_digit,
1914 has_extra_digit,
1915 exp_data,
1916 d,
1917 );
1918 }
1919 }
1920
1921 let bcd_size = if Float::NUM_BITS == 64 { 16 } else { 8 };
1922 unsafe {
1923 buffer
1924 .add(usize::from(has_extra_digit))
1925 .cast::<FloatDecDigitsType>()
1926 .write_unaligned(dig.digits);
1927 buffer
1928 .add(usize::from(has_extra_digit) + bcd_size)
1929 .write(b'0' + dec.last_digit);
1930 }
1931 let length = usize::from(has_extra_digit)
1932 + if has_last_digit {
1933 bcd_size + 1
1934 } else {
1935 dig.num_digits
1936 }
1937 - 1;
1938
1939 if Float::FIXED_DEC_EXP.contains(&dec_exp) {
1940 if length as i32 - 1 <= dec_exp {
1941 return unsafe {
1943 ptr::copy(buffer.add(1), buffer, length);
1944 ptr::write_bytes(buffer.add(length), b'0', dec_exp as usize + 3 - length);
1945 *buffer.add(dec_exp as usize + 1) = b'.';
1946 buffer.add(dec_exp as usize + 3)
1947 };
1948 } else if 0 <= dec_exp {
1949 return unsafe {
1951 ptr::copy(buffer.add(1), buffer, dec_exp as usize + 1);
1952 *buffer.add(dec_exp as usize + 1) = b'.';
1953 buffer.add(length + 1)
1954 };
1955 } else {
1956 return unsafe {
1958 ptr::copy(buffer.add(1), buffer.add((1 - dec_exp) as usize), length);
1959 ptr::write_bytes(buffer, b'0', (1 - dec_exp) as usize);
1960 *buffer.add(1) = b'.';
1961 buffer.add((1 - dec_exp) as usize + length)
1962 };
1963 }
1964 }
1965
1966 unsafe {
1967 *buffer = *buffer.add(1);
1969 *buffer.add(1) = b'.';
1970 }
1971 buffer = unsafe { buffer.add(length + usize::from(length > 1)) };
1972
1973 if ExpStringTable::ENABLE {
1975 let mut exp_data = unsafe {
1976 *d.exp_strings
1977 .data
1978 .get_unchecked((dec_exp + ExpStringTable::OFFSET) as usize)
1979 };
1980 let len = (exp_data >> 48) as usize;
1981 exp_data = exp_data.to_le();
1982 unsafe {
1983 ptr::copy_nonoverlapping(
1984 ptr::addr_of!(exp_data).cast::<u8>(),
1985 buffer,
1986 if Float::MAX_10_EXP >= 100 { 5 } else { 4 },
1987 );
1988 return buffer.add(len);
1989 }
1990 }
1991 let sign_ptr = buffer;
1992 let e_sign = if dec_exp >= 0 {
1993 (u16::from(b'+') << 8) | u16::from(b'e')
1994 } else {
1995 (u16::from(b'-') << 8) | u16::from(b'e')
1996 };
1997 buffer = unsafe { buffer.add(1) };
1998 dec_exp = if dec_exp >= 0 { dec_exp } else { -dec_exp };
1999 buffer = unsafe { buffer.add(usize::from(dec_exp >= 10)) };
2000 if Float::MAX_10_EXP >= 100 {
2001 let digit = if USE_UMUL128_HI64 {
2003 umul128_hi64(dec_exp as u64, 0x290000000000000) as u32
2004 } else {
2005 (dec_exp as u32 * DIV100_SIG) >> DIV100_EXP
2006 };
2007 unsafe {
2008 *buffer = b'0' + digit as u8;
2009 }
2010 buffer = unsafe { buffer.add(usize::from(dec_exp >= 100)) };
2011 dec_exp -= (digit * 100) as i32;
2012 }
2013 unsafe {
2014 buffer
2015 .cast::<u16>()
2016 .write_unaligned(*digits2(dec_exp as usize));
2017 sign_ptr.cast::<u16>().write_unaligned(e_sign.to_le());
2018 buffer.add(2)
2019 }
2020}
2021
2022 }
2023}}
2024
2025pub struct Buffer {
2036 bytes: [MaybeUninit<u8>; BUFFER_SIZE],
2037}
2038
2039impl Buffer {
2040 #[inline]
2043 #[cfg_attr(feature = "no-panic", no_panic)]
2044 pub const fn new() -> Self {
2045 let bytes = [MaybeUninit::<u8>::uninit(); BUFFER_SIZE];
2046 Buffer { bytes }
2047 }
2048
2049 #[cfg_attr(feature = "no-panic", no_panic)]
2061 pub fn format<F: Float>(&mut self, f: F) -> &str {
2062 f.impl_format(self)
2063 }
2064}
2065
2066struct BufferOfFloat<'a, F>(&'a mut Buffer, core::marker::PhantomData<F>);
2067
2068impl<'a, F> BufferOfFloat<'a, F> {
2069 #[inline]
2070 const fn new(buffer: &'a mut Buffer) -> Self {
2071 Self(buffer, core::marker::PhantomData)
2072 }
2073}
2074
2075const _: () =
{
use f32 as FLOAT;
#[rustfmt::skip]
impl<'a> BufferOfFloat<'a, FLOAT> {
#[inline]
const fn format(self, f: FLOAT) -> &'a str {
let f = ConstFloat(f);
if f.is_nonfinite() {
f.format_nonfinite()
} else { self.format_finite(f) }
}
}
};
const _: () =
{
use f64 as FLOAT;
#[rustfmt::skip]
impl<'a> BufferOfFloat<'a, FLOAT> {
#[inline]
const fn format(self, f: FLOAT) -> &'a str {
let f = ConstFloat(f);
if f.is_nonfinite() {
f.format_nonfinite()
} else { self.format_finite(f) }
}
}
};impl_for_floats!({
2076 {
2077 use f32 as FLOAT;
2078 }
2079 {
2080 use f64 as FLOAT;
2081 }
2082
2083 #[rustfmt::skip]
2084 impl<'a> BufferOfFloat<'a, FLOAT> {
2085 #[inline]
2086 const fn format(self, f: FLOAT) -> &'a str {
2087 let f = ConstFloat(f);
2088 if f.is_nonfinite() {
2089 f.format_nonfinite()
2090 } else {
2091 self.format_finite(f)
2092 }
2093 }
2094
2095 }
2096});
2097
2098impl<'a> BufferOfFloat<'a, f32> {
2099 #[inline]
2100 const fn format_finite(self, f: ConstFloat<f32>) -> &'a str {
2101 self.0.format_finite_f32(f.0)
2102 }
2103}
2104
2105impl<'a> BufferOfFloat<'a, f64> {
2106 #[inline]
2107 const fn format_finite(self, f: ConstFloat<f64>) -> &'a str {
2108 self.0.format_finite_f64(f.0)
2109 }
2110}
2111
2112impl Buffer {
2113 #[cfg_attr(feature = "no-panic", no_panic)]
2129 pub fn format_finite<F: Float>(&mut self, f: F) -> &str {
2130 f.impl_format_finite(self)
2131 }
2132}
2133
2134macro_rules! buffer_methods_for_floats {
2135 (
2136 #[$FLOAT:ident]
2137 #[$f32:ident($method_for_f32:ident)]
2138 #[$f64:ident($method_for_f64:ident)]
2139 $(#$attr:tt)*
2140 const fn __$args:tt -> $ReturnTy:ty $body:block
2141 ) => {
2142 const _: () = {
2143 use $f32 as $FLOAT;
2144 impl Buffer {
2145 $(#$attr)*
2146 const fn $method_for_f32 $args -> $ReturnTy $body
2147 }
2148 };
2149 const _: () = {
2150 use $f64 as $FLOAT;
2151 impl Buffer {
2152 $(#$attr)*
2153 const fn $method_for_f64 $args -> $ReturnTy $body
2154 }
2155 };
2156 };
2157}
2158
2159const _: () =
{
use f32 as FLOAT;
impl Buffer {
#[inline]
const fn format_finite_f32(&mut self, f: FLOAT) -> &str {
let f = ConstFloat(f);
unsafe {
let end =
f.write_to_zmij_buffer(self.bytes.as_mut_ptr().cast::<u8>());
let len =
end.offset_from(self.bytes.as_ptr().cast::<u8>()) as usize;
let slice =
slice::from_raw_parts(self.bytes.as_ptr().cast::<u8>(),
len);
str::from_utf8_unchecked(slice)
}
}
}
};
const _: () =
{
use f64 as FLOAT;
impl Buffer {
#[inline]
const fn format_finite_f64(&mut self, f: FLOAT) -> &str {
let f = ConstFloat(f);
unsafe {
let end =
f.write_to_zmij_buffer(self.bytes.as_mut_ptr().cast::<u8>());
let len =
end.offset_from(self.bytes.as_ptr().cast::<u8>()) as usize;
let slice =
slice::from_raw_parts(self.bytes.as_ptr().cast::<u8>(),
len);
str::from_utf8_unchecked(slice)
}
}
}
};buffer_methods_for_floats! {
2160 #[FLOAT]
2161 #[f32(format_finite_f32)]
2162 #[f64(format_finite_f64)]
2163 #[inline]
2164 const fn __(&mut self, f: FLOAT) -> &str {
2165 let f = ConstFloat(f);
2166 unsafe {
2167 let end = f.write_to_zmij_buffer(self.bytes.as_mut_ptr().cast::<u8>());
2168 let len = end.offset_from(self.bytes.as_ptr().cast::<u8>()) as usize;
2169 let slice = slice::from_raw_parts(self.bytes.as_ptr().cast::<u8>(), len);
2170 str::from_utf8_unchecked(slice)
2171 }
2172 }
2173}
2174
2175#[allow(unknown_lints)] #[allow(private_bounds)]
2182pub trait Float: private::Sealed {}
2183impl Float for f32 {}
2184impl Float for f64 {}
2185
2186mod private {
2187 use crate::{Buffer, BufferOfFloat, ConstFloat};
2188
2189 pub trait Sealed: crate::traits::Float {
2190 fn impl_format_finite(self, buffer: &mut Buffer) -> &str;
2191 fn impl_format(self, buffer: &mut Buffer) -> &str;
2192 }
2193
2194 impl Sealed for f32 {
2195 fn impl_format_finite(self, buffer: &mut Buffer) -> &str {
2196 buffer.format_finite_f32(self)
2197 }
2198
2199 fn impl_format(self, buffer: &mut Buffer) -> &str {
2200 BufferOfFloat::<Self>::new(buffer).format(self)
2201 }
2202 }
2203
2204 impl ConstFloat<f32> {
2205 #[inline]
2206 #[rustfmt::skip]
2207 pub(crate) const
2208 fn is_nonfinite(self) -> bool {
2209 const EXP_MASK: u32 = 0x7f800000;
2210 let bits = self.to_bits();
2211 bits & EXP_MASK == EXP_MASK
2212 }
2213
2214 #[cold]
2215 #[cfg_attr(feature = "no-panic", inline)]
2216 #[rustfmt::skip]
2217 pub(crate) const
2218 fn format_nonfinite(self) -> &'static str {
2219 const MANTISSA_MASK: u32 = 0x007fffff;
2220 const SIGN_MASK: u32 = 0x80000000;
2221 let bits = self.to_bits();
2222 if bits & MANTISSA_MASK != 0 {
2223 crate::NAN
2224 } else if bits & SIGN_MASK != 0 {
2225 crate::NEG_INFINITY
2226 } else {
2227 crate::INFINITY
2228 }
2229 }
2230 }
2231
2232 impl Sealed for f64 {
2233 fn impl_format_finite(self, buffer: &mut Buffer) -> &str {
2234 buffer.format_finite_f64(self)
2235 }
2236
2237 fn impl_format(self, buffer: &mut Buffer) -> &str {
2238 BufferOfFloat::<Self>::new(buffer).format(self)
2239 }
2240 }
2241
2242 impl ConstFloat<f64> {
2243 #[inline]
2244 #[rustfmt::skip]
2245 pub(crate) const
2246 fn is_nonfinite(self) -> bool {
2247 const EXP_MASK: u64 = 0x7ff0000000000000;
2248 let bits = self.to_bits();
2249 bits & EXP_MASK == EXP_MASK
2250 }
2251
2252 #[cold]
2253 #[cfg_attr(feature = "no-panic", inline)]
2254 #[rustfmt::skip]
2255 pub(crate) const
2256 fn format_nonfinite(self) -> &'static str {
2257 const MANTISSA_MASK: u64 = 0x000fffffffffffff;
2258 const SIGN_MASK: u64 = 0x8000000000000000;
2259 let bits = self.to_bits();
2260 if bits & MANTISSA_MASK != 0 {
2261 crate::NAN
2262 } else if bits & SIGN_MASK != 0 {
2263 crate::NEG_INFINITY
2264 } else {
2265 crate::INFINITY
2266 }
2267 }
2268 }
2269}
2270
2271impl Default for Buffer {
2272 #[inline]
2273 #[cfg_attr(feature = "no-panic", no_panic)]
2274 fn default() -> Self {
2275 Buffer::new()
2276 }
2277}
2278
2279pub struct Format<'a, T>(pub &'a mut Buffer, pub T);
2280
2281pub struct FormatFinite<'a, T>(pub &'a mut Buffer, pub T);
2282
2283const _: () =
{
use f32 as FLOAT;
impl<'a> Format<'a, FLOAT> {
pub const fn call_once(self) -> &'a str {
let Self(this, f) = self;
BufferOfFloat::<FLOAT>::new(this).format(f)
}
}
impl<'a> FormatFinite<'a, FLOAT> {
pub const fn call_once(self) -> &'a str {
let Self(this, f) = self;
BufferOfFloat::<FLOAT>::new(this).format_finite(ConstFloat(f))
}
}
};
const _: () =
{
use f64 as FLOAT;
impl<'a> Format<'a, FLOAT> {
pub const fn call_once(self) -> &'a str {
let Self(this, f) = self;
BufferOfFloat::<FLOAT>::new(this).format(f)
}
}
impl<'a> FormatFinite<'a, FLOAT> {
pub const fn call_once(self) -> &'a str {
let Self(this, f) = self;
BufferOfFloat::<FLOAT>::new(this).format_finite(ConstFloat(f))
}
}
};impl_for_floats!({
2284 {
2285 use f32 as FLOAT;
2286 }
2287 {
2288 use f64 as FLOAT;
2289 }
2290
2291 impl<'a> Format<'a, FLOAT> {
2292 pub const fn call_once(self) -> &'a str {
2293 let Self(this, f) = self;
2294 BufferOfFloat::<FLOAT>::new(this).format(f)
2295 }
2296 }
2297
2298 impl<'a> FormatFinite<'a, FLOAT> {
2299 pub const fn call_once(self) -> &'a str {
2300 let Self(this, f) = self;
2301 BufferOfFloat::<FLOAT>::new(this).format_finite(ConstFloat(f))
2302 }
2303 }
2304});