malachite_nz/integer/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::integer::Integer;
10use crate::natural::conversion::string::to_string::BaseFmtWrapper;
11use alloc::string::{String, ToString};
12use core::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result, UpperHex, Write};
13use malachite_base::num::conversion::string::to_string::{
14 digit_to_display_byte_large, digit_to_display_byte_lower, digit_to_display_byte_upper,
15};
16use malachite_base::num::conversion::traits::{Digits, ToStringBase, WrappingFrom};
17use malachite_base::strings::{ToBinaryString, ToLowerHexString, ToOctalString, ToUpperHexString};
18use malachite_base::vecs::vec_pad_left;
19
20impl Display for BaseFmtWrapper<&Integer> {
21 /// Writes a wrapped [`Integer`] to a string using a specified base.
22 ///
23 /// If the base is greater than 10, lowercase alphabetic letters are used by default. Using the
24 /// `#` flag switches to uppercase letters (it has no effect above base 36, where the two cases
25 /// are distinct digits). Padding with zeros works as usual.
26 ///
27 /// # Worst-case complexity
28 /// $T(n) = O(n (\log n)^2 \log\log n)$
29 ///
30 /// $M(n) = O(n \log n)$
31 ///
32 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
33 ///
34 /// # Panics
35 /// Panics if `base` is less than 2 or greater than 62.
36 ///
37 /// # Examples
38 /// ```
39 /// use malachite_nz::integer::Integer;
40 /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
41 ///
42 /// let n = Integer::from(-1000000000);
43 /// let x = BaseFmtWrapper::new(&n, 36);
44 /// assert_eq!(format!("{}", x), "-gjdgxs");
45 /// assert_eq!(format!("{:#}", x), "-GJDGXS");
46 /// assert_eq!(format!("{:010}", x), "-000gjdgxs");
47 /// assert_eq!(format!("{:#010}", x), "-000GJDGXS");
48 /// ```
49 fn fmt(&self, f: &mut Formatter) -> Result {
50 if !self.x.sign && (f.width().is_some() || f.sign_plus()) {
51 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
52 // sign-aware zero flag, and fill and alignment.
53 let s = if f.alternate() {
54 self.x
55 .unsigned_abs_ref()
56 .to_string_base_upper(u8::wrapping_from(self.base))
57 } else {
58 self.x
59 .unsigned_abs_ref()
60 .to_string_base(u8::wrapping_from(self.base))
61 };
62 return f.pad_integral(false, "", &s);
63 }
64 if !self.x.sign {
65 f.write_char('-')?;
66 }
67 Display::fmt(
68 &BaseFmtWrapper::new(self.x.unsigned_abs_ref(), self.base),
69 f,
70 )
71 }
72}
73
74impl Debug for BaseFmtWrapper<&Integer> {
75 /// Writes a wrapped [`Integer`] to a string using a specified base.
76 ///
77 /// If the base is greater than 10, lowercase alphabetic letters are used by default. Using the
78 /// `#` flag switches to uppercase letters (it has no effect above base 36, where the two cases
79 /// are distinct digits). Padding with zeros works as usual.
80 ///
81 /// This is the same as the [`Display::fmt`] implementation.
82 ///
83 /// # Worst-case complexity
84 /// $T(n) = O(n (\log n)^2 \log\log n)$
85 ///
86 /// $M(n) = O(n \log n)$
87 ///
88 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
89 ///
90 /// # Panics
91 /// Panics if `base` is less than 2 or greater than 62.
92 ///
93 /// # Examples
94 /// ```
95 /// use malachite_nz::integer::Integer;
96 /// use malachite_nz::natural::conversion::string::to_string::BaseFmtWrapper;
97 ///
98 /// let n = Integer::from(-1000000000);
99 /// let x = BaseFmtWrapper::new(&n, 36);
100 /// assert_eq!(format!("{:?}", x), "-gjdgxs");
101 /// assert_eq!(format!("{:#?}", x), "-GJDGXS");
102 /// assert_eq!(format!("{:010?}", x), "-000gjdgxs");
103 /// assert_eq!(format!("{:#010?}", x), "-000GJDGXS");
104 /// ```
105 #[inline]
106 fn fmt(&self, f: &mut Formatter) -> Result {
107 Display::fmt(self, f)
108 }
109}
110
111impl ToStringBase for Integer {
112 /// Converts an [`Integer`] to a [`String`] using a specified base.
113 ///
114 /// For bases up to 36, digits from 0 to 9 become [`char`]s from `'0'` to `'9'` and digits from
115 /// 10 to 35 become the lowercase [`char`]s `'a'` to `'z'`. For bases from 37 through 62 the
116 /// uppercase and lowercase letters are distinct digits, `'A'` through `'Z'` representing 10
117 /// through 35 and `'a'` through `'z'` representing 36 through 61, as in GMP.
118 ///
119 /// # Worst-case complexity
120 /// $T(n) = O(n (\log n)^2 \log\log n)$
121 ///
122 /// $M(n) = O(n \log n)$
123 ///
124 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
125 ///
126 /// # Panics
127 /// Panics if `base` is less than 2 or greater than 62.
128 ///
129 /// # Examples
130 /// ```
131 /// use malachite_base::num::conversion::traits::ToStringBase;
132 /// use malachite_nz::integer::Integer;
133 ///
134 /// assert_eq!(Integer::from(1000).to_string_base(2), "1111101000");
135 /// assert_eq!(Integer::from(1000).to_string_base(10), "1000");
136 /// assert_eq!(Integer::from(1000).to_string_base(36), "rs");
137 ///
138 /// assert_eq!(Integer::from(-1000).to_string_base(2), "-1111101000");
139 /// assert_eq!(Integer::from(-1000).to_string_base(10), "-1000");
140 /// assert_eq!(Integer::from(-1000).to_string_base(36), "-rs");
141 /// // above base 36, the uppercase and lowercase letters are distinct digits
142 /// assert_eq!(Integer::from(-1000).to_string_base(62), "-G8");
143 /// ```
144 fn to_string_base(&self, base: u8) -> String {
145 assert!((2..=62).contains(&base), "base out of range");
146 if *self == 0u32 {
147 "0".to_string()
148 } else {
149 let mut digits = self.unsigned_abs_ref().to_digits_desc(&base);
150 let map = if base > 36 {
151 // above base 36 there is only one alphabet, with both cases as distinct digits
152 digit_to_display_byte_large
153 } else {
154 digit_to_display_byte_lower
155 };
156 for digit in &mut digits {
157 *digit = map(*digit).unwrap();
158 }
159 if *self < 0u32 {
160 vec_pad_left(&mut digits, 1, b'-');
161 }
162 String::from_utf8(digits).unwrap()
163 }
164 }
165
166 /// Converts an [`Integer`] to a [`String`] using a specified base.
167 ///
168 /// For bases up to 36, digits from 0 to 9 become [`char`]s from `'0'` to `'9'` and digits from
169 /// 10 to 35 become the uppercase [`char`]s `'A'` to `'Z'`. For bases from 37 through 62 the
170 /// uppercase and lowercase letters are distinct digits and there is only one alphabet, so the
171 /// result is the same as
172 /// [`to_string_base`](malachite_base::num::conversion::traits::ToStringBase::to_string_base)'s.
173 ///
174 /// # Worst-case complexity
175 /// $T(n) = O(n (\log n)^2 \log\log n)$
176 ///
177 /// $M(n) = O(n \log n)$
178 ///
179 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
180 ///
181 /// # Panics
182 /// Panics if `base` is less than 2 or greater than 62.
183 ///
184 /// # Examples
185 /// ```
186 /// use malachite_base::num::conversion::traits::ToStringBase;
187 /// use malachite_nz::integer::Integer;
188 ///
189 /// assert_eq!(Integer::from(1000).to_string_base_upper(2), "1111101000");
190 /// assert_eq!(Integer::from(1000).to_string_base_upper(10), "1000");
191 /// assert_eq!(Integer::from(1000).to_string_base_upper(36), "RS");
192 ///
193 /// assert_eq!(Integer::from(-1000).to_string_base_upper(2), "-1111101000");
194 /// assert_eq!(Integer::from(-1000).to_string_base_upper(10), "-1000");
195 /// assert_eq!(Integer::from(-1000).to_string_base_upper(36), "-RS");
196 /// assert_eq!(Integer::from(-1000).to_string_base_upper(62), "-G8");
197 /// ```
198 fn to_string_base_upper(&self, base: u8) -> String {
199 assert!((2..=62).contains(&base), "base out of range");
200 if *self == 0u32 {
201 "0".to_string()
202 } else {
203 let mut digits = self.unsigned_abs_ref().to_digits_desc(&base);
204 let map = if base > 36 {
205 // above base 36 there is only one alphabet, with both cases as distinct digits
206 digit_to_display_byte_large
207 } else {
208 digit_to_display_byte_upper
209 };
210 for digit in &mut digits {
211 *digit = map(*digit).unwrap();
212 }
213 if *self < 0u32 {
214 vec_pad_left(&mut digits, 1, b'-');
215 }
216 String::from_utf8(digits).unwrap()
217 }
218 }
219}
220
221impl Display for Integer {
222 /// Converts an [`Integer`] to a [`String`].
223 ///
224 /// # Worst-case complexity
225 /// $T(n) = O(n (\log n)^2 \log\log n)$
226 ///
227 /// $M(n) = O(n \log n)$
228 ///
229 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
230 ///
231 /// # Examples
232 /// ```
233 /// use core::str::FromStr;
234 /// use malachite_base::num::basic::traits::Zero;
235 /// use malachite_nz::integer::Integer;
236 ///
237 /// assert_eq!(Integer::ZERO.to_string(), "0");
238 ///
239 /// assert_eq!(Integer::from(123).to_string(), "123");
240 /// assert_eq!(
241 /// Integer::from_str("1000000000000").unwrap().to_string(),
242 /// "1000000000000"
243 /// );
244 /// assert_eq!(format!("{:05}", Integer::from(123)), "00123");
245 ///
246 /// assert_eq!(Integer::from(-123).to_string(), "-123");
247 /// assert_eq!(
248 /// Integer::from_str("-1000000000000").unwrap().to_string(),
249 /// "-1000000000000"
250 /// );
251 /// assert_eq!(format!("{:05}", Integer::from(-123)), "-0123");
252 /// ```
253 fn fmt(&self, f: &mut Formatter) -> Result {
254 if *self < 0u32 {
255 if f.width().is_some() || f.sign_plus() {
256 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
257 // sign-aware zero flag, and fill and alignment.
258 return f.pad_integral(false, "", &self.unsigned_abs_ref().to_string());
259 }
260 f.write_char('-')?;
261 }
262 Display::fmt(self.unsigned_abs_ref(), f)
263 }
264}
265
266impl Debug for Integer {
267 /// Converts an [`Integer`] to a [`String`].
268 ///
269 /// This is the same as the [`Display::fmt`] implementation.
270 ///
271 /// # Worst-case complexity
272 /// $T(n) = O(n (\log n)^2 \log\log n)$
273 ///
274 /// $M(n) = O(n \log n)$
275 ///
276 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
277 ///
278 /// # Examples
279 /// ```
280 /// use core::str::FromStr;
281 /// use malachite_base::num::basic::traits::Zero;
282 /// use malachite_base::strings::ToDebugString;
283 /// use malachite_nz::integer::Integer;
284 ///
285 /// assert_eq!(Integer::ZERO.to_debug_string(), "0");
286 ///
287 /// assert_eq!(Integer::from(123).to_debug_string(), "123");
288 /// assert_eq!(
289 /// Integer::from_str("1000000000000")
290 /// .unwrap()
291 /// .to_debug_string(),
292 /// "1000000000000"
293 /// );
294 /// assert_eq!(format!("{:05?}", Integer::from(123)), "00123");
295 ///
296 /// assert_eq!(Integer::from(-123).to_debug_string(), "-123");
297 /// assert_eq!(
298 /// Integer::from_str("-1000000000000")
299 /// .unwrap()
300 /// .to_debug_string(),
301 /// "-1000000000000"
302 /// );
303 /// assert_eq!(format!("{:05?}", Integer::from(-123)), "-0123");
304 /// ```
305 #[inline]
306 fn fmt(&self, f: &mut Formatter) -> Result {
307 Display::fmt(self, f)
308 }
309}
310
311impl Binary for Integer {
312 /// Converts an [`Integer`] to a binary [`String`].
313 ///
314 /// Using the `#` format flag prepends `"0b"` to the string.
315 ///
316 /// # Worst-case complexity
317 /// $T(n) = O(n)$
318 ///
319 /// $M(n) = O(n)$
320 ///
321 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
322 ///
323 /// # Examples
324 /// ```
325 /// use core::str::FromStr;
326 /// use malachite_base::num::basic::traits::Zero;
327 /// use malachite_base::strings::ToBinaryString;
328 /// use malachite_nz::integer::Integer;
329 ///
330 /// assert_eq!(Integer::ZERO.to_binary_string(), "0");
331 /// assert_eq!(Integer::from(123).to_binary_string(), "1111011");
332 /// assert_eq!(
333 /// Integer::from_str("1000000000000")
334 /// .unwrap()
335 /// .to_binary_string(),
336 /// "1110100011010100101001010001000000000000"
337 /// );
338 /// assert_eq!(format!("{:011b}", Integer::from(123)), "00001111011");
339 /// assert_eq!(Integer::from(-123).to_binary_string(), "-1111011");
340 /// assert_eq!(
341 /// Integer::from_str("-1000000000000")
342 /// .unwrap()
343 /// .to_binary_string(),
344 /// "-1110100011010100101001010001000000000000"
345 /// );
346 /// assert_eq!(format!("{:011b}", Integer::from(-123)), "-0001111011");
347 ///
348 /// assert_eq!(format!("{:#b}", Integer::ZERO), "0b0");
349 /// assert_eq!(format!("{:#b}", Integer::from(123)), "0b1111011");
350 /// assert_eq!(
351 /// format!("{:#b}", Integer::from_str("1000000000000").unwrap()),
352 /// "0b1110100011010100101001010001000000000000"
353 /// );
354 /// assert_eq!(format!("{:#011b}", Integer::from(123)), "0b001111011");
355 /// assert_eq!(format!("{:#b}", Integer::from(-123)), "-0b1111011");
356 /// assert_eq!(
357 /// format!("{:#b}", Integer::from_str("-1000000000000").unwrap()),
358 /// "-0b1110100011010100101001010001000000000000"
359 /// );
360 /// assert_eq!(format!("{:#011b}", Integer::from(-123)), "-0b01111011");
361 /// ```
362 fn fmt(&self, f: &mut Formatter) -> Result {
363 if *self < 0u32 {
364 if f.width().is_some() || f.sign_plus() {
365 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
366 // sign-aware zero flag, the `#` prefix, and fill and alignment.
367 return f.pad_integral(false, "0b", &self.unsigned_abs_ref().to_binary_string());
368 }
369 f.write_char('-')?;
370 }
371 Binary::fmt(self.unsigned_abs_ref(), f)
372 }
373}
374
375impl Octal for Integer {
376 /// Converts an [`Integer`] to an octal [`String`].
377 ///
378 /// Using the `#` format flag prepends `"0o"` to the string.
379 ///
380 /// # Worst-case complexity
381 /// $T(n) = O(n)$
382 ///
383 /// $M(n) = O(n)$
384 ///
385 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
386 ///
387 /// # Examples
388 /// ```
389 /// use core::str::FromStr;
390 /// use malachite_base::num::basic::traits::Zero;
391 /// use malachite_base::strings::ToOctalString;
392 /// use malachite_nz::integer::Integer;
393 ///
394 /// assert_eq!(Integer::ZERO.to_octal_string(), "0");
395 /// assert_eq!(Integer::from(123).to_octal_string(), "173");
396 /// assert_eq!(
397 /// Integer::from_str("1000000000000")
398 /// .unwrap()
399 /// .to_octal_string(),
400 /// "16432451210000"
401 /// );
402 /// assert_eq!(format!("{:07o}", Integer::from(123)), "0000173");
403 /// assert_eq!(Integer::from(-123).to_octal_string(), "-173");
404 /// assert_eq!(
405 /// Integer::from_str("-1000000000000")
406 /// .unwrap()
407 /// .to_octal_string(),
408 /// "-16432451210000"
409 /// );
410 /// assert_eq!(format!("{:07o}", Integer::from(-123)), "-000173");
411 ///
412 /// assert_eq!(format!("{:#o}", Integer::ZERO), "0o0");
413 /// assert_eq!(format!("{:#o}", Integer::from(123)), "0o173");
414 /// assert_eq!(
415 /// format!("{:#o}", Integer::from_str("1000000000000").unwrap()),
416 /// "0o16432451210000"
417 /// );
418 /// assert_eq!(format!("{:#07o}", Integer::from(123)), "0o00173");
419 /// assert_eq!(format!("{:#o}", Integer::from(-123)), "-0o173");
420 /// assert_eq!(
421 /// format!("{:#o}", Integer::from_str("-1000000000000").unwrap()),
422 /// "-0o16432451210000"
423 /// );
424 /// assert_eq!(format!("{:#07o}", Integer::from(-123)), "-0o0173");
425 /// ```
426 fn fmt(&self, f: &mut Formatter) -> Result {
427 if *self < 0u32 {
428 if f.width().is_some() || f.sign_plus() {
429 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
430 // sign-aware zero flag, the `#` prefix, and fill and alignment.
431 return f.pad_integral(false, "0o", &self.unsigned_abs_ref().to_octal_string());
432 }
433 f.write_char('-')?;
434 }
435 Octal::fmt(self.unsigned_abs_ref(), f)
436 }
437}
438
439impl LowerHex for Integer {
440 /// Converts an [`Integer`] to a hexadecimal [`String`] using lowercase characters.
441 ///
442 /// Using the `#` format flag prepends `"0x"` to the string.
443 ///
444 /// # Worst-case complexity
445 /// $T(n) = O(n)$
446 ///
447 /// $M(n) = O(n)$
448 ///
449 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
450 ///
451 /// # Examples
452 /// ```
453 /// use core::str::FromStr;
454 /// use malachite_base::num::basic::traits::Zero;
455 /// use malachite_base::strings::ToLowerHexString;
456 /// use malachite_nz::integer::Integer;
457 ///
458 /// assert_eq!(Integer::ZERO.to_lower_hex_string(), "0");
459 /// assert_eq!(Integer::from(123).to_lower_hex_string(), "7b");
460 /// assert_eq!(
461 /// Integer::from_str("1000000000000")
462 /// .unwrap()
463 /// .to_lower_hex_string(),
464 /// "e8d4a51000"
465 /// );
466 /// assert_eq!(format!("{:07x}", Integer::from(123)), "000007b");
467 /// assert_eq!(Integer::from(-123).to_lower_hex_string(), "-7b");
468 /// assert_eq!(
469 /// Integer::from_str("-1000000000000")
470 /// .unwrap()
471 /// .to_lower_hex_string(),
472 /// "-e8d4a51000"
473 /// );
474 /// assert_eq!(format!("{:07x}", Integer::from(-123)), "-00007b");
475 ///
476 /// assert_eq!(format!("{:#x}", Integer::ZERO), "0x0");
477 /// assert_eq!(format!("{:#x}", Integer::from(123)), "0x7b");
478 /// assert_eq!(
479 /// format!("{:#x}", Integer::from_str("1000000000000").unwrap()),
480 /// "0xe8d4a51000"
481 /// );
482 /// assert_eq!(format!("{:#07x}", Integer::from(123)), "0x0007b");
483 /// assert_eq!(format!("{:#x}", Integer::from(-123)), "-0x7b");
484 /// assert_eq!(
485 /// format!("{:#x}", Integer::from_str("-1000000000000").unwrap()),
486 /// "-0xe8d4a51000"
487 /// );
488 /// assert_eq!(format!("{:#07x}", Integer::from(-123)), "-0x007b");
489 /// ```
490 fn fmt(&self, f: &mut Formatter) -> Result {
491 if *self < 0u32 {
492 if f.width().is_some() || f.sign_plus() {
493 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
494 // sign-aware zero flag, the `#` prefix, and fill and alignment.
495 return f.pad_integral(false, "0x", &self.unsigned_abs_ref().to_lower_hex_string());
496 }
497 f.write_char('-')?;
498 }
499 LowerHex::fmt(self.unsigned_abs_ref(), f)
500 }
501}
502
503impl UpperHex for Integer {
504 /// Converts an [`Integer`] to a hexadecimal [`String`] using uppercase characters.
505 ///
506 /// Using the `#` format flag prepends `"0x"` to the string.
507 ///
508 /// # Worst-case complexity
509 /// $T(n) = O(n)$
510 ///
511 /// $M(n) = O(n)$
512 ///
513 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
514 ///
515 /// # Examples
516 /// ```
517 /// use core::str::FromStr;
518 /// use malachite_base::num::basic::traits::Zero;
519 /// use malachite_base::strings::ToUpperHexString;
520 /// use malachite_nz::integer::Integer;
521 ///
522 /// assert_eq!(Integer::ZERO.to_upper_hex_string(), "0");
523 /// assert_eq!(Integer::from(123).to_upper_hex_string(), "7B");
524 /// assert_eq!(
525 /// Integer::from_str("1000000000000")
526 /// .unwrap()
527 /// .to_upper_hex_string(),
528 /// "E8D4A51000"
529 /// );
530 /// assert_eq!(format!("{:07X}", Integer::from(123)), "000007B");
531 /// assert_eq!(Integer::from(-123).to_upper_hex_string(), "-7B");
532 /// assert_eq!(
533 /// Integer::from_str("-1000000000000")
534 /// .unwrap()
535 /// .to_upper_hex_string(),
536 /// "-E8D4A51000"
537 /// );
538 /// assert_eq!(format!("{:07X}", Integer::from(-123)), "-00007B");
539 ///
540 /// assert_eq!(format!("{:#X}", Integer::ZERO), "0x0");
541 /// assert_eq!(format!("{:#X}", Integer::from(123)), "0x7B");
542 /// assert_eq!(
543 /// format!("{:#X}", Integer::from_str("1000000000000").unwrap()),
544 /// "0xE8D4A51000"
545 /// );
546 /// assert_eq!(format!("{:#07X}", Integer::from(123)), "0x0007B");
547 /// assert_eq!(format!("{:#X}", Integer::from(-123)), "-0x7B");
548 /// assert_eq!(
549 /// format!("{:#X}", Integer::from_str("-1000000000000").unwrap()),
550 /// "-0xE8D4A51000"
551 /// );
552 /// assert_eq!(format!("{:#07X}", Integer::from(-123)), "-0x007B");
553 /// ```
554 fn fmt(&self, f: &mut Formatter) -> Result {
555 if *self < 0u32 {
556 if f.width().is_some() || f.sign_plus() {
557 // Let `pad_integral` handle the interaction of the sign with the `+` flag, the
558 // sign-aware zero flag, the `#` prefix, and fill and alignment.
559 return f.pad_integral(false, "0x", &self.unsigned_abs_ref().to_upper_hex_string());
560 }
561 f.write_char('-')?;
562 }
563 UpperHex::fmt(self.unsigned_abs_ref(), f)
564 }
565}