Skip to main content

malachite_nz/natural/conversion/string/
to_string.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::natural::InnerNatural::{Large, Small};
10use crate::natural::Natural;
11use crate::natural::conversion::digits::general_digits::{
12    limbs_digit_count, limbs_to_digits_small_base_no_alg_specified,
13};
14use crate::natural::logic::significant_bits::limbs_significant_bits;
15use crate::platform::Limb;
16use alloc::string::String;
17#[cfg(feature = "test_build")]
18use core::fmt::Write;
19use core::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result, UpperHex};
20#[cfg(feature = "test_build")]
21use itertools::Itertools;
22use malachite_base::num::arithmetic::traits::{DivRound, Parity, ShrRound};
23use malachite_base::num::basic::integers::PrimitiveInt;
24use malachite_base::num::conversion::string::to_string::{
25    BaseFmtWrapper as BaseBaseFmtWrapper, digit_to_display_byte_lower, digit_to_display_byte_upper,
26};
27#[cfg(feature = "test_build")]
28use malachite_base::num::conversion::traits::PowerOf2DigitIterable;
29use malachite_base::num::conversion::traits::{Digits, ExactFrom, ToStringBase, WrappingFrom};
30#[cfg(feature = "test_build")]
31use malachite_base::num::logic::traits::{BitIterable, SignificantBits};
32use malachite_base::rounding_modes::RoundingMode::*;
33
34/// A `struct` that allows for formatting a [`Natural`] or [`Integer`](crate::integer::Integer) and
35/// rendering its digits in a specified base.
36#[derive(Clone, Eq, Hash, PartialEq)]
37pub struct BaseFmtWrapper<T> {
38    pub(crate) x: T,
39    pub(crate) base: u8,
40}
41
42impl<T> BaseFmtWrapper<T> {
43    /// Creates a new `BaseFmtWrapper`.
44    ///
45    /// # Worst-case complexity
46    /// Constant time and additional memory.
47    ///
48    /// # Panics
49    /// Panics if `base` is less than 2 or greater than 36.
50    ///
51    /// # Examples
52    /// ```
53    /// use malachite_nz::integer::Integer;
54    /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
55    /// use malachite_nz::natural::Natural;
56    ///
57    /// let n = Natural::from(1000000000u32);
58    /// let x = BaseFmtWrapper::new(&n, 36);
59    /// assert_eq!(format!("{}", x), "gjdgxs");
60    /// assert_eq!(format!("{:#}", x), "GJDGXS");
61    ///
62    /// let n = Integer::from(-1000000000);
63    /// let x = BaseFmtWrapper::new(&n, 36);
64    /// assert_eq!(format!("{}", x), "-gjdgxs");
65    /// assert_eq!(format!("{:#}", x), "-GJDGXS");
66    /// ```
67    pub fn new(x: T, base: u8) -> Self {
68        assert!((2..=36).contains(&base), "base out of range");
69        Self { x, base }
70    }
71
72    /// Recovers the value from a `BaseFmtWrapper`.
73    ///
74    /// # Worst-case complexity
75    /// Constant time and additional memory.
76    ///
77    /// # Examples
78    /// ```
79    /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
80    /// use malachite_nz::natural::Natural;
81    ///
82    /// assert_eq!(
83    ///     BaseFmtWrapper::new(Natural::from(1000000000u32), 36).unwrap(),
84    ///     1000000000
85    /// );
86    /// ```
87    #[allow(clippy::missing_const_for_fn)]
88    pub fn unwrap(self) -> T {
89        self.x
90    }
91}
92
93impl Display for BaseFmtWrapper<&Natural> {
94    /// Writes a wrapped [`Natural`] to a string using a specified base.
95    ///
96    /// If the base is greater than 10, lowercase alphabetic letters are used by default. Using the
97    /// `#` flag switches to uppercase letters. Padding with zeros works as usual.
98    ///
99    /// # Worst-case complexity
100    /// $T(n) = O(n (\log n)^2 \log\log n)$
101    ///
102    /// $M(n) = O(n \log n)$
103    ///
104    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
105    ///
106    /// # Panics
107    /// Panics if `base` is less than 2 or greater than 36.
108    ///
109    /// # Examples
110    /// ```
111    /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
112    /// use malachite_nz::natural::Natural;
113    ///
114    /// let n = Natural::from(1000000000u32);
115    /// let x = BaseFmtWrapper::new(&n, 36);
116    /// assert_eq!(format!("{}", x), "gjdgxs");
117    /// assert_eq!(format!("{:#}", x), "GJDGXS");
118    /// assert_eq!(format!("{:010}", x), "0000gjdgxs");
119    /// assert_eq!(format!("{:#010}", x), "0000GJDGXS");
120    /// ```
121    fn fmt(&self, f: &mut Formatter) -> Result {
122        assert!((2..=36).contains(&self.base), "base out of range");
123        if let Natural(Small(x)) = self.x {
124            Display::fmt(&BaseBaseFmtWrapper::new(*x, self.base), f)
125        } else {
126            let mut digits = self.x.to_digits_desc(&u8::wrapping_from(self.base));
127            if f.alternate() {
128                for digit in &mut digits {
129                    *digit = digit_to_display_byte_upper(*digit).unwrap();
130                }
131            } else {
132                for digit in &mut digits {
133                    *digit = digit_to_display_byte_lower(*digit).unwrap();
134                }
135            }
136            f.pad_integral(true, "", core::str::from_utf8(&digits).unwrap())
137        }
138    }
139}
140
141impl Debug for BaseFmtWrapper<&Natural> {
142    /// Writes a wrapped [`Natural`] to a string using a specified base.
143    ///
144    /// If the base is greater than 10, lowercase alphabetic letters are used by default. Using the
145    /// `#` flag switches to uppercase letters. Padding with zeros works as usual.
146    ///
147    /// This is the same as the [`Display::fmt`] implementation.
148    ///
149    /// # Worst-case complexity
150    /// $T(n) = O(n (\log n)^2 \log\log n)$
151    ///
152    /// $M(n) = O(n \log n)$
153    ///
154    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
155    ///
156    /// # Panics
157    /// Panics if `base` is less than 2 or greater than 36.
158    ///
159    /// # Examples
160    /// ```
161    /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
162    /// use malachite_nz::natural::Natural;
163    ///
164    /// let n = Natural::from(1000000000u32);
165    /// let x = BaseFmtWrapper::new(&n, 36);
166    /// assert_eq!(format!("{:?}", x), "gjdgxs");
167    /// assert_eq!(format!("{:#?}", x), "GJDGXS");
168    /// assert_eq!(format!("{:010?}", x), "0000gjdgxs");
169    /// assert_eq!(format!("{:#010?}", x), "0000GJDGXS");
170    /// ```
171    #[inline]
172    fn fmt(&self, f: &mut Formatter) -> Result {
173        Display::fmt(self, f)
174    }
175}
176
177impl ToStringBase for Natural {
178    /// Converts a [`Natural`] to a [`String`] using a specified base.
179    ///
180    /// Digits from 0 to 9 become [`char`]s from `'0'` to `'9'`. Digits from 10 to 35 become the
181    /// lowercase [`char`]s `'a'` to `'z'`.
182    ///
183    /// # Worst-case complexity
184    /// $T(n) = O(n (\log n)^2 \log\log n)$
185    ///
186    /// $M(n) = O(n \log n)$
187    ///
188    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
189    ///
190    /// # Panics
191    /// Panics if `base` is less than 2 or greater than 36.
192    ///
193    /// # Examples
194    /// ```
195    /// use malachite_base::num::conversion::traits::ToStringBase;
196    /// use malachite_nz::natural::Natural;
197    ///
198    /// assert_eq!(Natural::from(1000u32).to_string_base(2), "1111101000");
199    /// assert_eq!(Natural::from(1000u32).to_string_base(10), "1000");
200    /// assert_eq!(Natural::from(1000u32).to_string_base(36), "rs");
201    /// ```
202    fn to_string_base(&self, base: u8) -> String {
203        assert!((2..=36).contains(&base), "base out of range");
204        if let Self(Small(x)) = self {
205            x.to_string_base(base)
206        } else {
207            let mut digits = self.to_digits_desc(&base);
208            for digit in &mut digits {
209                *digit = digit_to_display_byte_lower(*digit).unwrap();
210            }
211            String::from_utf8(digits).unwrap()
212        }
213    }
214
215    /// Converts a [`Natural`] to a [`String`] using a specified base.
216    ///
217    /// Digits from 0 to 9 become [`char`]s from `'0'` to `'9'`. Digits from 10 to 35 become the
218    /// uppercase [`char`]s `'A'` to `'Z'`.
219    ///
220    /// # Worst-case complexity
221    /// $T(n) = O(n (\log n)^2 \log\log n)$
222    ///
223    /// $M(n) = O(n \log n)$
224    ///
225    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
226    ///
227    /// # Panics
228    /// Panics if `base` is less than 2 or greater than 36.
229    ///
230    /// # Examples
231    /// ```
232    /// use malachite_base::num::conversion::traits::ToStringBase;
233    /// use malachite_nz::natural::Natural;
234    ///
235    /// assert_eq!(Natural::from(1000u32).to_string_base_upper(2), "1111101000");
236    /// assert_eq!(Natural::from(1000u32).to_string_base_upper(10), "1000");
237    /// assert_eq!(Natural::from(1000u32).to_string_base_upper(36), "RS");
238    /// ```
239    fn to_string_base_upper(&self, base: u8) -> String {
240        assert!((2..=36).contains(&base), "base out of range");
241        if let Self(Small(x)) = self {
242            x.to_string_base_upper(base)
243        } else {
244            let mut digits = self.to_digits_desc(&base);
245            for digit in &mut digits {
246                *digit = digit_to_display_byte_upper(*digit).unwrap();
247            }
248            String::from_utf8(digits).unwrap()
249        }
250    }
251}
252
253impl Display for Natural {
254    /// Converts a [`Natural`] to a [`String`].
255    ///
256    /// # Worst-case complexity
257    /// $T(n) = O(n (\log n)^2 \log\log n)$
258    ///
259    /// $M(n) = O(n \log n)$
260    ///
261    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
262    ///
263    /// # Examples
264    /// ```
265    /// use core::str::FromStr;
266    /// use malachite_base::num::basic::traits::Zero;
267    /// use malachite_nz::natural::Natural;
268    ///
269    /// assert_eq!(Natural::ZERO.to_string(), "0");
270    /// assert_eq!(Natural::from(123u32).to_string(), "123");
271    /// assert_eq!(
272    ///     Natural::from_str("1000000000000").unwrap().to_string(),
273    ///     "1000000000000"
274    /// );
275    /// assert_eq!(format!("{:05}", Natural::from(123u32)), "00123");
276    /// ```
277    fn fmt(&self, f: &mut Formatter) -> Result {
278        match self {
279            Self(Small(x)) => Display::fmt(x, f),
280            Self(Large(xs)) => {
281                let mut digits = vec![0; usize::exact_from(limbs_digit_count(xs, 10))];
282                let mut xs = xs.clone();
283                let len = limbs_to_digits_small_base_no_alg_specified(&mut digits, 10, &mut xs);
284                digits.truncate(len);
285                for digit in &mut digits {
286                    *digit = digit_to_display_byte_lower(*digit).unwrap();
287                }
288                f.pad_integral(true, "", core::str::from_utf8(&digits).unwrap())
289            }
290        }
291    }
292}
293
294impl Debug for Natural {
295    /// Converts a [`Natural`] to a [`String`].
296    ///
297    /// This is the same as the [`Display::fmt`] implementation.
298    ///
299    /// # Worst-case complexity
300    /// $T(n) = O(n (\log n)^2 \log\log n)$
301    ///
302    /// $M(n) = O(n \log n)$
303    ///
304    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
305    ///
306    /// # Examples
307    /// ```
308    /// use core::str::FromStr;
309    /// use malachite_base::num::basic::traits::Zero;
310    /// use malachite_base::strings::ToDebugString;
311    /// use malachite_nz::natural::Natural;
312    ///
313    /// assert_eq!(Natural::ZERO.to_debug_string(), "0");
314    /// assert_eq!(Natural::from(123u32).to_debug_string(), "123");
315    /// assert_eq!(
316    ///     Natural::from_str("1000000000000")
317    ///         .unwrap()
318    ///         .to_debug_string(),
319    ///     "1000000000000"
320    /// );
321    /// assert_eq!(format!("{:05?}", Natural::from(123u32)), "00123");
322    /// ```
323    #[inline]
324    fn fmt(&self, f: &mut Formatter) -> Result {
325        Display::fmt(self, f)
326    }
327}
328
329#[cfg(feature = "test_build")]
330pub struct NaturalAlt(pub Natural);
331
332#[cfg(feature = "test_build")]
333pub struct NaturalAlt2(pub Natural);
334
335#[cfg(feature = "test_build")]
336impl Binary for NaturalAlt {
337    fn fmt(&self, f: &mut Formatter) -> Result {
338        if let Natural(Small(x)) = self.0 {
339            Binary::fmt(&x, f)
340        } else {
341            if f.alternate() {
342                f.write_str("0b")?;
343            }
344            if let Some(width) = f.width() {
345                let mut len = usize::exact_from(self.0.significant_bits());
346                if f.alternate() {
347                    len += 2;
348                }
349                for _ in 0..width.saturating_sub(len) {
350                    f.write_char('0')?;
351                }
352            }
353            for bit in self.0.bits().rev() {
354                f.write_char(if bit { '1' } else { '0' })?;
355            }
356            Ok(())
357        }
358    }
359}
360
361#[cfg(feature = "test_build")]
362impl Binary for NaturalAlt2 {
363    fn fmt(&self, f: &mut Formatter) -> Result {
364        match &self.0 {
365            Natural(Small(x)) => Binary::fmt(x, f),
366            Natural(Large(xs)) => {
367                let (xs_last, xs_init) = xs.split_last().unwrap();
368                let width = if let Some(width) = f.width() {
369                    width.saturating_sub(xs_init.len() << Limb::LOG_WIDTH)
370                } else {
371                    0
372                };
373                let mut result = if f.alternate() {
374                    write!(f, "{xs_last:#0width$b}")
375                } else {
376                    write!(f, "{xs_last:0width$b}")
377                };
378                for x in xs_init.iter().rev() {
379                    #[cfg(feature = "32_bit_limbs")]
380                    {
381                        result = write!(f, "{x:032b}");
382                    }
383                    #[cfg(not(feature = "32_bit_limbs"))]
384                    {
385                        result = write!(f, "{x:064b}");
386                    }
387                }
388                result
389            }
390        }
391    }
392}
393
394impl Binary for Natural {
395    /// Converts a [`Natural`] to a binary [`String`].
396    ///
397    /// Using the `#` format flag prepends `"0b"` to the string.
398    ///
399    /// # Worst-case complexity
400    /// $T(n) = O(n)$
401    ///
402    /// $M(n) = O(n)$
403    ///
404    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
405    ///
406    /// # Examples
407    /// ```
408    /// use core::str::FromStr;
409    /// use malachite_base::num::basic::traits::Zero;
410    /// use malachite_base::strings::ToBinaryString;
411    /// use malachite_nz::natural::Natural;
412    ///
413    /// assert_eq!(Natural::ZERO.to_binary_string(), "0");
414    /// assert_eq!(Natural::from(123u32).to_binary_string(), "1111011");
415    /// assert_eq!(
416    ///     Natural::from_str("1000000000000")
417    ///         .unwrap()
418    ///         .to_binary_string(),
419    ///     "1110100011010100101001010001000000000000"
420    /// );
421    /// assert_eq!(format!("{:011b}", Natural::from(123u32)), "00001111011");
422    ///
423    /// assert_eq!(format!("{:#b}", Natural::ZERO), "0b0");
424    /// assert_eq!(format!("{:#b}", Natural::from(123u32)), "0b1111011");
425    /// assert_eq!(
426    ///     format!("{:#b}", Natural::from_str("1000000000000").unwrap()),
427    ///     "0b1110100011010100101001010001000000000000"
428    /// );
429    /// assert_eq!(format!("{:#011b}", Natural::from(123u32)), "0b001111011");
430    /// ```
431    fn fmt(&self, f: &mut Formatter) -> Result {
432        match self {
433            Self(Small(x)) => Binary::fmt(x, f),
434            Self(Large(xs)) => {
435                let mut bits = vec![0; usize::exact_from(limbs_significant_bits(xs))];
436                let mut limbs = xs.iter();
437                let mut limb = *limbs.next().unwrap();
438                let mut remaining_bits = Limb::WIDTH;
439                for bit in bits.iter_mut().rev() {
440                    if remaining_bits == 0 {
441                        remaining_bits = Limb::WIDTH;
442                        limb = *limbs.next().unwrap();
443                    }
444                    *bit = if limb.even() { b'0' } else { b'1' };
445                    limb >>= 1;
446                    remaining_bits -= 1;
447                }
448                f.pad_integral(true, "0b", core::str::from_utf8(&bits).unwrap())
449            }
450        }
451    }
452}
453
454#[cfg(feature = "test_build")]
455impl Octal for NaturalAlt {
456    fn fmt(&self, f: &mut Formatter) -> Result {
457        if let Natural(Small(x)) = self.0 {
458            Octal::fmt(&x, f)
459        } else {
460            if f.alternate() {
461                f.write_str("0o")?;
462            }
463            if let Some(width) = f.width() {
464                let mut len = usize::exact_from(self.0.significant_bits().div_round(3, Ceiling).0);
465                if f.alternate() {
466                    len += 2;
467                }
468                for _ in 0..width.saturating_sub(len) {
469                    f.write_char('0')?;
470                }
471            }
472            for digit in PowerOf2DigitIterable::<u8>::power_of_2_digits(&self.0, 3).rev() {
473                f.write_char(char::from(digit_to_display_byte_lower(digit).unwrap()))?;
474            }
475            Ok(())
476        }
477    }
478}
479
480#[cfg(feature = "test_build")]
481#[cfg(feature = "32_bit_limbs")]
482fn oz_fmt(f: &mut Formatter, x: Limb) -> Result {
483    write!(f, "{x:08o}")
484}
485#[cfg(feature = "test_build")]
486#[cfg(not(feature = "32_bit_limbs"))]
487fn oz_fmt(f: &mut Formatter, x: Limb) -> Result {
488    write!(f, "{x:016o}")
489}
490
491#[cfg(feature = "test_build")]
492impl Octal for NaturalAlt2 {
493    fn fmt(&self, f: &mut Formatter) -> Result {
494        match &self.0 {
495            Natural(Small(x)) => Octal::fmt(x, f),
496            Natural(Large(xs)) => {
497                if f.alternate() {
498                    f.write_str("0o")?;
499                }
500                if let Some(width) = f.width() {
501                    let mut len =
502                        usize::exact_from(limbs_significant_bits(xs).div_round(3, Ceiling).0);
503                    if f.alternate() {
504                        len += 2;
505                    }
506                    for _ in 0..width.saturating_sub(len) {
507                        f.write_char('0')?;
508                    }
509                }
510                let mut triple_r = xs.len() % 3;
511                if triple_r == 0 {
512                    triple_r = 3;
513                }
514                let mut result;
515                let last_i = xs.len() - 1;
516                const W_1_2: u64 = Limb::WIDTH >> 1;
517                const W_1_4: u64 = Limb::WIDTH >> 2;
518                const W_3_4: u64 = W_1_4 * 3;
519                const MASK: Limb = (1 << W_3_4) - 1;
520                match triple_r {
521                    1 => {
522                        let x_2 = xs[last_i];
523                        let y = x_2 >> W_3_4;
524                        if y == 0 {
525                            result = write!(f, "{:o}", x_2 & MASK);
526                        } else {
527                            write!(f, "{y:o}").unwrap();
528                            result = oz_fmt(f, x_2 & MASK);
529                        }
530                    }
531                    2 => {
532                        let x_1 = xs[last_i];
533                        let x_2 = xs[last_i - 1];
534                        let y = x_1 >> W_1_2;
535                        if y == 0 {
536                            write!(f, "{:o}", ((x_1 << W_1_4) & MASK) | (x_2 >> W_3_4)).unwrap();
537                        } else {
538                            write!(f, "{y:o}").unwrap();
539                            oz_fmt(f, ((x_1 << W_1_4) & MASK) | (x_2 >> W_3_4)).unwrap();
540                        }
541                        result = oz_fmt(f, x_2 & MASK);
542                    }
543                    _ => {
544                        let x_0 = xs[last_i];
545                        let x_1 = xs[last_i - 1];
546                        let x_2 = xs[last_i - 2];
547                        let y = x_0 >> W_1_4;
548                        if y == 0 {
549                            write!(f, "{:o}", ((x_0 << W_1_2) & MASK) | (x_1 >> W_1_2)).unwrap();
550                        } else {
551                            write!(f, "{y:o}").unwrap();
552                            oz_fmt(f, ((x_0 << W_1_2) & MASK) | (x_1 >> W_1_2)).unwrap();
553                        }
554                        oz_fmt(f, ((x_1 << W_1_4) & MASK) | (x_2 >> W_3_4)).unwrap();
555                        result = oz_fmt(f, x_2 & MASK);
556                    }
557                }
558                for mut chunk in &xs.iter().rev().skip(triple_r).chunks(3) {
559                    let x_0 = chunk.next().unwrap();
560                    let x_1 = chunk.next().unwrap();
561                    let x_2 = chunk.next().unwrap();
562                    oz_fmt(f, x_0 >> W_1_4).unwrap();
563                    oz_fmt(f, ((x_0 << W_1_2) & MASK) | (x_1 >> W_1_2)).unwrap();
564                    oz_fmt(f, ((x_1 << W_1_4) & MASK) | (x_2 >> W_3_4)).unwrap();
565                    result = oz_fmt(f, x_2 & MASK);
566                }
567                result
568            }
569        }
570    }
571}
572
573impl Octal for Natural {
574    /// Converts a [`Natural`] to an octal [`String`].
575    ///
576    /// Using the `#` format flag prepends `"0o"` to the string.
577    ///
578    /// # Worst-case complexity
579    /// $T(n) = O(n)$
580    ///
581    /// $M(n) = O(n)$
582    ///
583    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
584    ///
585    /// # Examples
586    /// ```
587    /// use core::str::FromStr;
588    /// use malachite_base::num::basic::traits::Zero;
589    /// use malachite_base::strings::ToOctalString;
590    /// use malachite_nz::natural::Natural;
591    ///
592    /// assert_eq!(Natural::ZERO.to_octal_string(), "0");
593    /// assert_eq!(Natural::from(123u32).to_octal_string(), "173");
594    /// assert_eq!(
595    ///     Natural::from_str("1000000000000")
596    ///         .unwrap()
597    ///         .to_octal_string(),
598    ///     "16432451210000"
599    /// );
600    /// assert_eq!(format!("{:07o}", Natural::from(123u32)), "0000173");
601    ///
602    /// assert_eq!(format!("{:#o}", Natural::ZERO), "0o0");
603    /// assert_eq!(format!("{:#o}", Natural::from(123u32)), "0o173");
604    /// assert_eq!(
605    ///     format!("{:#o}", Natural::from_str("1000000000000").unwrap()),
606    ///     "0o16432451210000"
607    /// );
608    /// assert_eq!(format!("{:#07o}", Natural::from(123u32)), "0o00173");
609    /// ```
610    fn fmt(&self, f: &mut Formatter) -> Result {
611        match self {
612            Self(Small(x)) => Octal::fmt(x, f),
613            Self(Large(xs)) => {
614                let mut digits =
615                    vec![0; usize::exact_from(limbs_significant_bits(xs).div_round(3, Ceiling).0)];
616                let mut limbs = xs.iter();
617                let mut remaining_bits = Limb::WIDTH;
618                let mut limb = *limbs.next().unwrap();
619                for digit in digits.iter_mut().rev() {
620                    if remaining_bits >= 3 {
621                        *digit = digit_to_display_byte_lower(u8::wrapping_from(limb & 7)).unwrap();
622                        remaining_bits -= 3;
623                        limb >>= 3;
624                    } else {
625                        match remaining_bits {
626                            0 => {
627                                limb = *limbs.next().unwrap();
628                                *digit = digit_to_display_byte_lower(u8::wrapping_from(limb & 7))
629                                    .unwrap();
630                                remaining_bits = Limb::WIDTH - 3;
631                                limb >>= 3;
632                            }
633                            1 => {
634                                let previous_limb = limb;
635                                limb = *limbs.next().unwrap_or(&0);
636                                *digit = digit_to_display_byte_lower(u8::wrapping_from(
637                                    ((limb & 3) << 1) | previous_limb,
638                                ))
639                                .unwrap();
640                                remaining_bits = Limb::WIDTH - 2;
641                                limb >>= 2;
642                            }
643                            _ => {
644                                let previous_limb = limb;
645                                limb = *limbs.next().unwrap_or(&0);
646                                *digit = digit_to_display_byte_lower(u8::wrapping_from(
647                                    ((limb & 1) << 2) | previous_limb,
648                                ))
649                                .unwrap();
650                                remaining_bits = Limb::WIDTH - 1;
651                                limb >>= 1;
652                            }
653                        }
654                    }
655                }
656                f.pad_integral(true, "0o", core::str::from_utf8(&digits).unwrap())
657            }
658        }
659    }
660}
661
662#[cfg(feature = "test_build")]
663impl LowerHex for NaturalAlt {
664    fn fmt(&self, f: &mut Formatter) -> Result {
665        if let Natural(Small(x)) = self.0 {
666            LowerHex::fmt(&x, f)
667        } else {
668            if f.alternate() {
669                f.write_str("0x")?;
670            }
671            if let Some(width) = f.width() {
672                let mut len = usize::exact_from(self.0.significant_bits().shr_round(2, Ceiling).0);
673                if f.alternate() {
674                    len += 2;
675                }
676                for _ in 0..width.saturating_sub(len) {
677                    f.write_char('0')?;
678                }
679            }
680            for digit in PowerOf2DigitIterable::<u8>::power_of_2_digits(&self.0, 4).rev() {
681                f.write_char(char::from(digit_to_display_byte_lower(digit).unwrap()))?;
682            }
683            Ok(())
684        }
685    }
686}
687
688#[cfg(feature = "test_build")]
689impl LowerHex for NaturalAlt2 {
690    fn fmt(&self, f: &mut Formatter) -> Result {
691        match &self.0 {
692            Natural(Small(x)) => LowerHex::fmt(x, f),
693            Natural(Large(xs)) => {
694                let (xs_last, xs_init) = xs.split_last().unwrap();
695                let width = if let Some(width) = f.width() {
696                    width.saturating_sub(xs_init.len() << Limb::LOG_WIDTH >> 2)
697                } else {
698                    0
699                };
700                let mut result = if f.alternate() {
701                    write!(f, "{xs_last:#0width$x}")
702                } else {
703                    write!(f, "{xs_last:0width$x}")
704                };
705                for x in xs_init.iter().rev() {
706                    #[cfg(feature = "32_bit_limbs")]
707                    {
708                        result = write!(f, "{x:08x}");
709                    }
710                    #[cfg(not(feature = "32_bit_limbs"))]
711                    {
712                        result = write!(f, "{x:016x}");
713                    }
714                }
715                result
716            }
717        }
718    }
719}
720
721impl LowerHex for Natural {
722    /// Converts a [`Natural`] to a hexadecimal [`String`] using lowercase characters.
723    ///
724    /// Using the `#` format flag prepends `"0x"` to the string.
725    ///
726    /// # Worst-case complexity
727    /// $T(n) = O(n)$
728    ///
729    /// $M(n) = O(n)$
730    ///
731    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
732    ///
733    /// # Examples
734    /// ```
735    /// use core::str::FromStr;
736    /// use malachite_base::num::basic::traits::Zero;
737    /// use malachite_base::strings::ToLowerHexString;
738    /// use malachite_nz::natural::Natural;
739    ///
740    /// assert_eq!(Natural::ZERO.to_lower_hex_string(), "0");
741    /// assert_eq!(Natural::from(123u32).to_lower_hex_string(), "7b");
742    /// assert_eq!(
743    ///     Natural::from_str("1000000000000")
744    ///         .unwrap()
745    ///         .to_lower_hex_string(),
746    ///     "e8d4a51000"
747    /// );
748    /// assert_eq!(format!("{:07x}", Natural::from(123u32)), "000007b");
749    ///
750    /// assert_eq!(format!("{:#x}", Natural::ZERO), "0x0");
751    /// assert_eq!(format!("{:#x}", Natural::from(123u32)), "0x7b");
752    /// assert_eq!(
753    ///     format!("{:#x}", Natural::from_str("1000000000000").unwrap()),
754    ///     "0xe8d4a51000"
755    /// );
756    /// assert_eq!(format!("{:#07x}", Natural::from(123u32)), "0x0007b");
757    /// ```
758    fn fmt(&self, f: &mut Formatter) -> Result {
759        match self {
760            Self(Small(x)) => LowerHex::fmt(x, f),
761            Self(Large(xs)) => {
762                const DIGITS_PER_LIMB: u64 = Limb::WIDTH >> 2;
763                let mut digits =
764                    vec![0; usize::exact_from(limbs_significant_bits(xs).shr_round(2, Ceiling).0)];
765                let mut limbs = xs.iter();
766                let mut limb = *limbs.next().unwrap();
767                let mut remaining_digits = DIGITS_PER_LIMB;
768                for digit in digits.iter_mut().rev() {
769                    if remaining_digits == 0 {
770                        remaining_digits = DIGITS_PER_LIMB;
771                        limb = *limbs.next().unwrap();
772                    }
773                    *digit = digit_to_display_byte_lower(u8::wrapping_from(limb & 15)).unwrap();
774                    limb >>= 4;
775                    remaining_digits -= 1;
776                }
777                f.pad_integral(true, "0x", core::str::from_utf8(&digits).unwrap())
778            }
779        }
780    }
781}
782
783impl UpperHex for Natural {
784    /// Converts a [`Natural`] to a hexadecimal [`String`] using uppercase characters.
785    ///
786    /// Using the `#` format flag prepends `"0x"` to the string.
787    ///
788    /// # Worst-case complexity
789    /// $T(n) = O(n)$
790    ///
791    /// $M(n) = O(n)$
792    ///
793    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
794    ///
795    /// # Examples
796    /// ```
797    /// use core::str::FromStr;
798    /// use malachite_base::num::basic::traits::Zero;
799    /// use malachite_base::strings::ToUpperHexString;
800    /// use malachite_nz::natural::Natural;
801    ///
802    /// assert_eq!(Natural::ZERO.to_upper_hex_string(), "0");
803    /// assert_eq!(Natural::from(123u32).to_upper_hex_string(), "7B");
804    /// assert_eq!(
805    ///     Natural::from_str("1000000000000")
806    ///         .unwrap()
807    ///         .to_upper_hex_string(),
808    ///     "E8D4A51000"
809    /// );
810    /// assert_eq!(format!("{:07X}", Natural::from(123u32)), "000007B");
811    ///
812    /// assert_eq!(format!("{:#X}", Natural::ZERO), "0x0");
813    /// assert_eq!(format!("{:#X}", Natural::from(123u32)), "0x7B");
814    /// assert_eq!(
815    ///     format!("{:#X}", Natural::from_str("1000000000000").unwrap()),
816    ///     "0xE8D4A51000"
817    /// );
818    /// assert_eq!(format!("{:#07X}", Natural::from(123u32)), "0x0007B");
819    /// ```
820    fn fmt(&self, f: &mut Formatter) -> Result {
821        match self {
822            Self(Small(x)) => UpperHex::fmt(x, f),
823            Self(Large(xs)) => {
824                const DIGITS_PER_LIMB: u64 = Limb::WIDTH >> 2;
825                let mut digits =
826                    vec![0; usize::exact_from(limbs_significant_bits(xs).shr_round(2, Ceiling).0)];
827                let mut limbs = xs.iter();
828                let mut limb = *limbs.next().unwrap();
829                let mut remaining_digits = DIGITS_PER_LIMB;
830                for digit in digits.iter_mut().rev() {
831                    if remaining_digits == 0 {
832                        remaining_digits = DIGITS_PER_LIMB;
833                        limb = *limbs.next().unwrap();
834                    }
835                    *digit = digit_to_display_byte_upper(u8::wrapping_from(limb & 15)).unwrap();
836                    limb >>= 4;
837                    remaining_digits -= 1;
838                }
839                f.pad_integral(true, "0x", core::str::from_utf8(&digits).unwrap())
840            }
841        }
842    }
843}