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}