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