1use crate::debug_hex;
17use crate::debug_hex::IsDebugHex;
18use crate::int_helper;
19use crate::types::extra::{LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128, Unsigned};
20use crate::{
21 FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64,
22 FixedU128,
23};
24use az::{WrappingAs, WrappingCast};
25use core::cmp;
26use core::cmp::Ordering;
27use core::fmt::{
28 Alignment, Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Result as FmtResult,
29 UpperExp, UpperHex,
30};
31use core::ops::{Add, Shl, Shr};
32use core::str;
33
34struct Buffer {
48 int_digits: usize,
49 frac_digits: usize,
50 digits: [u8; 129],
51 exp: i32,
52 exp_len: usize,
53 exp_bytes: [u8; 4],
54}
55
56impl Buffer {
57 fn new(int_digits: u32, frac_digits: u32) -> Buffer {
58 assert!(int_digits + frac_digits <= 128, "out of bounds");
59 Buffer {
60 int_digits: int_digits as usize,
61 frac_digits: frac_digits as usize,
62 digits: [0; 129],
63 exp: 0,
64 exp_len: 0,
65 exp_bytes: [0; 4],
66 }
67 }
68
69 fn int(&mut self) -> &mut [u8] {
71 let begin = 1;
72 let end = 1 + self.int_digits;
73 &mut self.digits[begin..end]
74 }
75
76 fn frac(&mut self) -> &mut [u8] {
77 let begin = 1 + self.int_digits;
78 let end = 1 + self.int_digits + self.frac_digits;
79 &mut self.digits[begin..end]
80 }
81
82 fn int_and_frac(&self) -> &[u8] {
83 let begin = 1;
84 let end = 1 + self.int_digits + self.frac_digits;
85 &self.digits[begin..end]
86 }
87
88 fn find_exp_dec(&mut self, max_frac_digits: Option<usize>, truncation: &mut Truncation) {
89 match self.int_and_frac().iter().position(|&x| x > 0) {
90 None => {
91 self.int_digits = 0;
92 self.frac_digits = 0;
93 }
94 Some(first) => {
95 if self.int_digits > first {
97 let exp = self.int_digits - 1 - first;
98 self.int_digits -= exp;
99 self.frac_digits += exp;
100 self.exp = exp.wrapping_as::<i32>();
101 } else {
102 let neg_exp = first - self.int_digits + 1;
103 self.int_digits += neg_exp;
104 self.frac_digits -= neg_exp;
105 self.exp = -neg_exp.wrapping_as::<i32>();
106 }
107
108 if let Some(max) = max_frac_digits {
110 if self.frac_digits > max {
111 let frac = self.frac();
112 update_truncation(truncation, &frac[max..]);
113 self.frac_digits = max;
114 }
115 }
116 }
117 }
118 }
119
120 fn inc_exp_after_rounding_up(&mut self, fixed_prec: bool) {
121 self.exp += 1;
122 self.int_digits = self
124 .int_digits
125 .checked_sub(1)
126 .expect("expected at least one int digit for LowerExp/UpperExp");
127 if !fixed_prec {
128 self.frac_digits += 1;
129 }
130 }
131
132 fn finish(
133 &mut self,
134 format: Format,
135 is_neg: bool,
136 truncation: Truncation,
137 fmt: &mut Formatter,
138 ) -> FmtResult {
139 let has_exp = matches!(format, Format::UpExp | Format::LowExp);
140
141 let added_ms_digit = self.round_and_trim(format.max_digit(), truncation);
142
143 if added_ms_digit.0 && has_exp {
145 self.inc_exp_after_rounding_up(fmt.precision().is_some());
146 }
147
148 self.encode_digits(format == Format::UpHex);
149 if has_exp {
150 self.encode_exp(format == Format::UpExp);
151 }
152 self.pad_and_print(is_neg, format.prefix(), fmt)
153 }
154
155 fn round_and_trim(&mut self, max: u8, truncation: Truncation) -> RoundingAddedMSDigit {
157 let len = 1 + self.int_digits + self.frac_digits;
158
159 let is_odd = self.digits[len - 1] & 1 != 0;
161 let round_up =
162 truncation == Truncation::GreaterTie || (truncation == Truncation::Tie && is_odd);
163 if round_up {
164 let mut incremented_zero_at = None;
165 for (index, b) in self.digits[0..len].iter_mut().enumerate().rev() {
166 if *b < max {
167 if *b == 0 {
168 incremented_zero_at = Some(index)
169 }
170 *b += 1;
171 break;
172 }
173 *b = 0;
174 if self.frac_digits > 0 {
176 self.frac_digits -= 1;
177 }
178 }
179 match incremented_zero_at {
180 Some(index) if self.digits[0..index].iter().all(|&x| x == 0) => {
181 RoundingAddedMSDigit(true)
182 }
183 _ => RoundingAddedMSDigit(false),
184 }
185 } else {
186 for b in self.digits[len - self.frac_digits..len].iter_mut().rev() {
187 if *b != 0 {
188 break;
189 }
190 self.frac_digits -= 1;
191 }
192 RoundingAddedMSDigit(false)
193 }
194 }
195
196 fn encode_digits(&mut self, upper: bool) {
197 for digit in &mut self.digits[..1 + self.int_digits + self.frac_digits] {
198 if *digit < 10 {
199 *digit += b'0';
200 } else {
201 *digit += if upper { b'A' - 10 } else { b'a' - 10 };
202 }
203 }
204 }
205
206 fn encode_exp(&mut self, upper: bool) {
207 debug_assert!(-39 <= self.exp && self.exp <= 38);
208
209 self.exp_len = 1;
210 self.exp_bytes[0] = if upper { b'E' } else { b'e' };
211 if self.exp < 0 {
212 self.exp_len = 2;
213 self.exp_bytes[1] = b'-';
214 }
215 let abs_exp = self.exp.abs().wrapping_as::<u8>();
216
217 if abs_exp > 9 {
218 self.exp_len += 2;
219 let (e0, e1) = (abs_exp % 10, abs_exp / 10);
220 self.exp_bytes[self.exp_len - 2] = b'0' + e1;
221 self.exp_bytes[self.exp_len - 1] = b'0' + e0;
222 } else {
223 self.exp_len += 1;
224 self.exp_bytes[self.exp_len - 1] = b'0' + abs_exp;
225 }
226 }
227
228 fn pad_and_print(&self, is_neg: bool, maybe_prefix: &str, fmt: &mut Formatter) -> FmtResult {
229 use core::fmt::Write;
230
231 let sign = if is_neg {
232 "-"
233 } else if fmt.sign_plus() {
234 "+"
235 } else {
236 ""
237 };
238 let prefix = if fmt.alternate() { maybe_prefix } else { "" };
239
240 let abs_begin = if self.exp_bytes[1] == b'-' {
257 self.int_digits
258 } else if self.int_digits == 0 || self.digits[0] != b'0' {
259 0
260 } else if self.digits[1] != b'0' {
261 1
262 } else {
263 2
264 };
265 let end_zeros = fmt.precision().map_or(0, |x| x - self.frac_digits);
266 let has_frac = self.frac_digits > 0 || end_zeros > 0;
267
268 let digits_width = 1 + self.int_digits + self.frac_digits - abs_begin;
269 let req_width = sign.len()
270 + prefix.len()
271 + digits_width
272 + usize::from(has_frac)
273 + end_zeros
274 + self.exp_len;
275 let pad = fmt
276 .width()
277 .and_then(|w| w.checked_sub(req_width))
278 .unwrap_or(0);
279 let (pad_left, pad_zeros, pad_right) = if fmt.sign_aware_zero_pad() {
280 (0, pad, 0)
281 } else {
282 match fmt.align() {
283 Some(Alignment::Left) => (0, 0, pad),
284 Some(Alignment::Center) => (pad / 2, 0, pad - pad / 2),
285 None | Some(Alignment::Right) => (pad, 0, 0),
286 }
287 };
288 let fill = fmt.fill();
289
290 for _ in 0..pad_left {
291 fmt.write_char(fill)?;
292 }
293 fmt.write_str(sign)?;
294 fmt.write_str(prefix)?;
295 for _ in 0..pad_zeros {
296 fmt.write_char('0')?;
297 }
298 let int_bytes = &self.digits[abs_begin..1 + self.int_digits];
299 fmt.write_str(str::from_utf8(int_bytes).unwrap())?;
300 if has_frac {
301 fmt.write_char('.')?;
302 let frac_bytes =
303 &self.digits[1 + self.int_digits..1 + self.int_digits + self.frac_digits];
304 fmt.write_str(str::from_utf8(frac_bytes).unwrap())?;
305 for _ in 0..end_zeros {
306 fmt.write_char('0')?;
307 }
308 }
309 fmt.write_str(str::from_utf8(&self.exp_bytes[..self.exp_len]).unwrap())?;
310 for _ in 0..pad_right {
311 fmt.write_char(fill)?;
312 }
313 Ok(())
314 }
315}
316
317fn update_truncation(truncation: &mut Truncation, mut truncated_frac: &[u8]) {
318 if truncated_frac.is_empty() {
319 return;
320 }
321
322 let mut leading_zeros = false;
323 while let [0, tail @ ..] = truncated_frac {
324 leading_zeros = true;
325 truncated_frac = tail;
326 }
327
328 if truncated_frac.is_empty() {
329 if *truncation != Truncation::Zero {
331 *truncation = Truncation::LessTie
332 }
333 return;
334 }
335
336 if leading_zeros {
337 *truncation = Truncation::LessTie;
339 return;
340 }
341
342 let first = truncated_frac[0];
344 truncated_frac = &truncated_frac[1..];
345
346 if first < 5 {
347 *truncation = Truncation::LessTie;
348 return;
349 }
350 if first > 5 || *truncation != Truncation::Zero {
351 *truncation = Truncation::GreaterTie;
352 return;
353 }
354 while let [0, tail @ ..] = truncated_frac {
356 truncated_frac = tail;
357 }
358 *truncation = if truncated_frac.is_empty() {
359 Truncation::Tie
360 } else {
361 Truncation::GreaterTie
362 }
363}
364
365#[derive(Clone, Copy, PartialEq)]
366enum Format {
367 Bin,
368 Oct,
369 LowHex,
370 UpHex,
371 Dec,
372 LowExp,
373 UpExp,
374}
375
376#[derive(PartialEq)]
377enum Truncation {
378 Zero,
379 LessTie,
380 Tie,
381 GreaterTie,
382}
383
384struct RoundingAddedMSDigit(bool);
385
386impl Format {
387 fn digit_bits(self) -> u32 {
388 match self {
389 Format::Bin => 1,
390 Format::Oct => 3,
391 Format::LowHex | Format::UpHex => 4,
392 Format::Dec | Format::LowExp | Format::UpExp => 4,
393 }
394 }
395 fn max_digit(self) -> u8 {
396 match self {
397 Format::Bin => 1,
398 Format::Oct => 7,
399 Format::LowHex | Format::UpHex => 15,
400 Format::Dec | Format::LowExp | Format::UpExp => 9,
401 }
402 }
403 fn prefix(self) -> &'static str {
404 match self {
405 Format::Bin => "0b",
406 Format::Oct => "0o",
407 Format::LowHex | Format::UpHex => "0x",
408 Format::Dec | Format::LowExp | Format::UpExp => "",
409 }
410 }
411}
412
413trait FmtHelper
414where
415 Self: Copy + Ord,
416 Self: Shl<u32, Output = Self> + Shr<u32, Output = Self> + Add<Output = Self>,
417 Self: WrappingCast<u8> + Mul10 + From<u8>,
418{
419 const ZERO: Self;
420 const MSB: Self;
421 const BITS: u32;
422
423 type Half: FmtHelper;
424
425 fn int_used_nbits(int: Self) -> u32;
426 fn frac_used_nbits(frac: Self) -> u32;
427 fn as_half(val: Self) -> Self::Half;
428 fn div_rem_10(val: Self) -> (Self, u8);
429 fn wrapping_neg(val: Self) -> Self;
430
431 fn write_int_radix2(mut int: Self, format: Format, nbits: u32, buf: &mut Buffer) {
432 if Self::Half::BITS == Self::BITS / 2 && nbits <= Self::Half::BITS {
433 return FmtHelper::write_int_radix2(Self::as_half(int), format, nbits, buf);
434 }
435 let digit_bits = format.digit_bits();
436 let mask = format.max_digit();
437 for b in buf.int().iter_mut().rev() {
438 debug_assert!(int != Self::ZERO);
439 *b = int.wrapping_as::<u8>() & mask;
440 int = int >> digit_bits;
441 }
442 debug_assert!(int == Self::ZERO);
443 }
444
445 fn write_frac_radix2(
446 mut frac: Self,
447 format: Format,
448 nbits: u32,
449 buf: &mut Buffer,
450 ) -> Truncation {
451 if Self::Half::BITS == Self::BITS / 2 && nbits <= Self::Half::BITS {
452 return FmtHelper::write_frac_radix2(
453 Self::as_half(frac >> Self::Half::BITS),
454 format,
455 nbits,
456 buf,
457 );
458 }
459 let digit_bits = format.digit_bits();
460 let compl_digit_bits = Self::BITS - digit_bits;
461 for b in &mut *buf.frac() {
462 debug_assert!(frac != Self::ZERO);
463 *b = (frac >> compl_digit_bits).wrapping_as::<u8>();
464 frac = frac << digit_bits;
465 }
466 if frac == Self::ZERO {
467 Truncation::Zero
468 } else {
469 match frac.cmp(&Self::MSB) {
470 Ordering::Less => Truncation::LessTie,
471 Ordering::Equal => Truncation::Tie,
472 Ordering::Greater => Truncation::GreaterTie,
473 }
474 }
475 }
476
477 fn write_int_dec(mut int: Self, nbits: u32, buf: &mut Buffer) -> usize {
479 if Self::Half::BITS == Self::BITS / 2 && nbits <= Self::Half::BITS {
480 return FmtHelper::write_int_dec(Self::as_half(int), nbits, buf);
481 }
482 let mut sig = 0;
483 for b in buf.int().iter_mut().rev() {
484 let (q, r) = Self::div_rem_10(int);
485 int = q;
486 *b = r;
487 if r != 0 || sig != 0 {
488 sig += 1;
489 }
490 }
491 debug_assert!(int == Self::ZERO);
492 sig
493 }
494
495 fn write_frac_dec(
498 mut frac: Self,
499 nbits: u32,
500 frac_format: DecFracFormat,
501 buf: &mut Buffer,
502 ) -> Truncation {
503 if Self::Half::BITS == Self::BITS / 2 && nbits <= Self::Half::BITS {
504 return FmtHelper::write_frac_dec(
505 Self::as_half(frac >> Self::Half::BITS),
506 nbits,
507 frac_format,
508 buf,
509 );
510 }
511
512 let mut is_past_point = !frac_format.has_exp || frac_format.int_sig_digits > 0;
513 let (auto_prec, mut rem_prec) = match frac_format.precision {
514 Some(prec) => (false, prec),
515 None => (true, 0),
516 };
517 if !auto_prec && frac_format.has_exp && is_past_point {
518 rem_prec = rem_prec.saturating_sub(frac_format.int_sig_digits - 1);
519 }
520 if !auto_prec && is_past_point && buf.frac_digits > rem_prec {
521 buf.frac_digits = rem_prec;
522 }
523
524 let (mut tie, mut add_5) = if nbits == Self::BITS {
526 (Self::ZERO, true)
527 } else {
528 (Self::MSB >> nbits, false)
529 };
530 for (i, b) in buf.frac().iter_mut().enumerate() {
531 *b = Mul10::mul10_assign(&mut frac);
532
533 if auto_prec && frac < Self::from(10) || Self::wrapping_neg(frac) < Self::from(10) {
535 buf.frac_digits = i + 1;
536 break;
537 }
538
539 if auto_prec {
540 Mul10::mul10_assign(&mut tie);
543 if add_5 {
544 tie = tie + Self::from(5);
545 add_5 = false;
546 }
547 if frac < tie || Self::wrapping_neg(frac) < tie {
548 buf.frac_digits = i + 1;
549 break;
550 }
551 } else if frac_format.has_exp {
552 debug_assert!(rem_prec > 0);
553 if is_past_point {
554 rem_prec -= 1;
555 if rem_prec == 0 {
556 buf.frac_digits = i + 1;
557 break;
558 }
559 } else if *b != 0 {
560 is_past_point = true;
561 }
563 }
564 }
565 if frac == Self::ZERO {
566 Truncation::Zero
567 } else {
568 match frac.cmp(&Self::MSB) {
569 Ordering::Less => Truncation::LessTie,
570 Ordering::Equal => Truncation::Tie,
571 Ordering::Greater => Truncation::GreaterTie,
572 }
573 }
574 }
575}
576
577macro_rules! impl_format_helper {
578 ($U:ident, $H:ident) => {
579 impl FmtHelper for $U {
580 const ZERO: $U = 0;
581 const MSB: $U = 1 << ($U::BITS - 1);
582 const BITS: u32 = $U::BITS;
583
584 type Half = $H;
585
586 fn int_used_nbits(int: $U) -> u32 {
587 $U::BITS - int.leading_zeros()
588 }
589
590 fn frac_used_nbits(frac: $U) -> u32 {
591 $U::BITS - frac.trailing_zeros()
592 }
593
594 fn as_half(val: $U) -> Self::Half {
595 val as Self::Half
596 }
597
598 fn div_rem_10(val: $U) -> ($U, u8) {
599 (val / 10, (val % 10).wrapping_cast())
600 }
601
602 fn wrapping_neg(val: $U) -> $U {
603 val.wrapping_neg()
604 }
605 }
606 };
607}
608
609impl_format_helper! { u8, u8 }
610impl_format_helper! { u16, u8 }
611impl_format_helper! { u32, u16 }
612impl_format_helper! { u64, u32 }
613impl_format_helper! { u128, u64 }
614
615fn fmt<U: FmtHelper>(
616 (neg, abs): (bool, U),
617 frac_nbits: u32,
618 format: Format,
619 fmt: &mut Formatter,
620) -> FmtResult {
621 let (int, frac) = if frac_nbits == 0 {
622 (abs, U::ZERO)
623 } else if frac_nbits == U::BITS {
624 (U::ZERO, abs)
625 } else {
626 (abs >> frac_nbits, abs << (U::BITS - frac_nbits))
627 };
628 match format {
629 Format::Bin | Format::Oct | Format::LowHex | Format::UpHex => {
630 fmt_radix2((neg, int, frac), format, fmt)
631 }
632 Format::Dec | Format::LowExp | Format::UpExp => {
633 fmt_dec((neg, int, frac), frac_nbits, format, fmt)
634 }
635 }
636}
637
638#[derive(Clone, Copy, Debug)]
639struct DecFracFormat {
640 int_sig_digits: usize,
641 has_exp: bool,
642 precision: Option<usize>,
643}
644
645fn fmt_dec<U: FmtHelper>(
646 (neg, int, frac): (bool, U, U),
647 frac_nbits: u32,
648 format: Format,
649 fmt: &mut Formatter,
650) -> FmtResult {
651 let int_used_nbits = FmtHelper::int_used_nbits(int);
652 let frac_used_nbits = FmtHelper::frac_used_nbits(frac);
653 let int_max_len = ceil_log10_2_times(int_used_nbits);
654 let frac_max_len = if fmt.precision().is_some() {
655 frac_used_nbits
657 } else {
658 ceil_log10_2_times(frac_nbits)
660 };
661 let mut buf = Buffer::new(int_max_len, frac_max_len);
662
663 let int_sig_digits = FmtHelper::write_int_dec(int, int_used_nbits, &mut buf);
664 let has_exp = matches!(format, Format::UpExp | Format::LowExp);
665 let frac_format = DecFracFormat {
666 int_sig_digits,
667 has_exp,
668 precision: fmt.precision(),
669 };
670 let mut truncation = FmtHelper::write_frac_dec(frac, frac_nbits, frac_format, &mut buf);
671 if has_exp {
672 buf.find_exp_dec(fmt.precision(), &mut truncation);
673 }
674 buf.finish(format, neg, truncation, fmt)
675}
676
677fn fmt_radix2<U: FmtHelper>(
678 (neg, int, frac): (bool, U, U),
679 format: Format,
680 fmt: &mut Formatter,
681) -> FmtResult {
682 let digit_bits = format.digit_bits();
683 let int_used_nbits = FmtHelper::int_used_nbits(int);
684 let int_digits = int_used_nbits.div_ceil(digit_bits);
685 let frac_used_nbits = FmtHelper::frac_used_nbits(frac);
686 let mut frac_digits = frac_used_nbits.div_ceil(digit_bits);
687 if let Some(precision) = fmt.precision() {
688 frac_digits = cmp::min(frac_digits as usize, precision) as u32;
690 }
691
692 let mut buf = Buffer::new(int_digits, frac_digits);
693 FmtHelper::write_int_radix2(int, format, int_used_nbits, &mut buf);
694 let frac_rem_cmp_tie = FmtHelper::write_frac_radix2(frac, format, frac_used_nbits, &mut buf);
696 buf.finish(format, neg, frac_rem_cmp_tie, fmt)
697}
698
699macro_rules! impl_fmt {
700 ($Fixed:ident($LeEqU:ident, $Inner:ident)) => {
701 impl<Frac: $LeEqU> Display for $Fixed<Frac> {
702 fn fmt(&self, f: &mut Formatter) -> FmtResult {
703 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
704 fmt(neg_abs, Self::FRAC_NBITS, Format::Dec, f)
705 }
706 }
707
708 impl<Frac: Unsigned> Debug for $Fixed<Frac> {
709 fn fmt(&self, f: &mut Formatter) -> FmtResult {
710 if Frac::U32 > $Inner::BITS {
711 match debug_hex::is_debug_hex(f) {
712 IsDebugHex::Lower => {
713 f.write_fmt(format_args!("(0x{:x}", self.to_bits()))?;
714 }
715 IsDebugHex::Upper => {
716 f.write_fmt(format_args!("(0x{:X}", self.to_bits()))?;
717 }
718 IsDebugHex::No => {
719 f.write_fmt(format_args!("({}", self.to_bits()))?;
720 }
721 }
722 return f.write_fmt(format_args!(" >> {})", Frac::U32));
723 }
724 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
725 match debug_hex::is_debug_hex(f) {
726 IsDebugHex::Lower => fmt(neg_abs, Frac::U32, Format::LowHex, f),
727 IsDebugHex::Upper => fmt(neg_abs, Frac::U32, Format::UpHex, f),
728 IsDebugHex::No => fmt(neg_abs, Frac::U32, Format::Dec, f),
729 }
730 }
731 }
732
733 impl<Frac: $LeEqU> Binary for $Fixed<Frac> {
734 fn fmt(&self, f: &mut Formatter) -> FmtResult {
735 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
736 fmt(neg_abs, Self::FRAC_NBITS, Format::Bin, f)
737 }
738 }
739
740 impl<Frac: $LeEqU> Octal for $Fixed<Frac> {
741 fn fmt(&self, f: &mut Formatter) -> FmtResult {
742 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
743 fmt(neg_abs, Self::FRAC_NBITS, Format::Oct, f)
744 }
745 }
746
747 impl<Frac: $LeEqU> LowerHex for $Fixed<Frac> {
748 fn fmt(&self, f: &mut Formatter) -> FmtResult {
749 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
750 fmt(neg_abs, Self::FRAC_NBITS, Format::LowHex, f)
751 }
752 }
753
754 impl<Frac: $LeEqU> UpperHex for $Fixed<Frac> {
755 fn fmt(&self, f: &mut Formatter) -> FmtResult {
756 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
757 fmt(neg_abs, Self::FRAC_NBITS, Format::UpHex, f)
758 }
759 }
760
761 impl<Frac: $LeEqU> LowerExp for $Fixed<Frac> {
762 fn fmt(&self, f: &mut Formatter) -> FmtResult {
763 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
764 fmt(neg_abs, Self::FRAC_NBITS, Format::LowExp, f)
765 }
766 }
767
768 impl<Frac: $LeEqU> UpperExp for $Fixed<Frac> {
769 fn fmt(&self, f: &mut Formatter) -> FmtResult {
770 let neg_abs = int_helper::$Inner::neg_abs(self.to_bits());
771 fmt(neg_abs, Self::FRAC_NBITS, Format::UpExp, f)
772 }
773 }
774 };
775}
776
777impl_fmt! { FixedU8(LeEqU8, u8) }
778impl_fmt! { FixedU16(LeEqU16, u16) }
779impl_fmt! { FixedU32(LeEqU32, u32) }
780impl_fmt! { FixedU64(LeEqU64, u64) }
781impl_fmt! { FixedU128(LeEqU128, u128) }
782impl_fmt! { FixedI8(LeEqU8, i8) }
783impl_fmt! { FixedI16(LeEqU16, i16) }
784impl_fmt! { FixedI32(LeEqU32, i32) }
785impl_fmt! { FixedI64(LeEqU64, i64) }
786impl_fmt! { FixedI128(LeEqU128, i128) }
787
788fn ceil_log10_2_times(int_bits: u32) -> u32 {
790 debug_assert!(int_bits < 112_816);
791 ((u64::from(int_bits) * 0x4D10_4D43 + 0xFFFF_FFFF) >> 32) as u32
792}
793
794pub(crate) trait Mul10: Sized {
795 fn mul10_assign(slf: &mut Self) -> u8;
796}
797macro_rules! mul10_widen {
798 ($Single:ty, $Double:ty) => {
799 impl Mul10 for $Single {
800 #[inline]
801 fn mul10_assign(x: &mut $Single) -> u8 {
802 let prod = <$Double>::from(*x) * 10;
803 *x = prod as $Single;
804 (prod >> <$Single>::BITS) as u8
805 }
806 }
807 };
808}
809mul10_widen! { u8, u16 }
810mul10_widen! { u16, u32 }
811mul10_widen! { u32, u64 }
812mul10_widen! { u64, u128 }
813impl Mul10 for u128 {
814 #[inline]
815 fn mul10_assign(x: &mut u128) -> u8 {
816 const LO_MASK: u128 = !(!0 << 64);
817 let hi = (*x >> 64) * 10;
818 let lo = (*x & LO_MASK) * 10;
819 let (hi_lo, hi_hi) = (hi as u64, (hi >> 64) as u64);
823 let (lo_lo, lo_hi) = (lo as u64, (lo >> 64) as u64);
824 let (wrapped, overflow) = hi_lo.overflowing_add(lo_hi);
825 *x = (u128::from(wrapped) << 64) | u128::from(lo_lo);
826 hi_hi as u8 + u8::from(overflow)
827 }
828}
829
830#[cfg(test)]
831mod tests {
832 use crate::display;
833 use crate::types::*;
834 use std::format;
835 #[cfg(not(feature = "std"))]
836 use std::string::{String, ToString};
837
838 #[test]
839 fn format() {
840 let pos = I16F16::from_num(12.3);
841 assert_eq!(format!("{pos:+}"), "+12.3");
842 assert_eq!(format!("{pos:.20}"), "12.30000305175781250000");
843 assert_eq!(format!("{pos:+08}"), "+00012.3");
844 assert_eq!(format!("{pos:+#08}"), "+00012.3");
845 assert_eq!(format!("{pos:+08X}"), "+0C.4CCD");
846 assert_eq!(format!("{pos:+08.1X}"), "+0000C.5");
847 assert_eq!(format!("{pos:+#08X}"), "+0xC.4CCD");
848 assert_eq!(format!("{pos:+#08.1X}"), "+0x00C.5");
849
850 assert_eq!(format!("{pos:#<8}"), "12.3####");
851 assert_eq!(format!("{pos:#^8}"), "##12.3##");
852 assert_eq!(format!("{pos:#^9}"), "##12.3###");
853 assert_eq!(format!("{pos:#>8}"), "####12.3");
854 assert_eq!(format!("{pos:#^08}"), "000012.3");
855
856 assert_eq!(format!("{pos:^8e}"), " 1.23e1 ");
857 assert_eq!(format!("{pos:^08E}"), "001.23E1");
858 assert_eq!(format!("{pos:.20e}"), "1.23000030517578125000e1");
859
860 let pos = I16F16::from_bits(9);
861 assert_eq!(format!("{pos}"), "0.00014");
862 assert_eq!(format!("{pos:.16}"), "0.0001373291015625");
863 assert_eq!(format!("{pos:e}"), "1.4e-4");
864 assert_eq!(format!("{pos:.16e}"), "1.3732910156250000e-4");
865
866 assert_eq!(format!("{:.1e}", I16F16::from_num(999)), "1.0e3");
867 assert_eq!(format!("{:.1e}", I16F16::from_num(1000)), "1.0e3");
868 assert_eq!(format!("{:.1e}", I16F16::from_num(1001)), "1.0e3");
869 assert_eq!(format!("{:.1e}", U0F32::lit("0.999")), "1.0e0");
870 assert_eq!(format!("{:.1e}", I16F16::lit("0.999")), "1.0e0");
871 assert_eq!(format!("{:.2e}", I16F16::lit("9.099")), "9.10e0");
872 }
873
874 fn trim_frac_zeros(mut x: &str) -> &str {
875 while x.ends_with('0') {
876 x = &x[..x.len() - 1];
877 }
878 if x.ends_with('.') {
879 x = &x[..x.len() - 1];
880 }
881 x
882 }
883
884 fn up_frac_digits(x: &mut String, frac_digits: usize) {
885 if let Some(point) = x.find('.') {
886 if let Some(additional) = frac_digits.checked_sub(x.len() - point - 1) {
887 x.reserve(additional);
888 for _ in 0..additional {
889 x.push('0');
890 }
891 }
892 } else {
893 x.reserve(frac_digits + 1);
894 x.push('.');
895 for _ in 0..frac_digits {
896 x.push('0');
897 }
898 }
899 }
900
901 #[test]
902 fn hex() {
903 for i in 0..(1u32 << 7) {
904 let p = 0x1234_5678_9abc_def0u64 ^ u64::from(i);
905 let n = -0x1234_5678_9abc_def0i64 ^ i64::from(i);
906 let f_p = U57F7::from_bits(p);
907 let f_n = I57F7::from_bits(n);
908 let mut check_p = format!("{:x}.{:02x}", p >> 7, (p & 0x7f) << 1);
909 up_frac_digits(&mut check_p, 1000);
910 let trimmed_p = trim_frac_zeros(&check_p);
911 let mut check_n = format!("-{:x}.{:02x}", n.abs() >> 7, (n.abs() & 0x7f) << 1);
912 up_frac_digits(&mut check_n, 1000);
913 let trimmed_n = trim_frac_zeros(&check_n);
914 assert_eq!(format!("{f_p:.1000x}"), check_p);
915 assert_eq!(format!("{f_p:x}"), trimmed_p);
916 assert_eq!(format!("{f_n:.1000x}"), check_n);
917 assert_eq!(format!("{f_n:x}"), trimmed_n);
918 }
919 }
920
921 #[test]
922 fn debug_hex() {
923 let v = I16F16::MAX;
924 assert_eq!(format!("{v:?}"), "32767.99998");
925 assert_eq!(format!("{v:x?}"), "7fff.ffff");
926 assert_eq!(format!("{v:X?}"), "7FFF.FFFF");
927 assert_eq!(format!("{v:010X?}"), "07FFF.FFFF");
928 }
929
930 #[test]
931 fn dec() {
932 for i in 0..(1 << 7) {
933 let bits = (!0u32 >> 8) ^ i;
935 let fix = U25F7::from_bits(bits);
936 let flt = (bits as f32) / 7f32.exp2();
937 assert_eq!(format!("{fix}"), format!("{flt}"));
938 assert_eq!(U25F7::from_num(flt), fix);
939 assert_eq!(fix.to_num::<f32>(), flt);
940 }
941 }
942
943 #[test]
944 fn display_frac() {
945 assert_eq!(
946 format!("{:X}", I0F128::from_bits(!0)),
947 "-0.00000000000000000000000000000001"
948 );
949 assert_eq!(format!("{:X}", I0F64::from_bits(!0)), "-0.0000000000000001");
950 assert_eq!(format!("{:X}", I0F32::from_bits(!0)), "-0.00000001");
951 assert_eq!(format!("{:X}", I0F16::from_bits(!0)), "-0.0001");
952 assert_eq!(format!("{:X}", I0F8::from_bits(!0)), "-0.01");
953 assert_eq!(
954 format!("{:X}", U0F128::from_bits(!0)),
955 "0.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
956 );
957 assert_eq!(format!("{:X}", U0F64::from_bits(!0)), "0.FFFFFFFFFFFFFFFF");
958 assert_eq!(format!("{:X}", U0F32::from_bits(!0)), "0.FFFFFFFF");
959 assert_eq!(format!("{:X}", U0F16::from_bits(!0)), "0.FFFF");
960 assert_eq!(format!("{:X}", U0F8::from_bits(!0)), "0.FF");
961
962 assert_eq!(
963 format!("{}", I0F128::from_bits(!0)),
964 "-0.000000000000000000000000000000000000003"
965 );
966 assert_eq!(
967 format!("{}", I0F64::from_bits(!0)),
968 "-0.00000000000000000005"
969 );
970 assert_eq!(format!("{}", I0F32::from_bits(!0)), "-0.0000000002");
971 assert_eq!(format!("{}", I0F16::from_bits(!0)), "-0.00002");
972 assert_eq!(format!("{}", I0F8::from_bits(!0)), "-0.004");
973 assert_eq!(
974 format!("{}", U0F128::from_bits(!0)),
975 "0.999999999999999999999999999999999999997"
976 );
977 assert_eq!(
978 format!("{}", U0F64::from_bits(!0)),
979 "0.99999999999999999995"
980 );
981 assert_eq!(format!("{}", U0F32::from_bits(!0)), "0.9999999998");
982 assert_eq!(format!("{}", U0F16::from_bits(!0)), "0.99998");
983 assert_eq!(format!("{}", U0F8::from_bits(!0)), "0.996");
984
985 let no_internal_overflow_bits = 0xe666_6666_6666_6665_ffff_ffff_ffff_ffffu128;
987 let internal_overflow_bits = 0xe666_6666_6666_6666_ffff_ffff_ffff_ffffu128;
988 assert_eq!(
989 format!("{:X}", U0F128::from_bits(no_internal_overflow_bits)),
990 "0.E666666666666665FFFFFFFFFFFFFFFF"
991 );
992 assert_eq!(
993 format!("{:X}", U0F128::from_bits(internal_overflow_bits)),
994 "0.E666666666666666FFFFFFFFFFFFFFFF"
995 );
996 assert_eq!(
997 format!("{}", U0F128::from_bits(no_internal_overflow_bits)),
998 "0.899999999999999999978315956550289911317"
999 );
1000 assert_eq!(
1001 format!("{}", U0F128::from_bits(internal_overflow_bits)),
1002 "0.900000000000000000032526065174565133017"
1003 );
1004 }
1005
1006 #[test]
1007 fn close_to_round_decimal() {
1008 for i in 0..1000u16 {
1009 let float = f32::from(i + 1000) / 1000.;
1012 let fix = U9F23::from_num(float);
1013 let check = format!("1.{i:03}");
1014 assert_eq!(format!("{fix}"), trim_frac_zeros(&check));
1015 assert_eq!(format!("{fix}"), format!("{float}"));
1016 for prec in 0..10 {
1017 assert_eq!(format!("{fix:.prec$}"), format!("{float:.prec$}"));
1018 }
1019 }
1020 }
1021
1022 #[test]
1023 fn check_ceil_log10_2_times() {
1024 for i in 0..112_816 {
1025 let check = (f64::from(i) * 2f64.log10()).ceil() as u32;
1026 assert_eq!(display::ceil_log10_2_times(i), check);
1027 }
1028 }
1029
1030 #[test]
1031 fn rounding() {
1032 let i = U8F8::from_bits(0xFF80);
1033 assert_eq!(format!("{i}"), "255.5");
1034 assert_eq!(format!("{i:?}"), "255.5");
1035 assert_eq!(format!("{i:.0}"), "256");
1036 assert_eq!(format!("{i:b}"), "11111111.1");
1037 assert_eq!(format!("{i:.0b}"), "100000000");
1038 assert_eq!(format!("{i:o}"), "377.4");
1039 assert_eq!(format!("{i:.0o}"), "400");
1040 assert_eq!(format!("{i:X}"), "FF.8");
1041 assert_eq!(format!("{i:.0X}"), "100");
1042
1043 let i = U8F8::from_bits(0xFE80);
1044 assert_eq!(format!("{i}"), "254.5");
1045 assert_eq!(format!("{i:?}"), "254.5");
1046 assert_eq!(format!("{i:.0}"), "254");
1047 assert_eq!(format!("{i:b}"), "11111110.1");
1048 assert_eq!(format!("{i:.0b}"), "11111110");
1049 assert_eq!(format!("{i:o}"), "376.4");
1050 assert_eq!(format!("{i:.0o}"), "376");
1051 assert_eq!(format!("{i:X}"), "FE.8");
1052 assert_eq!(format!("{i:.0X}"), "FE");
1053
1054 let i = U8F8::from_bits(0xDDDD);
1055 assert_eq!(format!("{i}"), "221.863");
1056 assert_eq!(format!("{i:?}"), "221.863");
1057 assert_eq!(format!("{i:.0}"), "222");
1058 assert_eq!(format!("{i:.1}"), "221.9");
1059 assert_eq!(format!("{i:.2}"), "221.86");
1060 assert_eq!(format!("{i:.3}"), "221.863");
1061 assert_eq!(format!("{i:.4}"), "221.8633");
1062 assert_eq!(format!("{i:.5}"), "221.86328");
1063 assert_eq!(format!("{i:.6}"), "221.863281");
1064 assert_eq!(format!("{i:.7}"), "221.8632812");
1065 assert_eq!(format!("{i:.8}"), "221.86328125");
1066 assert_eq!(format!("{i:.9}"), "221.863281250");
1067 assert_eq!(format!("{i:b}"), "11011101.11011101");
1068 assert_eq!(format!("{i:.0b}"), "11011110");
1069 assert_eq!(format!("{i:.1b}"), "11011110.0");
1070 assert_eq!(format!("{i:.2b}"), "11011101.11");
1071 assert_eq!(format!("{i:.3b}"), "11011101.111");
1072 assert_eq!(format!("{i:.4b}"), "11011101.1110");
1073 assert_eq!(format!("{i:.5b}"), "11011101.11100");
1074 assert_eq!(format!("{i:.6b}"), "11011101.110111");
1075 assert_eq!(format!("{i:.7b}"), "11011101.1101110");
1076 assert_eq!(format!("{i:.8b}"), "11011101.11011101");
1077 assert_eq!(format!("{i:.9b}"), "11011101.110111010");
1078 assert_eq!(format!("{i:o}"), "335.672");
1079 assert_eq!(format!("{i:.0o}"), "336");
1080 assert_eq!(format!("{i:.1o}"), "335.7");
1081 assert_eq!(format!("{i:.2o}"), "335.67");
1082 assert_eq!(format!("{i:.3o}"), "335.672");
1083 assert_eq!(format!("{i:.4o}"), "335.6720");
1084 assert_eq!(format!("{i:X}"), "DD.DD");
1085 assert_eq!(format!("{i:.0X}"), "DE");
1086 assert_eq!(format!("{i:.0X}"), "DE");
1087 assert_eq!(format!("{i:.1X}"), "DD.E");
1088 assert_eq!(format!("{i:.2X}"), "DD.DD");
1089 assert_eq!(format!("{i:.3X}"), "DD.DD0");
1090 }
1091
1092 #[test]
1093 fn compare_frac0_int() {
1094 for u in 0..=255u8 {
1095 let i = u as i8;
1096 let (ifix, ufix) = (I8F0::from_bits(i), U8F0::from_bits(u));
1097 assert_eq!(ifix.to_string(), i.to_string());
1098 assert_eq!(ufix.to_string(), u.to_string());
1099 if i >= 0 {
1100 assert_eq!(format!("{ifix:#X}"), format!("{i:#X}"));
1101 assert_eq!(format!("{ifix:#b}"), format!("{i:#b}"));
1102 } else {
1103 let abs_i = i.wrapping_neg() as u8;
1104 assert_eq!(format!("{ifix:#X}"), format!("-{abs_i:#X}"));
1105 assert_eq!(format!("{ifix:#b}"), format!("-{abs_i:#b}"));
1106 }
1107 assert_eq!(format!("{ufix:#x}"), format!("{u:#x}"));
1108 assert_eq!(format!("{ufix:#o}"), format!("{u:#o}"));
1109 }
1110 }
1111
1112 #[test]
1113 fn compare_frac4_float() {
1114 for u in 0..=255u8 {
1115 let (ifix, ufix) = (I4F4::from_bits(u as i8), U4F4::from_bits(u));
1120 let (iflo, uflo) = (ifix.to_num::<f32>(), ufix.to_num::<f32>());
1121 let (sifix, sufix) = (ifix.to_string(), ufix.to_string());
1122 let pifix = sifix.find('.').map_or(0, |p| sifix.len() - 1 - p);
1123 let pufix = sufix.find('.').map_or(0, |p| sufix.len() - 1 - p);
1124 let (siflo, suflo) = (format!("{iflo:.pifix$}"), format!("{uflo:.pufix$}"));
1125 assert_eq!(sifix, siflo);
1126 assert_eq!(sufix, suflo);
1127
1128 let ifixed =
1133 I28F4::from(ifix) + I28F4::from_num(i32::from(ifix.to_bits().signum()) << 19);
1134 let ufixed = U28F4::from(ufix) + U28F4::from_num(1 << 19);
1135 let (ifloat, ufloat) = (ifixed.to_num::<f32>(), ufixed.to_num::<f32>());
1136 let (sifixed, sufixed) = (ifixed.to_string(), ufixed.to_string());
1137 let (sifloat, sufloat) = (ifloat.to_string(), ufloat.to_string());
1138 assert_eq!(sifixed, sifloat);
1139 assert_eq!(sufixed, sufloat);
1140
1141 let sifix_frac = sifix.find('.').map(|i| &sifix[i..]);
1145 let sifixed_frac = sifixed.find('.').map(|i| &sifixed[i..]);
1146 assert_eq!(sifix_frac, sifixed_frac);
1147 let sufix_frac = sufix.find('.').map(|i| &sufix[i..]);
1148 let sufixed_frac = sufixed.find('.').map(|i| &sufixed[i..]);
1149 assert_eq!(sufix_frac, sufixed_frac);
1150 }
1151 }
1152
1153 #[test]
1154 fn compare_frac17_float() {
1155 for u in 0..(1 << 17) {
1156 let fix = U15F17::from_bits(u) + U15F17::from_num(99);
1158 let fix_pos = I15F17::from_num(fix);
1159 let fix_neg = -fix_pos;
1160 let (flo, flo_neg) = (fix.to_num::<f32>(), fix_neg.to_num::<f32>());
1161
1162 let fix_str = fix.to_string();
1163 let fix_pos_str = fix_pos.to_string();
1164 let fix_neg_str = fix_neg.to_string();
1165 assert_eq!(fix_str, flo.to_string());
1166 assert_eq!(fix_str, fix_pos_str);
1167 assert_eq!(fix_neg_str, flo_neg.to_string());
1168 if u != 0 {
1169 assert_eq!(&fix_neg_str[..1], "-");
1170 assert_eq!(&fix_neg_str[1..], fix_pos_str);
1171 }
1172
1173 let fix_str3 = format!("{fix:.3}");
1174 let fix_pos_str3 = format!("{fix_pos:.3}");
1175 let fix_neg_str3 = format!("{fix_neg:.3}");
1176 assert_eq!(fix_str3, format!("{flo:.3}"));
1177 assert_eq!(fix_str3, fix_pos_str3);
1178 assert_eq!(fix_neg_str3, format!("{flo_neg:.3}"));
1179 if u != 0 {
1180 assert_eq!(&fix_neg_str3[..1], "-");
1181 assert_eq!(&fix_neg_str3[1..], fix_pos_str3);
1182 }
1183 }
1184 }
1185
1186 #[test]
1187 fn exp_small_numbers() {
1188 assert_eq!(format!("{:e}", I0F64::DELTA), "5e-20");
1189 assert_eq!(format!("{:e}", I0F64::DELTA * 2), "1e-19");
1190 assert_eq!(format!("{:e}", I0F64::DELTA * 3), "1.6e-19");
1191 assert_eq!(format!("{:e}", I0F64::DELTA * 4), "2e-19");
1192 }
1193}