dashu_int/ibig.rs
1//! Signed big integer.
2
3use crate::{
4 repr::{Repr, TypedRepr, TypedReprRef},
5 Sign, UBig,
6};
7
8/// A signed arbitrary precision integer.
9///
10/// `IBig` represents an arbitrarily large signed integer. It shares [`UBig`]'s representation — the
11/// sign bit is folded in without extra allocation — so it has the same small-integer inlining (values
12/// that fit in a [`DoubleWord`](crate::DoubleWord) stay on the stack) and the same niche bit, making
13/// [`Option<IBig>`] the same size as [`IBig`].
14///
15/// For the full discussion — construction, parsing, printing, and the memory layout — see the
16/// [user guide](https://zyxin.xyz/dashu/types.html).
17///
18/// # Examples
19///
20/// Parsing and printing (base 2–36 is supported for string/literal parsing):
21///
22/// ```
23/// // parsing
24/// # use dashu_base::ParseError;
25/// # use dashu_int::{IBig, Word};
26/// let a = IBig::from(408580953453092208335085386466371u128);
27/// let b = IBig::from(-0x1231abcd4134i64);
28/// let c = IBig::from_str_radix("a2a123bbb127779cccc123", 32)?;
29/// let d = IBig::from_str_radix("-1231abcd4134", 16)?;
30/// assert_eq!(a, c);
31/// assert_eq!(b, d);
32///
33/// // printing
34/// assert_eq!(format!("{}", IBig::from(12)), "12");
35/// assert_eq!(format!("{:#X}", IBig::from(-0xabcd)), "-0xABCD");
36/// if Word::BITS == 64 {
37/// // number of digits to display depends on the word size
38/// assert_eq!(
39/// format!("{:?}", IBig::NEG_ONE << 1000),
40/// "-1071508607186267320..4386837205668069376"
41/// );
42/// }
43/// # Ok::<(), ParseError>(())
44/// ```
45///
46/// The niche bit makes `Option<IBig>` free, and `IBig` matches `UBig` in size:
47///
48/// ```
49/// # use dashu_int::{IBig, UBig};
50/// use core::mem::size_of;
51/// assert_eq!(size_of::<IBig>(), size_of::<UBig>());
52/// assert_eq!(size_of::<IBig>(), size_of::<Option<IBig>>());
53/// ```
54#[derive(Eq, Hash, PartialEq)]
55#[repr(transparent)]
56pub struct IBig(pub(crate) Repr);
57
58impl IBig {
59 #[rustversion::attr(since(1.64), const)]
60 #[inline]
61 pub(crate) fn as_sign_repr(&self) -> (Sign, TypedReprRef<'_>) {
62 self.0.as_sign_typed()
63 }
64
65 #[inline]
66 pub(crate) fn into_sign_repr(self) -> (Sign, TypedRepr) {
67 self.0.into_sign_typed()
68 }
69
70 /// Get the raw representation in [Word][crate::Word]s.
71 ///
72 /// If the number is zero, then empty slice will be returned.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// # use dashu_int::{IBig, Sign};
78 /// assert_eq!(IBig::ZERO.as_sign_words(), (Sign::Positive, &[] as &[_]));
79 /// assert_eq!(IBig::NEG_ONE.as_sign_words().0, Sign::Negative);
80 /// assert_eq!(IBig::NEG_ONE.as_sign_words().1, &[1]);
81 /// ```
82 #[inline]
83 pub fn as_sign_words(&self) -> (Sign, &[crate::Word]) {
84 self.0.as_sign_slice()
85 }
86
87 /// Get the sign of the number. Zero value has a positive sign.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// # use dashu_int::{IBig, Sign};
93 /// assert_eq!(IBig::ZERO.sign(), Sign::Positive);
94 /// assert_eq!(IBig::from(2).sign(), Sign::Positive);
95 /// assert_eq!(IBig::from(-3).sign(), Sign::Negative);
96 /// ```
97 #[inline]
98 pub const fn sign(&self) -> Sign {
99 self.0.sign()
100 }
101
102 /// Convert the [IBig] into its [Sign] and [UBig] magnitude
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// # use dashu_int::{IBig, Sign, UBig};
108 /// assert_eq!(IBig::ZERO.into_parts(), (Sign::Positive, UBig::ZERO));
109 /// assert_eq!(IBig::ONE.into_parts(), (Sign::Positive, UBig::ONE));
110 /// assert_eq!(IBig::NEG_ONE.into_parts(), (Sign::Negative, UBig::ONE));
111 /// ```
112 #[inline]
113 pub fn into_parts(self) -> (Sign, UBig) {
114 let sign = self.0.sign();
115 let mag = self.0.with_sign(Sign::Positive);
116 (sign, UBig(mag))
117 }
118
119 /// Create an [IBig] from the [Sign] and [UBig] magnitude
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// # use dashu_int::{IBig, Sign, UBig};
125 /// assert_eq!(IBig::from_parts(Sign::Positive, UBig::ZERO), IBig::ZERO);
126 /// assert_eq!(IBig::from_parts(Sign::Positive, UBig::ONE), IBig::ONE);
127 /// assert_eq!(IBig::from_parts(Sign::Negative, UBig::ONE), IBig::NEG_ONE);
128 /// ```
129 #[inline]
130 pub fn from_parts(sign: Sign, magnitude: UBig) -> Self {
131 IBig(magnitude.0.with_sign(sign))
132 }
133
134 /// Create an IBig in a const context.
135 ///
136 /// The magnitude is limited to a [DoubleWord][crate::DoubleWord].
137 ///
138 /// # Examples
139 ///
140 /// ```
141 /// # use dashu_int::{IBig, Sign, UBig};
142 /// const ONE: IBig = IBig::from_parts_const(Sign::Positive, 1);
143 /// assert_eq!(ONE, IBig::ONE);
144 /// const NEG_ONE: IBig = IBig::from_parts_const(Sign::Negative, 1);
145 /// assert_eq!(NEG_ONE, IBig::NEG_ONE);
146 /// ```
147 #[inline]
148 pub const fn from_parts_const(sign: Sign, dword: crate::DoubleWord) -> Self {
149 Self(Repr::from_dword(dword).with_sign(sign))
150 }
151
152 /// Create an IBig from an i64.
153 ///
154 /// This function is const on 32-bit and 64-bit targets.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// # use dashu_int::IBig;
160 /// assert_eq!(IBig::from_i64(-42), IBig::from(-42i64));
161 /// assert_eq!(IBig::from_i64(42), IBig::from(42i64));
162 /// ```
163 #[cfg(not(any(target_pointer_width = "16", force_bits = "16")))]
164 #[inline]
165 pub const fn from_i64(n: i64) -> Self {
166 let sign = if n >= 0 {
167 Sign::Positive
168 } else {
169 Sign::Negative
170 };
171 let mag = n.unsigned_abs() as crate::DoubleWord;
172 Self(Repr::from_dword(mag).with_sign(sign))
173 }
174
175 /// Create an IBig from an i64.
176 ///
177 /// On 16-bit targets `i64` is wider than [`DoubleWord`][crate::DoubleWord], so this delegates
178 /// to `From<i64>` and is not `const`; on 32-bit and 64-bit targets the `const` constructor
179 /// above is used instead.
180 #[cfg(any(target_pointer_width = "16", force_bits = "16"))]
181 #[inline]
182 pub fn from_i64(n: i64) -> Self {
183 Self::from(n)
184 }
185
186 /// Create an IBig from a static sequence of [Word][crate::Word]s and a sign.
187 ///
188 /// See [UBig::from_static_words] for why this method is unsafe. This method
189 /// is intended for the use of static creation macros.
190 #[doc(hidden)]
191 #[inline]
192 pub const unsafe fn from_static_words(sign: Sign, words: &'static [crate::Word]) -> Self {
193 Self(Repr::from_static_words(words).with_sign(sign))
194 }
195
196 /// [IBig] with value 0
197 pub const ZERO: Self = Self(Repr::zero());
198 /// [IBig] with value 1
199 pub const ONE: Self = Self(Repr::one());
200 /// [IBig] with value -1
201 pub const NEG_ONE: Self = Self(Repr::neg_one());
202
203 /// Check whether the number is 0
204 ///
205 /// # Examples
206 ///
207 /// ```
208 /// # use dashu_int::IBig;
209 /// assert!(IBig::ZERO.is_zero());
210 /// assert!(!IBig::ONE.is_zero());
211 /// ```
212 #[inline]
213 pub const fn is_zero(&self) -> bool {
214 self.0.is_zero()
215 }
216
217 /// Check whether the number is 1
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// # use dashu_int::IBig;
223 /// assert!(!IBig::ZERO.is_one());
224 /// assert!(IBig::ONE.is_one());
225 /// ```
226 #[inline]
227 pub const fn is_one(&self) -> bool {
228 self.0.is_one()
229 }
230}
231
232// This custom implementation is necessary due to https://github.com/rust-lang/rust/issues/98374
233impl Clone for IBig {
234 #[inline]
235 fn clone(&self) -> IBig {
236 IBig(self.0.clone())
237 }
238 #[inline]
239 fn clone_from(&mut self, source: &IBig) {
240 self.0.clone_from(&source.0)
241 }
242}