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}