dashu_int/
ibig.rs

1//! Signed big integer.
2
3use crate::{
4    repr::{Repr, TypedRepr, TypedReprRef},
5    Sign, UBig,
6};
7
8/// An signed arbitrary precision integer.
9///
10/// This struct represents an arbitrarily large signed integer. Technically the size of the integer
11/// is bounded by the memory size, but it's enough for practical use on modern devices.
12///
13/// # Parsing and printing
14///
15/// There are four ways to create an [IBig] instance:
16/// 1. Use predifined constants (e.g. [IBig::ZERO], [IBig::NEG_ONE]).
17/// 1. Use the literal macro `ibig!` defined in the [`dashu-macro`](https://docs.rs/dashu-macros/latest/dashu_macros/) crate.
18/// 1. Construct from a [Sign] and a [UBig] instance.
19/// 1. Parse from a string.
20///
21/// Parsing from either literal or string supports representation with base 2~36.
22///
23/// For printing, the [IBig] type supports common formatting traits ([Display][core::fmt::Display],
24/// [Debug][core::fmt::Debug], [LowerHex][core::fmt::LowerHex], etc.). Specially, printing huge number
25/// using [Debug][core::fmt::Debug] will conveniently omit the middle digits of the number, only print
26/// the least and most significant (decimal) digits.
27///
28/// ```
29/// // parsing
30/// # use dashu_base::ParseError;
31/// # use dashu_int::{IBig, Word};
32/// let a = IBig::from(408580953453092208335085386466371u128);
33/// let b = IBig::from(-0x1231abcd4134i64);
34/// let c = IBig::from_str_radix("a2a123bbb127779cccc123", 32)?;
35/// let d = IBig::from_str_radix("-1231abcd4134", 16)?;
36/// assert_eq!(a, c);
37/// assert_eq!(b, d);
38///
39/// // printing
40/// assert_eq!(format!("{}", IBig::from(12)), "12");
41/// assert_eq!(format!("{:#X}", IBig::from(-0xabcd)), "-0xABCD");
42/// if Word::BITS == 64 {
43///     // number of digits to display depends on the word size
44///     assert_eq!(
45///         format!("{:?}", IBig::NEG_ONE << 1000),
46///         "-1071508607186267320..4386837205668069376"
47///     );
48/// }
49/// # Ok::<(), ParseError>(())
50/// ```
51///
52/// # Memory
53///
54/// The internal representation of [IBig] is exactly the same as [UBig]. It just use a
55/// small trick to store the sign bit without additional memory allocation. This means that
56/// [IBig] also has the small integer optimization and the niche bit to use with simple
57/// enums.
58///
59/// ```
60/// # use dashu_int::{IBig, UBig};
61/// use core::mem::size_of;
62/// assert_eq!(size_of::<IBig>(), size_of::<UBig>());
63/// assert_eq!(size_of::<IBig>(), size_of::<Option<IBig>>());
64/// ```
65///
66#[derive(Eq, Hash, PartialEq)]
67#[repr(transparent)]
68pub struct IBig(pub(crate) Repr);
69
70impl IBig {
71    #[rustversion::attr(since(1.64), const)]
72    #[inline]
73    pub(crate) fn as_sign_repr(&self) -> (Sign, TypedReprRef<'_>) {
74        self.0.as_sign_typed()
75    }
76
77    #[inline]
78    pub(crate) fn into_sign_repr(self) -> (Sign, TypedRepr) {
79        self.0.into_sign_typed()
80    }
81
82    /// Get the raw representation in [Word][crate::Word]s.
83    ///
84    /// If the number is zero, then empty slice will be returned.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// # use dashu_int::{IBig, Sign};
90    /// assert_eq!(IBig::ZERO.as_sign_words(), (Sign::Positive, &[] as &[_]));
91    /// assert_eq!(IBig::NEG_ONE.as_sign_words().0, Sign::Negative);
92    /// assert_eq!(IBig::NEG_ONE.as_sign_words().1, &[1]);
93    /// ```
94    #[inline]
95    pub fn as_sign_words(&self) -> (Sign, &[crate::Word]) {
96        self.0.as_sign_slice()
97    }
98
99    /// Get the sign of the number. Zero value has a positive sign.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// # use dashu_int::{IBig, Sign};
105    /// assert_eq!(IBig::ZERO.sign(), Sign::Positive);
106    /// assert_eq!(IBig::from(2).sign(), Sign::Positive);
107    /// assert_eq!(IBig::from(-3).sign(), Sign::Negative);
108    /// ```
109    #[inline]
110    pub const fn sign(&self) -> Sign {
111        self.0.sign()
112    }
113
114    /// Convert the [IBig] into its [Sign] and [UBig] magnitude
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// # use dashu_int::{IBig, Sign, UBig};
120    /// assert_eq!(IBig::ZERO.into_parts(), (Sign::Positive, UBig::ZERO));
121    /// assert_eq!(IBig::ONE.into_parts(), (Sign::Positive, UBig::ONE));
122    /// assert_eq!(IBig::NEG_ONE.into_parts(), (Sign::Negative, UBig::ONE));
123    /// ```
124    #[inline]
125    pub fn into_parts(self) -> (Sign, UBig) {
126        let sign = self.0.sign();
127        let mag = self.0.with_sign(Sign::Positive);
128        (sign, UBig(mag))
129    }
130
131    /// Create an [IBig] from the [Sign] and [UBig] magnitude
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// # use dashu_int::{IBig, Sign, UBig};
137    /// assert_eq!(IBig::from_parts(Sign::Positive, UBig::ZERO), IBig::ZERO);
138    /// assert_eq!(IBig::from_parts(Sign::Positive, UBig::ONE), IBig::ONE);
139    /// assert_eq!(IBig::from_parts(Sign::Negative, UBig::ONE), IBig::NEG_ONE);
140    /// ```
141    #[inline]
142    pub fn from_parts(sign: Sign, magnitude: UBig) -> Self {
143        IBig(magnitude.0.with_sign(sign))
144    }
145
146    /// Create an IBig in a const context.
147    ///
148    /// The magnitude is limited to a [DoubleWord][crate::DoubleWord].
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// # use dashu_int::{IBig, Sign, UBig};
154    /// const ONE: IBig = IBig::from_parts_const(Sign::Positive, 1);
155    /// assert_eq!(ONE, IBig::ONE);
156    /// const NEG_ONE: IBig = IBig::from_parts_const(Sign::Negative, 1);
157    /// assert_eq!(NEG_ONE, IBig::NEG_ONE);
158    /// ```
159    #[inline]
160    pub const fn from_parts_const(sign: Sign, dword: crate::DoubleWord) -> Self {
161        Self(Repr::from_dword(dword).with_sign(sign))
162    }
163
164    /// Create an IBig from a static sequence of [Word][crate::Word]s and a sign.
165    ///
166    /// See [UBig::from_static_words] for why this method is unsafe. This method
167    /// is intended for the use of static creation macros.
168    #[doc(hidden)]
169    #[inline]
170    pub const unsafe fn from_static_words(sign: Sign, words: &'static [crate::Word]) -> Self {
171        Self(Repr::from_static_words(words).with_sign(sign))
172    }
173
174    /// [IBig] with value 0
175    pub const ZERO: Self = Self(Repr::zero());
176    /// [IBig] with value 1
177    pub const ONE: Self = Self(Repr::one());
178    /// [IBig] with value -1
179    pub const NEG_ONE: Self = Self(Repr::neg_one());
180
181    /// Check whether the number is 0
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// # use dashu_int::IBig;
187    /// assert!(IBig::ZERO.is_zero());
188    /// assert!(!IBig::ONE.is_zero());
189    /// ```
190    #[inline]
191    pub const fn is_zero(&self) -> bool {
192        self.0.is_zero()
193    }
194
195    /// Check whether the number is 1
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// # use dashu_int::IBig;
201    /// assert!(!IBig::ZERO.is_one());
202    /// assert!(IBig::ONE.is_one());
203    /// ```
204    #[inline]
205    pub const fn is_one(&self) -> bool {
206        self.0.is_one()
207    }
208}
209
210// This custom implementation is necessary due to https://github.com/rust-lang/rust/issues/98374
211impl Clone for IBig {
212    #[inline]
213    fn clone(&self) -> IBig {
214        IBig(self.0.clone())
215    }
216    #[inline]
217    fn clone_from(&mut self, source: &IBig) {
218        self.0.clone_from(&source.0)
219    }
220}