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}