/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexical-parse-float-1.0.6/src/bigint.rs
Line | Count | Source |
1 | | //! A simple big-integer type for slow path algorithms. |
2 | | //! |
3 | | //! This includes minimal stack vector for use in big-integer arithmetic. |
4 | | |
5 | | #![doc(hidden)] |
6 | | |
7 | | use core::{cmp, mem, ops, ptr, slice}; |
8 | | |
9 | | #[cfg(feature = "radix")] |
10 | | use crate::float::ExtendedFloat80; |
11 | | use crate::float::RawFloat; |
12 | | use crate::limits::{u32_power_limit, u64_power_limit}; |
13 | | #[cfg(not(feature = "compact"))] |
14 | | use crate::table::get_large_int_power; |
15 | | |
16 | | /// Index an array without bounds checking. |
17 | | /// |
18 | | /// # Safety |
19 | | /// |
20 | | /// Safe if `index < array.len()`. |
21 | | macro_rules! index_unchecked { |
22 | | ($x:ident[$i:expr]) => { |
23 | | // SAFETY: safe if `index < array.len()`. |
24 | | *$x.get_unchecked($i) |
25 | | }; |
26 | | } |
27 | | |
28 | | // BIGINT |
29 | | // ------ |
30 | | |
31 | | /// Number of bits in a Bigint. |
32 | | /// |
33 | | /// This needs to be at least the number of bits required to store |
34 | | /// a Bigint, which is `log2(radix**digits)`. |
35 | | /// ≅ 5600 for base-36, rounded-up. |
36 | | #[cfg(feature = "radix")] |
37 | | const BIGINT_BITS: usize = 6000; |
38 | | |
39 | | /// ≅ 3600 for base-10, rounded-up. |
40 | | #[cfg(not(feature = "radix"))] |
41 | | const BIGINT_BITS: usize = 4000; |
42 | | |
43 | | /// The number of limbs for the bigint. |
44 | | const BIGINT_LIMBS: usize = BIGINT_BITS / Limb::BITS as usize; |
45 | | |
46 | | /// Storage for a big integer type. |
47 | | /// |
48 | | /// This is used for algorithms when we have a finite number of digits. |
49 | | /// Specifically, it stores all the significant digits scaled to the |
50 | | /// proper exponent, as an integral type, and then directly compares |
51 | | /// these digits. |
52 | | /// |
53 | | /// This requires us to store the number of significant bits, plus the |
54 | | /// number of exponent bits (required) since we scale everything |
55 | | /// to the same exponent. |
56 | | #[derive(Clone, PartialEq, Eq)] |
57 | | pub struct Bigint { |
58 | | /// Significant digits for the float, stored in a big integer in LE order. |
59 | | /// |
60 | | /// This is pretty much the same number of digits for any radix, since the |
61 | | /// significant digits balances out the zeros from the exponent: |
62 | | /// 1. Decimal is 1091 digits, 767 mantissa digits + 324 exponent zeros. |
63 | | /// 2. Base 6 is 1097 digits, or 680 mantissa digits + 417 exponent |
64 | | /// zeros. |
65 | | /// 3. Base 36 is 1086 digits, or 877 mantissa digits + 209 exponent |
66 | | /// zeros. |
67 | | /// |
68 | | /// However, the number of bytes required is larger for large radixes: |
69 | | /// for decimal, we need `log2(10**1091) ≅ 3600`, while for base 36 |
70 | | /// we need `log2(36**1086) ≅ 5600`. Since we use uninitialized data, |
71 | | /// we avoid a major performance hit from the large buffer size. |
72 | | pub data: StackVec<BIGINT_LIMBS>, |
73 | | } |
74 | | |
75 | | impl Bigint { |
76 | | /// Construct a bigfloat representing 0. |
77 | | #[inline(always)] |
78 | 1.37k | pub const fn new() -> Self { |
79 | 1.37k | Self { |
80 | 1.37k | data: StackVec::new(), |
81 | 1.37k | } |
82 | 1.37k | } |
83 | | |
84 | | /// Construct a bigfloat from an integer. |
85 | | #[inline(always)] |
86 | 0 | pub fn from_u32(value: u32) -> Self { |
87 | 0 | Self { |
88 | 0 | data: StackVec::from_u32(value), |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | /// Construct a bigfloat from an integer. |
93 | | #[inline(always)] |
94 | 868 | pub fn from_u64(value: u64) -> Self { |
95 | 868 | Self { |
96 | 868 | data: StackVec::from_u64(value), |
97 | 868 | } |
98 | 868 | } |
99 | | |
100 | | #[inline(always)] |
101 | 507 | pub fn hi64(&self) -> (u64, bool) { |
102 | 507 | self.data.hi64() |
103 | 507 | } |
104 | | |
105 | | /// Multiply and assign as if by exponentiation by a power. |
106 | | #[inline(always)] |
107 | 2.22k | pub fn pow(&mut self, base: u32, exp: u32) -> Option<()> { |
108 | 2.22k | let (odd, shift) = split_radix(base); |
109 | 2.22k | if odd != 0 { |
110 | 1.37k | pow::<BIGINT_LIMBS>(&mut self.data, odd, exp)?; |
111 | 853 | } |
112 | 2.22k | if shift != 0 { |
113 | 1.36k | shl(&mut self.data, (exp * shift) as usize)?; |
114 | 868 | } |
115 | 2.22k | Some(()) |
116 | 2.22k | } |
117 | | |
118 | | /// Calculate the bit-length of the big-integer. |
119 | | #[inline(always)] |
120 | 507 | pub fn bit_length(&self) -> u32 { |
121 | 507 | bit_length(&self.data) |
122 | 507 | } |
123 | | } |
124 | | |
125 | | impl ops::MulAssign<&Bigint> for Bigint { |
126 | 0 | fn mul_assign(&mut self, rhs: &Bigint) { |
127 | 0 | self.data *= &rhs.data; |
128 | 0 | } |
129 | | } |
130 | | |
131 | | impl Default for Bigint { |
132 | 0 | fn default() -> Self { |
133 | 0 | Self::new() |
134 | 0 | } |
135 | | } |
136 | | |
137 | | /// Number of bits in a Bigfloat. |
138 | | /// |
139 | | /// This needs to be at least the number of bits required to store |
140 | | /// a Bigint, which is `F::EXPONENT_BIAS + F::BITS`. |
141 | | /// Bias ≅ 1075, with 64 extra for the digits. |
142 | | #[cfg(feature = "radix")] |
143 | | const BIGFLOAT_BITS: usize = 1200; |
144 | | |
145 | | /// The number of limbs for the Bigfloat. |
146 | | #[cfg(feature = "radix")] |
147 | | const BIGFLOAT_LIMBS: usize = BIGFLOAT_BITS / Limb::BITS as usize; |
148 | | |
149 | | /// Storage for a big floating-point type. |
150 | | /// |
151 | | /// This is used for the algorithm with a non-finite digit count, which creates |
152 | | /// a representation of `b+h` and the float scaled into the range `[1, radix)`. |
153 | | #[cfg(feature = "radix")] |
154 | | #[derive(Clone, PartialEq, Eq)] |
155 | | pub struct Bigfloat { |
156 | | /// Significant digits for the float, stored in a big integer in LE order. |
157 | | /// |
158 | | /// This only needs ~1075 bits for the exponent, and ~64 more for the |
159 | | /// significant digits, since it's based on a theoretical representation |
160 | | /// of the halfway point. This means we can have a significantly smaller |
161 | | /// representation. The largest 64-bit exponent in magnitude is 2^1074, |
162 | | /// which will produce the same number of bits in any radix. |
163 | | pub data: StackVec<BIGFLOAT_LIMBS>, |
164 | | /// Binary exponent for the float type. |
165 | | pub exp: i32, |
166 | | } |
167 | | |
168 | | #[cfg(feature = "radix")] |
169 | | impl Bigfloat { |
170 | | /// Construct a bigfloat representing 0. |
171 | | #[inline(always)] |
172 | | pub const fn new() -> Self { |
173 | | Self { |
174 | | data: StackVec::new(), |
175 | | exp: 0, |
176 | | } |
177 | | } |
178 | | |
179 | | /// Construct a bigfloat from an extended-precision float. |
180 | | #[inline(always)] |
181 | | pub fn from_float(fp: ExtendedFloat80) -> Self { |
182 | | Self { |
183 | | data: StackVec::from_u64(fp.mant), |
184 | | exp: fp.exp, |
185 | | } |
186 | | } |
187 | | |
188 | | /// Construct a bigfloat from an integer. |
189 | | #[inline(always)] |
190 | | pub fn from_u32(value: u32) -> Self { |
191 | | Self { |
192 | | data: StackVec::from_u32(value), |
193 | | exp: 0, |
194 | | } |
195 | | } |
196 | | |
197 | | /// Construct a bigfloat from an integer. |
198 | | #[inline(always)] |
199 | | pub fn from_u64(value: u64) -> Self { |
200 | | Self { |
201 | | data: StackVec::from_u64(value), |
202 | | exp: 0, |
203 | | } |
204 | | } |
205 | | |
206 | | /// Multiply and assign as if by exponentiation by a power. |
207 | | #[inline(always)] |
208 | | pub fn pow(&mut self, base: u32, exp: u32) -> Option<()> { |
209 | | let (odd, shift) = split_radix(base); |
210 | | if odd != 0 { |
211 | | pow::<BIGFLOAT_LIMBS>(&mut self.data, odd, exp)?; |
212 | | } |
213 | | if shift != 0 { |
214 | | self.exp += (exp * shift) as i32; |
215 | | } |
216 | | Some(()) |
217 | | } |
218 | | |
219 | | /// Shift-left the entire buffer n bits, where bits is less than the limb |
220 | | /// size. |
221 | | #[inline(always)] |
222 | | pub fn shl_bits(&mut self, n: usize) -> Option<()> { |
223 | | shl_bits(&mut self.data, n) |
224 | | } |
225 | | |
226 | | /// Shift-left the entire buffer n limbs. |
227 | | #[inline(always)] |
228 | | pub fn shl_limbs(&mut self, n: usize) -> Option<()> { |
229 | | shl_limbs(&mut self.data, n) |
230 | | } |
231 | | |
232 | | /// Shift-left the entire buffer n bits. |
233 | | #[inline(always)] |
234 | | pub fn shl(&mut self, n: usize) -> Option<()> { |
235 | | shl(&mut self.data, n) |
236 | | } |
237 | | |
238 | | /// Get number of leading zero bits in the storage. |
239 | | /// Assumes the value is normalized. |
240 | | #[inline(always)] |
241 | | pub fn leading_zeros(&self) -> u32 { |
242 | | leading_zeros(&self.data) |
243 | | } |
244 | | } |
245 | | |
246 | | #[cfg(feature = "radix")] |
247 | | impl ops::MulAssign<&Bigfloat> for Bigfloat { |
248 | | #[inline(always)] |
249 | | #[allow(clippy::suspicious_op_assign_impl)] // reason="intended increment" |
250 | | #[allow(clippy::unwrap_used)] // reason="exceeding the bounds is a developer error" |
251 | | fn mul_assign(&mut self, rhs: &Bigfloat) { |
252 | | large_mul(&mut self.data, &rhs.data).unwrap(); |
253 | | self.exp += rhs.exp; |
254 | | } |
255 | | } |
256 | | |
257 | | #[cfg(feature = "radix")] |
258 | | impl Default for Bigfloat { |
259 | | fn default() -> Self { |
260 | | Self::new() |
261 | | } |
262 | | } |
263 | | |
264 | | // VEC |
265 | | // --- |
266 | | |
267 | | /// Simple stack vector implementation. |
268 | | #[derive(Clone)] |
269 | | pub struct StackVec<const SIZE: usize> { |
270 | | /// The raw buffer for the elements. |
271 | | data: [mem::MaybeUninit<Limb>; SIZE], |
272 | | /// The number of elements in the array (we never need more than |
273 | | /// `u16::MAX`). |
274 | | length: u16, |
275 | | } |
276 | | |
277 | | /// Extract the hi bits from the buffer. |
278 | | /// |
279 | | /// NOTE: Modifying this to remove unsafety which we statically |
280 | | /// check directly in every caller leads to ~20% degradation in |
281 | | /// performance. |
282 | | /// - `rview` - A reversed view over a slice. |
283 | | /// - `fn` - The callback to extract the high bits. |
284 | | macro_rules! hi { |
285 | | (@1 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{ |
286 | | $fn(unsafe { index_unchecked!($rview[0]) as $t }) |
287 | | }}; |
288 | | |
289 | | // # Safety |
290 | | // |
291 | | // Safe as long as the `stackvec.len() >= 2`. |
292 | | (@2 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{ |
293 | | let r0 = unsafe { index_unchecked!($rview[0]) as $t }; |
294 | | let r1 = unsafe { index_unchecked!($rview[1]) as $t }; |
295 | | $fn(r0, r1) |
296 | | }}; |
297 | | |
298 | | // # Safety |
299 | | // |
300 | | // Safe as long as the `stackvec.len() >= 2`. |
301 | | (@nonzero2 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{ |
302 | | let (v, n) = hi!(@2 $self, $rview, $t, $fn); |
303 | | (v, n || unsafe { nonzero($self, 2 ) }) |
304 | | }}; |
305 | | |
306 | | // # Safety |
307 | | // |
308 | | // Safe as long as the `stackvec.len() >= 3`. |
309 | | (@3 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{ |
310 | | let r0 = unsafe { index_unchecked!($rview[0]) as $t }; |
311 | | let r1 = unsafe { index_unchecked!($rview[1]) as $t }; |
312 | | let r2 = unsafe { index_unchecked!($rview[2]) as $t }; |
313 | | $fn(r0, r1, r2) |
314 | | }}; |
315 | | |
316 | | // # Safety |
317 | | // |
318 | | // Safe as long as the `stackvec.len() >= 3`. |
319 | | (@nonzero3 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{ |
320 | | let (v, n) = hi!(@3 $self, $rview, $t, $fn); |
321 | | (v, n || unsafe { nonzero($self, 3 ) }) |
322 | | }}; |
323 | | } |
324 | | |
325 | | impl<const SIZE: usize> StackVec<SIZE> { |
326 | | /// Construct an empty vector. |
327 | | #[must_use] |
328 | | #[inline(always)] |
329 | 2.52k | pub const fn new() -> Self { |
330 | 2.52k | Self { |
331 | 2.52k | length: 0, |
332 | 2.52k | data: [mem::MaybeUninit::uninit(); SIZE], |
333 | 2.52k | } |
334 | 2.52k | } <lexical_parse_float::bigint::StackVec<62>>::new Line | Count | Source | 329 | 2.24k | pub const fn new() -> Self { | 330 | 2.24k | Self { | 331 | 2.24k | length: 0, | 332 | 2.24k | data: [mem::MaybeUninit::uninit(); SIZE], | 333 | 2.24k | } | 334 | 2.24k | } |
<lexical_parse_float::bigint::StackVec<62>>::new Line | Count | Source | 329 | 282 | pub const fn new() -> Self { | 330 | 282 | Self { | 331 | 282 | length: 0, | 332 | 282 | data: [mem::MaybeUninit::uninit(); SIZE], | 333 | 282 | } | 334 | 282 | } |
|
335 | | |
336 | | /// Get a mutable ptr to the current start of the big integer. |
337 | | #[must_use] |
338 | | #[inline(always)] |
339 | 6.28k | pub fn as_mut_ptr(&mut self) -> *mut Limb { |
340 | 6.28k | self.data.as_mut_ptr().cast::<Limb>() |
341 | 6.28k | } <lexical_parse_float::bigint::StackVec<62>>::as_mut_ptr Line | Count | Source | 339 | 5.51k | pub fn as_mut_ptr(&mut self) -> *mut Limb { | 340 | 5.51k | self.data.as_mut_ptr().cast::<Limb>() | 341 | 5.51k | } |
<lexical_parse_float::bigint::StackVec<62>>::as_mut_ptr Line | Count | Source | 339 | 772 | pub fn as_mut_ptr(&mut self) -> *mut Limb { | 340 | 772 | self.data.as_mut_ptr().cast::<Limb>() | 341 | 772 | } |
|
342 | | |
343 | | /// Get a ptr to the current start of the big integer. |
344 | | #[must_use] |
345 | | #[inline(always)] |
346 | 0 | pub fn as_ptr(&self) -> *const Limb { |
347 | 0 | self.data.as_ptr().cast::<Limb>() |
348 | 0 | } |
349 | | |
350 | | /// Construct a vector from an existing slice. |
351 | | #[must_use] |
352 | | #[inline(always)] |
353 | 282 | pub fn try_from(x: &[Limb]) -> Option<Self> { |
354 | 282 | let mut vec = Self::new(); |
355 | 282 | vec.try_extend(x)?; |
356 | 282 | Some(vec) |
357 | 282 | } |
358 | | |
359 | | /// Sets the length of a vector. |
360 | | /// |
361 | | /// This will explicitly set the size of the vector, without actually |
362 | | /// modifying its buffers, so it is up to the caller to ensure that the |
363 | | /// vector is actually the specified size. |
364 | | /// |
365 | | /// # Safety |
366 | | /// |
367 | | /// Safe as long as `len` is less than `SIZE`. |
368 | | #[inline(always)] |
369 | 385 | pub unsafe fn set_len(&mut self, len: usize) { |
370 | 385 | debug_assert!(len <= u16::MAX as usize, "indexing must fit in 16 bits"); |
371 | 385 | debug_assert!(len <= SIZE, "cannot exceed our array bounds"); |
372 | 385 | self.length = len as u16; |
373 | 385 | } <lexical_parse_float::bigint::StackVec<62>>::set_len Line | Count | Source | 369 | 103 | pub unsafe fn set_len(&mut self, len: usize) { | 370 | 103 | debug_assert!(len <= u16::MAX as usize, "indexing must fit in 16 bits"); | 371 | 103 | debug_assert!(len <= SIZE, "cannot exceed our array bounds"); | 372 | 103 | self.length = len as u16; | 373 | 103 | } |
<lexical_parse_float::bigint::StackVec<62>>::set_len Line | Count | Source | 369 | 282 | pub unsafe fn set_len(&mut self, len: usize) { | 370 | 282 | debug_assert!(len <= u16::MAX as usize, "indexing must fit in 16 bits"); | 371 | 282 | debug_assert!(len <= SIZE, "cannot exceed our array bounds"); | 372 | 282 | self.length = len as u16; | 373 | 282 | } |
|
374 | | |
375 | | /// Get the number of elements stored in the vector. |
376 | | #[must_use] |
377 | | #[inline(always)] |
378 | 31.4k | pub const fn len(&self) -> usize { |
379 | 31.4k | self.length as usize |
380 | 31.4k | } <lexical_parse_float::bigint::StackVec<62>>::len Line | Count | Source | 378 | 28.0k | pub const fn len(&self) -> usize { | 379 | 28.0k | self.length as usize | 380 | 28.0k | } |
<lexical_parse_float::bigint::StackVec<62>>::len Line | Count | Source | 378 | 3.44k | pub const fn len(&self) -> usize { | 379 | 3.44k | self.length as usize | 380 | 3.44k | } |
|
381 | | |
382 | | /// If the vector is empty. |
383 | | #[must_use] |
384 | | #[inline(always)] |
385 | 103 | pub const fn is_empty(&self) -> bool { |
386 | 103 | self.len() == 0 |
387 | 103 | } <lexical_parse_float::bigint::StackVec<62>>::is_empty Line | Count | Source | 385 | 103 | pub const fn is_empty(&self) -> bool { | 386 | 103 | self.len() == 0 | 387 | 103 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::is_empty |
388 | | |
389 | | /// The number of items the vector can hold. |
390 | | #[must_use] |
391 | | #[inline(always)] |
392 | 6.28k | pub const fn capacity(&self) -> usize { |
393 | 6.28k | SIZE |
394 | 6.28k | } <lexical_parse_float::bigint::StackVec<62>>::capacity Line | Count | Source | 392 | 5.51k | pub const fn capacity(&self) -> usize { | 393 | 5.51k | SIZE | 394 | 5.51k | } |
<lexical_parse_float::bigint::StackVec<62>>::capacity Line | Count | Source | 392 | 772 | pub const fn capacity(&self) -> usize { | 393 | 772 | SIZE | 394 | 772 | } |
|
395 | | |
396 | | /// Append an item to the vector, without bounds checking. |
397 | | /// |
398 | | /// # Safety |
399 | | /// |
400 | | /// Safe if `self.len() < self.capacity()`. |
401 | | #[inline(always)] |
402 | 5.69k | unsafe fn push_unchecked(&mut self, value: Limb) { |
403 | 5.69k | debug_assert!(self.len() < self.capacity(), "cannot exceed our array bounds"); |
404 | | // SAFETY: safe, capacity is less than the current size. |
405 | 5.69k | unsafe { |
406 | 5.69k | let len = self.len(); |
407 | 5.69k | let ptr = self.as_mut_ptr().add(len); |
408 | 5.69k | ptr.write(value); |
409 | 5.69k | self.length += 1; |
410 | 5.69k | } |
411 | 5.69k | } <lexical_parse_float::bigint::StackVec<62>>::push_unchecked Line | Count | Source | 402 | 5.41k | unsafe fn push_unchecked(&mut self, value: Limb) { | 403 | 5.41k | debug_assert!(self.len() < self.capacity(), "cannot exceed our array bounds"); | 404 | | // SAFETY: safe, capacity is less than the current size. | 405 | 5.41k | unsafe { | 406 | 5.41k | let len = self.len(); | 407 | 5.41k | let ptr = self.as_mut_ptr().add(len); | 408 | 5.41k | ptr.write(value); | 409 | 5.41k | self.length += 1; | 410 | 5.41k | } | 411 | 5.41k | } |
<lexical_parse_float::bigint::StackVec<62>>::push_unchecked Line | Count | Source | 402 | 281 | unsafe fn push_unchecked(&mut self, value: Limb) { | 403 | 281 | debug_assert!(self.len() < self.capacity(), "cannot exceed our array bounds"); | 404 | | // SAFETY: safe, capacity is less than the current size. | 405 | 281 | unsafe { | 406 | 281 | let len = self.len(); | 407 | 281 | let ptr = self.as_mut_ptr().add(len); | 408 | 281 | ptr.write(value); | 409 | 281 | self.length += 1; | 410 | 281 | } | 411 | 281 | } |
|
412 | | |
413 | | /// Append an item to the vector. |
414 | | #[inline(always)] |
415 | 5.69k | pub fn try_push(&mut self, value: Limb) -> Option<()> { |
416 | 5.69k | if self.len() < self.capacity() { |
417 | | // SAFETY: safe, capacity is less than the current size. |
418 | 5.69k | unsafe { self.push_unchecked(value) }; |
419 | 5.69k | Some(()) |
420 | | } else { |
421 | 0 | None |
422 | | } |
423 | 5.69k | } <lexical_parse_float::bigint::StackVec<62>>::try_push Line | Count | Source | 415 | 5.41k | pub fn try_push(&mut self, value: Limb) -> Option<()> { | 416 | 5.41k | if self.len() < self.capacity() { | 417 | | // SAFETY: safe, capacity is less than the current size. | 418 | 5.41k | unsafe { self.push_unchecked(value) }; | 419 | 5.41k | Some(()) | 420 | | } else { | 421 | 0 | None | 422 | | } | 423 | 5.41k | } |
<lexical_parse_float::bigint::StackVec<62>>::try_push Line | Count | Source | 415 | 281 | pub fn try_push(&mut self, value: Limb) -> Option<()> { | 416 | 281 | if self.len() < self.capacity() { | 417 | | // SAFETY: safe, capacity is less than the current size. | 418 | 281 | unsafe { self.push_unchecked(value) }; | 419 | 281 | Some(()) | 420 | | } else { | 421 | 0 | None | 422 | | } | 423 | 281 | } |
|
424 | | |
425 | | /// Remove an item from the end of a vector, without bounds checking. |
426 | | /// |
427 | | /// # Safety |
428 | | /// |
429 | | /// Safe if `self.len() > 0`. |
430 | | #[inline(always)] |
431 | 0 | unsafe fn pop_unchecked(&mut self) -> Limb { |
432 | 0 | debug_assert!(!self.is_empty(), "cannot pop a value if none exists"); |
433 | 0 | self.length -= 1; |
434 | | // SAFETY: safe if `self.length > 0`. |
435 | | // We have a trivial drop and copy, so this is safe. |
436 | 0 | unsafe { ptr::read(self.as_mut_ptr().add(self.len())) } |
437 | 0 | } |
438 | | |
439 | | /// Remove an item from the end of the vector and return it, or None if |
440 | | /// empty. |
441 | | #[inline(always)] |
442 | 0 | pub fn pop(&mut self) -> Option<Limb> { |
443 | 0 | if self.is_empty() { |
444 | 0 | None |
445 | | } else { |
446 | | // SAFETY: safe, since `self.len() > 0`. |
447 | 0 | unsafe { Some(self.pop_unchecked()) } |
448 | | } |
449 | 0 | } |
450 | | |
451 | | /// Add items from a slice to the vector, without bounds checking. |
452 | | /// |
453 | | /// # Safety |
454 | | /// |
455 | | /// Safe if `self.len() + slc.len() <= self.capacity()`. |
456 | | #[inline(always)] |
457 | 282 | unsafe fn extend_unchecked(&mut self, slc: &[Limb]) { |
458 | 282 | let index = self.len(); |
459 | 282 | let new_len = index + slc.len(); |
460 | 282 | debug_assert!(self.len() + slc.len() <= self.capacity(), "cannot exceed our array bounds"); |
461 | 282 | let src = slc.as_ptr(); |
462 | | // SAFETY: safe if `self.len() + slc.len() <= self.capacity()`. |
463 | 282 | unsafe { |
464 | 282 | let dst = self.as_mut_ptr().add(index); |
465 | 282 | ptr::copy_nonoverlapping(src, dst, slc.len()); |
466 | 282 | self.set_len(new_len); |
467 | 282 | } |
468 | 282 | } |
469 | | |
470 | | /// Copy elements from a slice and append them to the vector. |
471 | | #[inline(always)] |
472 | 282 | pub fn try_extend(&mut self, slc: &[Limb]) -> Option<()> { |
473 | 282 | if self.len() + slc.len() <= self.capacity() { |
474 | | // SAFETY: safe, since `self.len() + slc.len() <= self.capacity()`. |
475 | 282 | unsafe { self.extend_unchecked(slc) }; |
476 | 282 | Some(()) |
477 | | } else { |
478 | 0 | None |
479 | | } |
480 | 282 | } |
481 | | |
482 | | /// Truncate vector to new length, dropping any items after `len`. |
483 | | /// |
484 | | /// # Safety |
485 | | /// |
486 | | /// Safe as long as `len <= self.capacity()`. |
487 | 0 | unsafe fn truncate_unchecked(&mut self, len: usize) { |
488 | 0 | debug_assert!(len <= self.capacity(), "cannot exceed our array bounds"); |
489 | 0 | self.length = len as u16; |
490 | 0 | } |
491 | | |
492 | | /// Resize the buffer, without bounds checking. |
493 | | /// |
494 | | /// # Safety |
495 | | /// |
496 | | /// Safe as long as `len <= self.capacity()`. |
497 | | #[inline(always)] |
498 | 209 | pub unsafe fn resize_unchecked(&mut self, len: usize, value: Limb) { |
499 | 209 | debug_assert!(len <= self.capacity(), "cannot exceed our array bounds"); |
500 | 209 | let old_len = self.len(); |
501 | 209 | if len > old_len { |
502 | | // We have a trivial drop, so there's no worry here. |
503 | | // Just, don't set the length until all values have been written, |
504 | | // so we don't accidentally read uninitialized memory. |
505 | | |
506 | 209 | let count = len - old_len; |
507 | 209 | for index in 0..count { |
508 | | // SAFETY: safe if `len < self.capacity()`. |
509 | 209 | unsafe { |
510 | 209 | let dst = self.as_mut_ptr().add(old_len + index); |
511 | 209 | ptr::write(dst, value); |
512 | 209 | } |
513 | | } |
514 | 209 | self.length = len as u16; |
515 | 0 | } else { |
516 | 0 | // SAFETY: safe since `len < self.len()`. |
517 | 0 | unsafe { self.truncate_unchecked(len) }; |
518 | 0 | } |
519 | 209 | } |
520 | | |
521 | | /// Try to resize the buffer. |
522 | | /// |
523 | | /// If the new length is smaller than the current length, truncate |
524 | | /// the input. If it's larger, then append elements to the buffer. |
525 | | #[inline(always)] |
526 | 209 | pub fn try_resize(&mut self, len: usize, value: Limb) -> Option<()> { |
527 | 209 | if len > self.capacity() { |
528 | 0 | None |
529 | | } else { |
530 | | // SAFETY: safe, since `len <= self.capacity()`. |
531 | 209 | unsafe { self.resize_unchecked(len, value) }; |
532 | 209 | Some(()) |
533 | | } |
534 | 209 | } |
535 | | |
536 | | // HI |
537 | | |
538 | | /// Get the high 16 bits from the vector. |
539 | | #[inline(always)] |
540 | 0 | pub fn hi16(&self) -> (u16, bool) { |
541 | 0 | let rview = self.rview(); |
542 | | // SAFETY: the buffer must be at least length bytes long which we check on the |
543 | | // match. |
544 | | unsafe { |
545 | 0 | match rview.len() { |
546 | 0 | 0 => (0, false), |
547 | 0 | 1 if Limb::BITS == 32 => hi!(@1 self, rview, u32, u32_to_hi16_1), |
548 | 0 | 1 => hi!(@1 self, rview, u64, u64_to_hi16_1), |
549 | 0 | _ if Limb::BITS == 32 => hi!(@nonzero2 self, rview, u32, u32_to_hi16_2), |
550 | 0 | _ => hi!(@nonzero2 self, rview, u64, u64_to_hi16_2), |
551 | | } |
552 | | } |
553 | 0 | } |
554 | | |
555 | | /// Get the high 32 bits from the vector. |
556 | | #[inline(always)] |
557 | 0 | pub fn hi32(&self) -> (u32, bool) { |
558 | 0 | let rview = self.rview(); |
559 | | // SAFETY: the buffer must be at least length bytes long which we check on the |
560 | | // match. |
561 | | unsafe { |
562 | 0 | match rview.len() { |
563 | 0 | 0 => (0, false), |
564 | 0 | 1 if Limb::BITS == 32 => hi!(@1 self, rview, u32, u32_to_hi32_1), |
565 | 0 | 1 => hi!(@1 self, rview, u64, u64_to_hi32_1), |
566 | 0 | _ if Limb::BITS == 32 => hi!(@nonzero2 self, rview, u32, u32_to_hi32_2), |
567 | 0 | _ => hi!(@nonzero2 self, rview, u64, u64_to_hi32_2), |
568 | | } |
569 | | } |
570 | 0 | } |
571 | | |
572 | | /// Get the high 64 bits from the vector. |
573 | | #[inline(always)] |
574 | 507 | pub fn hi64(&self) -> (u64, bool) { |
575 | 507 | let rview = self.rview(); |
576 | | // SAFETY: the buffer must be at least length bytes long which we check on the |
577 | | // match. |
578 | | unsafe { |
579 | 507 | match rview.len() { |
580 | 0 | 0 => (0, false), |
581 | 0 | 1 if Limb::BITS == 32 => hi!(@1 self, rview, u32, u32_to_hi64_1), |
582 | 99 | 1 => hi!(@1 self, rview, u64, u64_to_hi64_1), |
583 | 0 | 2 if Limb::BITS == 32 => hi!(@2 self, rview, u32, u32_to_hi64_2), |
584 | 299 | 2 => hi!(@2 self, rview, u64, u64_to_hi64_2), |
585 | 0 | _ if Limb::BITS == 32 => hi!(@nonzero3 self, rview, u32, u32_to_hi64_3), |
586 | 109 | _ => hi!(@nonzero2 self, rview, u64, u64_to_hi64_2), |
587 | | } |
588 | | } |
589 | 507 | } <lexical_parse_float::bigint::StackVec<62>>::hi64 Line | Count | Source | 574 | 507 | pub fn hi64(&self) -> (u64, bool) { | 575 | 507 | let rview = self.rview(); | 576 | | // SAFETY: the buffer must be at least length bytes long which we check on the | 577 | | // match. | 578 | | unsafe { | 579 | 507 | match rview.len() { | 580 | 0 | 0 => (0, false), | 581 | 0 | 1 if Limb::BITS == 32 => hi!(@1 self, rview, u32, u32_to_hi64_1), | 582 | 99 | 1 => hi!(@1 self, rview, u64, u64_to_hi64_1), | 583 | 0 | 2 if Limb::BITS == 32 => hi!(@2 self, rview, u32, u32_to_hi64_2), | 584 | 299 | 2 => hi!(@2 self, rview, u64, u64_to_hi64_2), | 585 | 0 | _ if Limb::BITS == 32 => hi!(@nonzero3 self, rview, u32, u32_to_hi64_3), | 586 | 109 | _ => hi!(@nonzero2 self, rview, u64, u64_to_hi64_2), | 587 | | } | 588 | | } | 589 | 507 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::hi64 |
590 | | |
591 | | // FROM |
592 | | |
593 | | /// Create `StackVec` from u16 value. |
594 | | #[must_use] |
595 | | #[inline(always)] |
596 | 0 | pub fn from_u16(x: u16) -> Self { |
597 | 0 | let mut vec = Self::new(); |
598 | 0 | assert!(1 <= vec.capacity(), "cannot exceed our array bounds"); |
599 | 0 | _ = vec.try_push(x as Limb); |
600 | 0 | vec.normalize(); |
601 | 0 | vec |
602 | 0 | } |
603 | | |
604 | | /// Create `StackVec` from u32 value. |
605 | | #[must_use] |
606 | | #[inline(always)] |
607 | 0 | pub fn from_u32(x: u32) -> Self { |
608 | 0 | let mut vec = Self::new(); |
609 | 0 | debug_assert!(1 <= vec.capacity(), "cannot exceed our array bounds"); |
610 | 0 | assert!(1 <= SIZE, "cannot exceed our array bounds"); |
611 | 0 | _ = vec.try_push(x as Limb); |
612 | 0 | vec.normalize(); |
613 | 0 | vec |
614 | 0 | } |
615 | | |
616 | | /// Create `StackVec` from u64 value. |
617 | | #[must_use] |
618 | | #[inline(always)] |
619 | 868 | pub fn from_u64(x: u64) -> Self { |
620 | 868 | let mut vec = Self::new(); |
621 | 868 | debug_assert!(2 <= vec.capacity(), "cannot exceed our array bounds"); |
622 | 868 | assert!(2 <= SIZE, "cannot exceed our array bounds"); |
623 | 868 | if Limb::BITS == 32 { |
624 | 0 | _ = vec.try_push(x as Limb); |
625 | 0 | _ = vec.try_push((x >> 32) as Limb); |
626 | 868 | } else { |
627 | 868 | _ = vec.try_push(x as Limb); |
628 | 868 | } |
629 | 868 | vec.normalize(); |
630 | 868 | vec |
631 | 868 | } <lexical_parse_float::bigint::StackVec<62>>::from_u64 Line | Count | Source | 619 | 868 | pub fn from_u64(x: u64) -> Self { | 620 | 868 | let mut vec = Self::new(); | 621 | 868 | debug_assert!(2 <= vec.capacity(), "cannot exceed our array bounds"); | 622 | 868 | assert!(2 <= SIZE, "cannot exceed our array bounds"); | 623 | 868 | if Limb::BITS == 32 { | 624 | 0 | _ = vec.try_push(x as Limb); | 625 | 0 | _ = vec.try_push((x >> 32) as Limb); | 626 | 868 | } else { | 627 | 868 | _ = vec.try_push(x as Limb); | 628 | 868 | } | 629 | 868 | vec.normalize(); | 630 | 868 | vec | 631 | 868 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::from_u64 |
632 | | |
633 | | // INDEX |
634 | | |
635 | | /// Create a reverse view of the vector for indexing. |
636 | | #[must_use] |
637 | | #[inline(always)] |
638 | 507 | pub fn rview(&self) -> ReverseView<'_, Limb> { |
639 | 507 | ReverseView { |
640 | 507 | inner: self, |
641 | 507 | } |
642 | 507 | } <lexical_parse_float::bigint::StackVec<62>>::rview Line | Count | Source | 638 | 507 | pub fn rview(&self) -> ReverseView<'_, Limb> { | 639 | 507 | ReverseView { | 640 | 507 | inner: self, | 641 | 507 | } | 642 | 507 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::rview |
643 | | |
644 | | // MATH |
645 | | |
646 | | /// Normalize the integer, so any leading zero values are removed. |
647 | | #[inline(always)] |
648 | 940 | pub fn normalize(&mut self) { |
649 | | // We don't care if this wraps: the index is bounds-checked. |
650 | 940 | while let Some(&value) = self.get(self.len().wrapping_sub(1)) { |
651 | 940 | if value == 0 { |
652 | 0 | self.length -= 1; |
653 | 0 | } else { |
654 | 940 | break; |
655 | | } |
656 | | } |
657 | 940 | } <lexical_parse_float::bigint::StackVec<62>>::normalize Line | Count | Source | 648 | 868 | pub fn normalize(&mut self) { | 649 | | // We don't care if this wraps: the index is bounds-checked. | 650 | 868 | while let Some(&value) = self.get(self.len().wrapping_sub(1)) { | 651 | 868 | if value == 0 { | 652 | 0 | self.length -= 1; | 653 | 0 | } else { | 654 | 868 | break; | 655 | | } | 656 | | } | 657 | 868 | } |
<lexical_parse_float::bigint::StackVec<62>>::normalize Line | Count | Source | 648 | 72 | pub fn normalize(&mut self) { | 649 | | // We don't care if this wraps: the index is bounds-checked. | 650 | 72 | while let Some(&value) = self.get(self.len().wrapping_sub(1)) { | 651 | 72 | if value == 0 { | 652 | 0 | self.length -= 1; | 653 | 0 | } else { | 654 | 72 | break; | 655 | | } | 656 | | } | 657 | 72 | } |
|
658 | | |
659 | | /// Get if the big integer is normalized. |
660 | | #[must_use] |
661 | | #[inline(always)] |
662 | 0 | pub fn is_normalized(&self) -> bool { |
663 | | // We don't care if this wraps: the index is bounds-checked. |
664 | 0 | self.get(self.len().wrapping_sub(1)) != Some(&0) |
665 | 0 | } |
666 | | |
667 | | /// Calculate the fast quotient for a single limb-bit quotient. |
668 | | /// |
669 | | /// This requires a non-normalized divisor, where there at least |
670 | | /// `integral_binary_factor` 0 bits set, to ensure at maximum a single |
671 | | /// digit will be produced for a single base. |
672 | | /// |
673 | | /// Warning: This is not a general-purpose division algorithm, |
674 | | /// it is highly specialized for peeling off singular digits. |
675 | | #[inline(always)] |
676 | | #[cfg(feature = "radix")] |
677 | | pub fn quorem(&mut self, y: &Self) -> Limb { |
678 | | large_quorem(self, y) |
679 | | } |
680 | | |
681 | | /// `AddAssign` small integer. |
682 | | #[inline(always)] |
683 | 3.30k | pub fn add_small(&mut self, y: Limb) -> Option<()> { |
684 | 3.30k | small_add(self, y) |
685 | 3.30k | } <lexical_parse_float::bigint::StackVec<62>>::add_small Line | Count | Source | 683 | 3.30k | pub fn add_small(&mut self, y: Limb) -> Option<()> { | 684 | 3.30k | small_add(self, y) | 685 | 3.30k | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::add_small |
686 | | |
687 | | /// `MulAssign` small integer. |
688 | | #[inline(always)] |
689 | 3.30k | pub fn mul_small(&mut self, y: Limb) -> Option<()> { |
690 | 3.30k | small_mul(self, y) |
691 | 3.30k | } <lexical_parse_float::bigint::StackVec<62>>::mul_small Line | Count | Source | 689 | 3.30k | pub fn mul_small(&mut self, y: Limb) -> Option<()> { | 690 | 3.30k | small_mul(self, y) | 691 | 3.30k | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_>>::mul_small |
692 | | } |
693 | | |
694 | | impl<const SIZE: usize> PartialEq for StackVec<SIZE> { |
695 | | #[inline(always)] |
696 | | #[allow(clippy::op_ref)] // reason="need to convert to slice for equality" |
697 | 0 | fn eq(&self, other: &Self) -> bool { |
698 | | use core::ops::Deref; |
699 | 0 | self.len() == other.len() && self.deref() == other.deref() |
700 | 0 | } |
701 | | } |
702 | | |
703 | | impl<const SIZE: usize> Eq for StackVec<SIZE> { |
704 | | } |
705 | | |
706 | | impl<const SIZE: usize> cmp::PartialOrd for StackVec<SIZE> { |
707 | | #[inline(always)] |
708 | 0 | fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { |
709 | 0 | Some(self.cmp(other)) |
710 | 0 | } |
711 | | } |
712 | | |
713 | | impl<const SIZE: usize> cmp::Ord for StackVec<SIZE> { |
714 | | #[inline(always)] |
715 | 868 | fn cmp(&self, other: &Self) -> cmp::Ordering { |
716 | 868 | compare(self, other) |
717 | 868 | } <lexical_parse_float::bigint::StackVec<62> as core::cmp::Ord>::cmp Line | Count | Source | 715 | 868 | fn cmp(&self, other: &Self) -> cmp::Ordering { | 716 | 868 | compare(self, other) | 717 | 868 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::StackVec<_> as core::cmp::Ord>::cmp |
718 | | } |
719 | | |
720 | | impl<const SIZE: usize> ops::Deref for StackVec<SIZE> { |
721 | | type Target = [Limb]; |
722 | | #[inline(always)] |
723 | 5.74k | fn deref(&self) -> &[Limb] { |
724 | 5.74k | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); |
725 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized |
726 | | // and `self.len() <= self.capacity()`. |
727 | | unsafe { |
728 | 5.74k | let ptr = self.data.as_ptr() as *const Limb; |
729 | 5.74k | slice::from_raw_parts(ptr, self.len()) |
730 | | } |
731 | 5.74k | } <lexical_parse_float::bigint::StackVec<62> as core::ops::deref::Deref>::deref Line | Count | Source | 723 | 5.46k | fn deref(&self) -> &[Limb] { | 724 | 5.46k | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); | 725 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized | 726 | | // and `self.len() <= self.capacity()`. | 727 | | unsafe { | 728 | 5.46k | let ptr = self.data.as_ptr() as *const Limb; | 729 | 5.46k | slice::from_raw_parts(ptr, self.len()) | 730 | | } | 731 | 5.46k | } |
<lexical_parse_float::bigint::StackVec<62> as core::ops::deref::Deref>::deref Line | Count | Source | 723 | 282 | fn deref(&self) -> &[Limb] { | 724 | 282 | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); | 725 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized | 726 | | // and `self.len() <= self.capacity()`. | 727 | | unsafe { | 728 | 282 | let ptr = self.data.as_ptr() as *const Limb; | 729 | 282 | slice::from_raw_parts(ptr, self.len()) | 730 | | } | 731 | 282 | } |
|
732 | | } |
733 | | |
734 | | impl<const SIZE: usize> ops::DerefMut for StackVec<SIZE> { |
735 | | #[inline(always)] |
736 | 8.84k | fn deref_mut(&mut self) -> &mut [Limb] { |
737 | 8.84k | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); |
738 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized |
739 | | // and `self.len() <= self.capacity()`. |
740 | 8.84k | unsafe { |
741 | 8.84k | let ptr = self.data.as_mut_ptr() as *mut Limb; |
742 | 8.84k | slice::from_raw_parts_mut(ptr, self.len()) |
743 | 8.84k | } |
744 | 8.84k | } <lexical_parse_float::bigint::StackVec<62> as core::ops::deref::DerefMut>::deref_mut Line | Count | Source | 736 | 7.30k | fn deref_mut(&mut self) -> &mut [Limb] { | 737 | 7.30k | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); | 738 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized | 739 | | // and `self.len() <= self.capacity()`. | 740 | 7.30k | unsafe { | 741 | 7.30k | let ptr = self.data.as_mut_ptr() as *mut Limb; | 742 | 7.30k | slice::from_raw_parts_mut(ptr, self.len()) | 743 | 7.30k | } | 744 | 7.30k | } |
<lexical_parse_float::bigint::StackVec<62> as core::ops::deref::DerefMut>::deref_mut Line | Count | Source | 736 | 1.54k | fn deref_mut(&mut self) -> &mut [Limb] { | 737 | 1.54k | debug_assert!(self.len() <= self.capacity(), "cannot exceed our array bounds"); | 738 | | // SAFETY: safe since `self.data[..self.len()]` must be initialized | 739 | | // and `self.len() <= self.capacity()`. | 740 | 1.54k | unsafe { | 741 | 1.54k | let ptr = self.data.as_mut_ptr() as *mut Limb; | 742 | 1.54k | slice::from_raw_parts_mut(ptr, self.len()) | 743 | 1.54k | } | 744 | 1.54k | } |
|
745 | | } |
746 | | |
747 | | impl<const SIZE: usize> ops::MulAssign<&[Limb]> for StackVec<SIZE> { |
748 | | #[inline(always)] |
749 | | #[allow(clippy::unwrap_used)] // reason="exceeding the bounds is a developer error" |
750 | 0 | fn mul_assign(&mut self, rhs: &[Limb]) { |
751 | 0 | large_mul(self, rhs).unwrap(); |
752 | 0 | } |
753 | | } |
754 | | |
755 | | impl<const SIZE: usize> Default for StackVec<SIZE> { |
756 | 0 | fn default() -> Self { |
757 | 0 | Self::new() |
758 | 0 | } |
759 | | } |
760 | | |
761 | | // REVERSE VIEW |
762 | | |
763 | | /// Reverse, immutable view of a sequence. |
764 | | pub struct ReverseView<'a, T: 'a> { |
765 | | inner: &'a [T], |
766 | | } |
767 | | |
768 | | impl<'a, T: 'a> ReverseView<'a, T> { |
769 | | /// Get a reference to a value, without bounds checking. |
770 | | /// |
771 | | /// # Safety |
772 | | /// |
773 | | /// Safe if forward indexing would be safe for the type, |
774 | | /// or `index < self.inner.len()`. |
775 | | #[inline(always)] |
776 | 915 | pub unsafe fn get_unchecked(&self, index: usize) -> &T { |
777 | 915 | debug_assert!(index < self.inner.len(), "cannot exceed our array bounds"); |
778 | 915 | let len = self.inner.len(); |
779 | | // SAFETY: Safe as long as the index < length, so len - index - 1 >= 0 and <= |
780 | | // len. |
781 | 915 | unsafe { self.inner.get_unchecked(len - index - 1) } |
782 | 915 | } <lexical_parse_float::bigint::ReverseView<u64>>::get_unchecked Line | Count | Source | 776 | 915 | pub unsafe fn get_unchecked(&self, index: usize) -> &T { | 777 | 915 | debug_assert!(index < self.inner.len(), "cannot exceed our array bounds"); | 778 | 915 | let len = self.inner.len(); | 779 | | // SAFETY: Safe as long as the index < length, so len - index - 1 >= 0 and <= | 780 | | // len. | 781 | 915 | unsafe { self.inner.get_unchecked(len - index - 1) } | 782 | 915 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::ReverseView<_>>::get_unchecked |
783 | | |
784 | | /// Get a reference to a value. |
785 | | #[inline(always)] |
786 | 0 | pub fn get(&self, index: usize) -> Option<&T> { |
787 | 0 | let len = self.inner.len(); |
788 | | // We don't care if this wraps: the index is bounds-checked. |
789 | 0 | self.inner.get(len.wrapping_sub(index + 1)) |
790 | 0 | } |
791 | | |
792 | | /// Get the length of the inner buffer. |
793 | | #[inline(always)] |
794 | 507 | pub const fn len(&self) -> usize { |
795 | 507 | self.inner.len() |
796 | 507 | } <lexical_parse_float::bigint::ReverseView<u64>>::len Line | Count | Source | 794 | 507 | pub const fn len(&self) -> usize { | 795 | 507 | self.inner.len() | 796 | 507 | } |
Unexecuted instantiation: <lexical_parse_float::bigint::ReverseView<_>>::len |
797 | | |
798 | | /// If the vector is empty. |
799 | | #[inline(always)] |
800 | 0 | pub const fn is_empty(&self) -> bool { |
801 | 0 | self.inner.is_empty() |
802 | 0 | } |
803 | | } |
804 | | |
805 | | impl<T> ops::Index<usize> for ReverseView<'_, T> { |
806 | | type Output = T; |
807 | | |
808 | | #[inline(always)] |
809 | 0 | fn index(&self, index: usize) -> &T { |
810 | 0 | let len = self.inner.len(); |
811 | 0 | &(*self.inner)[len - index - 1] |
812 | 0 | } |
813 | | } |
814 | | |
815 | | // HI |
816 | | // -- |
817 | | |
818 | | /// Check if any of the remaining bits are non-zero. |
819 | | /// |
820 | | /// # Safety |
821 | | /// |
822 | | /// Safe as long as `rindex <= x.len()`. This is only called |
823 | | /// where the type size is directly from the caller, and removing |
824 | | /// it leads to a ~20% degradation in performance. |
825 | | #[must_use] |
826 | | #[inline(always)] |
827 | 9 | pub unsafe fn nonzero(x: &[Limb], rindex: usize) -> bool { |
828 | 9 | debug_assert!(rindex <= x.len(), "cannot exceed our array bounds"); |
829 | 9 | let len = x.len(); |
830 | | // SAFETY: safe if `rindex < x.len()`, since then `x.len() - rindex < x.len()`. |
831 | 9 | let slc = unsafe { &index_unchecked!(x[..len - rindex]) }; |
832 | 9 | slc.iter().rev().any(|&x| x != 0) lexical_parse_float::bigint::nonzero::{closure#0}Line | Count | Source | 832 | 9 | slc.iter().rev().any(|&x| x != 0) |
Unexecuted instantiation: lexical_parse_float::bigint::nonzero::{closure#0} |
833 | 9 | } |
834 | | |
835 | | // These return the high X bits and if the bits were truncated. |
836 | | |
837 | | /// Shift 32-bit integer to high 16-bits. |
838 | | #[must_use] |
839 | | #[inline(always)] |
840 | 0 | pub const fn u32_to_hi16_1(r0: u32) -> (u16, bool) { |
841 | 0 | let r0 = u32_to_hi32_1(r0).0; |
842 | 0 | ((r0 >> 16) as u16, r0 as u16 != 0) |
843 | 0 | } |
844 | | |
845 | | /// Shift 2 32-bit integers to high 16-bits. |
846 | | #[must_use] |
847 | | #[inline(always)] |
848 | 0 | pub const fn u32_to_hi16_2(r0: u32, r1: u32) -> (u16, bool) { |
849 | 0 | let (r0, n) = u32_to_hi32_2(r0, r1); |
850 | 0 | ((r0 >> 16) as u16, n || r0 as u16 != 0) |
851 | 0 | } |
852 | | |
853 | | /// Shift 32-bit integer to high 32-bits. |
854 | | #[must_use] |
855 | | #[inline(always)] |
856 | 0 | pub const fn u32_to_hi32_1(r0: u32) -> (u32, bool) { |
857 | 0 | let ls = r0.leading_zeros(); |
858 | 0 | (r0 << ls, false) |
859 | 0 | } |
860 | | |
861 | | /// Shift 2 32-bit integers to high 32-bits. |
862 | | #[must_use] |
863 | | #[inline(always)] |
864 | 0 | pub const fn u32_to_hi32_2(r0: u32, r1: u32) -> (u32, bool) { |
865 | 0 | let ls = r0.leading_zeros(); |
866 | 0 | let rs = 32 - ls; |
867 | 0 | let v = match ls { |
868 | 0 | 0 => r0, |
869 | 0 | _ => (r0 << ls) | (r1 >> rs), |
870 | | }; |
871 | 0 | let n = r1 << ls != 0; |
872 | 0 | (v, n) |
873 | 0 | } |
874 | | |
875 | | /// Shift 32-bit integer to high 64-bits. |
876 | | #[must_use] |
877 | | #[inline(always)] |
878 | 0 | pub const fn u32_to_hi64_1(r0: u32) -> (u64, bool) { |
879 | 0 | u64_to_hi64_1(r0 as u64) |
880 | 0 | } |
881 | | |
882 | | /// Shift 2 32-bit integers to high 64-bits. |
883 | | #[must_use] |
884 | | #[inline(always)] |
885 | 0 | pub const fn u32_to_hi64_2(r0: u32, r1: u32) -> (u64, bool) { |
886 | 0 | let r0 = (r0 as u64) << 32; |
887 | 0 | let r1 = r1 as u64; |
888 | 0 | u64_to_hi64_1(r0 | r1) |
889 | 0 | } |
890 | | |
891 | | /// Shift 3 32-bit integers to high 64-bits. |
892 | | #[must_use] |
893 | | #[inline(always)] |
894 | 0 | pub const fn u32_to_hi64_3(r0: u32, r1: u32, r2: u32) -> (u64, bool) { |
895 | 0 | let r0 = r0 as u64; |
896 | 0 | let r1 = (r1 as u64) << 32; |
897 | 0 | let r2 = r2 as u64; |
898 | 0 | u64_to_hi64_2(r0, r1 | r2) |
899 | 0 | } |
900 | | |
901 | | /// Shift 64-bit integer to high 16-bits. |
902 | | #[must_use] |
903 | | #[inline(always)] |
904 | 0 | pub const fn u64_to_hi16_1(r0: u64) -> (u16, bool) { |
905 | 0 | let r0 = u64_to_hi64_1(r0).0; |
906 | 0 | ((r0 >> 48) as u16, r0 as u16 != 0) |
907 | 0 | } |
908 | | |
909 | | /// Shift 2 64-bit integers to high 16-bits. |
910 | | #[must_use] |
911 | | #[inline(always)] |
912 | 0 | pub const fn u64_to_hi16_2(r0: u64, r1: u64) -> (u16, bool) { |
913 | 0 | let (r0, n) = u64_to_hi64_2(r0, r1); |
914 | 0 | ((r0 >> 48) as u16, n || r0 as u16 != 0) |
915 | 0 | } |
916 | | |
917 | | /// Shift 64-bit integer to high 32-bits. |
918 | | #[must_use] |
919 | | #[inline(always)] |
920 | 0 | pub const fn u64_to_hi32_1(r0: u64) -> (u32, bool) { |
921 | 0 | let r0 = u64_to_hi64_1(r0).0; |
922 | 0 | ((r0 >> 32) as u32, r0 as u32 != 0) |
923 | 0 | } |
924 | | |
925 | | /// Shift 2 64-bit integers to high 32-bits. |
926 | | #[must_use] |
927 | | #[inline(always)] |
928 | 0 | pub const fn u64_to_hi32_2(r0: u64, r1: u64) -> (u32, bool) { |
929 | 0 | let (r0, n) = u64_to_hi64_2(r0, r1); |
930 | 0 | ((r0 >> 32) as u32, n || r0 as u32 != 0) |
931 | 0 | } |
932 | | |
933 | | /// Shift 64-bit integer to high 64-bits. |
934 | | #[must_use] |
935 | | #[inline(always)] |
936 | 99 | pub const fn u64_to_hi64_1(r0: u64) -> (u64, bool) { |
937 | 99 | let ls = r0.leading_zeros(); |
938 | 99 | (r0 << ls, false) |
939 | 99 | } |
940 | | |
941 | | /// Shift 2 64-bit integers to high 64-bits. |
942 | | #[must_use] |
943 | | #[inline(always)] |
944 | 408 | pub const fn u64_to_hi64_2(r0: u64, r1: u64) -> (u64, bool) { |
945 | 408 | let ls = r0.leading_zeros(); |
946 | 408 | let rs = 64 - ls; |
947 | 408 | let v = match ls { |
948 | 3 | 0 => r0, |
949 | 405 | _ => (r0 << ls) | (r1 >> rs), |
950 | | }; |
951 | 408 | let n = r1 << ls != 0; |
952 | 408 | (v, n) |
953 | 408 | } |
954 | | |
955 | | // POWERS |
956 | | // ------ |
957 | | |
958 | | /// MulAssign by a power. |
959 | | /// |
960 | | /// Theoretically... |
961 | | /// |
962 | | /// Use an exponentiation by squaring method, since it reduces the time |
963 | | /// complexity of the multiplication to ~`O(log(n))` for the squaring, |
964 | | /// and `O(n*m)` for the result. Since `m` is typically a lower-order |
965 | | /// factor, this significantly reduces the number of multiplications |
966 | | /// we need to do. Iteratively multiplying by small powers follows |
967 | | /// the nth triangular number series, which scales as `O(p^2)`, but |
968 | | /// where `p` is `n+m`. In short, it scales very poorly. |
969 | | /// |
970 | | /// Practically.... |
971 | | /// |
972 | | /// Exponentiation by Squaring: |
973 | | /// running 2 tests |
974 | | /// test bigcomp_f32_lexical ... bench: 1,018 ns/iter (+/- 78) |
975 | | /// test bigcomp_f64_lexical ... bench: 3,639 ns/iter (+/- 1,007) |
976 | | /// |
977 | | /// Exponentiation by Iterative Small Powers: |
978 | | /// running 2 tests |
979 | | /// test bigcomp_f32_lexical ... bench: 518 ns/iter (+/- 31) |
980 | | /// test bigcomp_f64_lexical ... bench: 583 ns/iter (+/- 47) |
981 | | /// |
982 | | /// Exponentiation by Iterative Large Powers (of 2): |
983 | | /// running 2 tests |
984 | | /// test bigcomp_f32_lexical ... bench: 671 ns/iter (+/- 31) |
985 | | /// test bigcomp_f64_lexical ... bench: 1,394 ns/iter (+/- 47) |
986 | | /// |
987 | | /// The following benchmarks were run on `1 * 5^300`, using native `pow`, |
988 | | /// a version with only small powers, and one with pre-computed powers |
989 | | /// of `5^(3 * max_exp)`, rather than `5^(5 * max_exp)`. |
990 | | /// |
991 | | /// However, using large powers is crucial for good performance for higher |
992 | | /// powers. |
993 | | /// pow/default time: [426.20 ns 427.96 ns 429.89 ns] |
994 | | /// pow/small time: [2.9270 us 2.9411 us 2.9565 us] |
995 | | /// pow/large:3 time: [838.51 ns 842.21 ns 846.27 ns] |
996 | | /// |
997 | | /// Even using worst-case scenarios, exponentiation by squaring is |
998 | | /// significantly slower for our workloads. Just multiply by small powers, |
999 | | /// in simple cases, and use pre-calculated large powers in other cases. |
1000 | | /// |
1001 | | /// Furthermore, using sufficiently big large powers is also crucial for |
1002 | | /// performance. This is a trade-off of binary size and performance, and |
1003 | | /// using a single value at ~`5^(5 * max_exp)` seems optimal. |
1004 | | #[allow(clippy::doc_markdown)] // reason="not attempted to be referencing items" |
1005 | | #[allow(clippy::missing_inline_in_public_items)] // reason="only public for testing" |
1006 | 1.37k | pub fn pow<const SIZE: usize>(x: &mut StackVec<SIZE>, base: u32, mut exp: u32) -> Option<()> { |
1007 | | // Minimize the number of iterations for large exponents: just |
1008 | | // do a few steps with a large powers. |
1009 | | #[cfg(not(feature = "compact"))] |
1010 | | { |
1011 | 1.37k | let (large, step) = get_large_int_power(base); |
1012 | 1.44k | while exp >= step { |
1013 | 72 | large_mul(x, large)?; |
1014 | 72 | exp -= step; |
1015 | | } |
1016 | | } |
1017 | | |
1018 | | // Now use our pre-computed small powers iteratively. |
1019 | 1.37k | let small_step = if Limb::BITS == 32 { |
1020 | 0 | u32_power_limit(base) |
1021 | | } else { |
1022 | 1.37k | u64_power_limit(base) |
1023 | | }; |
1024 | 1.37k | let max_native = (base as Limb).pow(small_step); |
1025 | 1.78k | while exp >= small_step { |
1026 | 411 | small_mul(x, max_native)?; |
1027 | 411 | exp -= small_step; |
1028 | | } |
1029 | 1.37k | if exp != 0 { |
1030 | 905 | let small_power = f64::int_pow_fast_path(exp as usize, base); |
1031 | 905 | small_mul(x, small_power as Limb)?; |
1032 | 470 | } |
1033 | 1.37k | Some(()) |
1034 | 1.37k | } lexical_parse_float::bigint::pow::<62> Line | Count | Source | 1006 | 1.37k | pub fn pow<const SIZE: usize>(x: &mut StackVec<SIZE>, base: u32, mut exp: u32) -> Option<()> { | 1007 | | // Minimize the number of iterations for large exponents: just | 1008 | | // do a few steps with a large powers. | 1009 | | #[cfg(not(feature = "compact"))] | 1010 | | { | 1011 | 1.37k | let (large, step) = get_large_int_power(base); | 1012 | 1.44k | while exp >= step { | 1013 | 72 | large_mul(x, large)?; | 1014 | 72 | exp -= step; | 1015 | | } | 1016 | | } | 1017 | | | 1018 | | // Now use our pre-computed small powers iteratively. | 1019 | 1.37k | let small_step = if Limb::BITS == 32 { | 1020 | 0 | u32_power_limit(base) | 1021 | | } else { | 1022 | 1.37k | u64_power_limit(base) | 1023 | | }; | 1024 | 1.37k | let max_native = (base as Limb).pow(small_step); | 1025 | 1.78k | while exp >= small_step { | 1026 | 411 | small_mul(x, max_native)?; | 1027 | 411 | exp -= small_step; | 1028 | | } | 1029 | 1.37k | if exp != 0 { | 1030 | 905 | let small_power = f64::int_pow_fast_path(exp as usize, base); | 1031 | 905 | small_mul(x, small_power as Limb)?; | 1032 | 470 | } | 1033 | 1.37k | Some(()) | 1034 | 1.37k | } |
Unexecuted instantiation: lexical_parse_float::bigint::pow::<_> |
1035 | | |
1036 | | // SCALAR |
1037 | | // ------ |
1038 | | |
1039 | | /// Add two small integers and return the resulting value and if overflow |
1040 | | /// happens. |
1041 | | #[must_use] |
1042 | | #[inline(always)] |
1043 | 3.48k | pub const fn scalar_add(x: Limb, y: Limb) -> (Limb, bool) { |
1044 | 3.48k | x.overflowing_add(y) |
1045 | 3.48k | } |
1046 | | |
1047 | | /// Multiply two small integers (with carry) (and return the overflow |
1048 | | /// contribution). |
1049 | | /// |
1050 | | /// Returns the (low, high) components. |
1051 | | #[must_use] |
1052 | | #[inline(always)] |
1053 | 6.99k | pub const fn scalar_mul(x: Limb, y: Limb, carry: Limb) -> (Limb, Limb) { |
1054 | | // Cannot overflow, as long as wide is 2x as wide. This is because |
1055 | | // the following is always true: |
1056 | | // `Wide::MAX - (Narrow::MAX * Narrow::MAX) >= Narrow::MAX` |
1057 | 6.99k | let z: Wide = (x as Wide) * (y as Wide) + (carry as Wide); |
1058 | 6.99k | (z as Limb, (z >> Limb::BITS) as Limb) |
1059 | 6.99k | } |
1060 | | |
1061 | | // SMALL |
1062 | | // ----- |
1063 | | |
1064 | | /// Add small integer to bigint starting from offset. |
1065 | | #[inline(always)] |
1066 | 3.30k | pub fn small_add_from<const SIZE: usize>( |
1067 | 3.30k | x: &mut StackVec<SIZE>, |
1068 | 3.30k | y: Limb, |
1069 | 3.30k | start: usize, |
1070 | 3.30k | ) -> Option<()> { |
1071 | 3.30k | let mut index = start; |
1072 | 3.30k | let mut carry = y; |
1073 | 5.07k | while carry != 0 && index < x.len() { |
1074 | 1.76k | // NOTE: Don't need unsafety because the compiler will optimize it out. |
1075 | 1.76k | let result = scalar_add(x[index], carry); |
1076 | 1.76k | x[index] = result.0; |
1077 | 1.76k | carry = result.1 as Limb; |
1078 | 1.76k | index += 1; |
1079 | 1.76k | } |
1080 | | // If we carried past all the elements, add to the end of the buffer. |
1081 | 3.30k | if carry != 0 { |
1082 | 1.37k | x.try_push(carry)?; |
1083 | 1.93k | } |
1084 | 3.30k | Some(()) |
1085 | 3.30k | } lexical_parse_float::bigint::small_add_from::<62> Line | Count | Source | 1066 | 3.30k | pub fn small_add_from<const SIZE: usize>( | 1067 | 3.30k | x: &mut StackVec<SIZE>, | 1068 | 3.30k | y: Limb, | 1069 | 3.30k | start: usize, | 1070 | 3.30k | ) -> Option<()> { | 1071 | 3.30k | let mut index = start; | 1072 | 3.30k | let mut carry = y; | 1073 | 5.07k | while carry != 0 && index < x.len() { | 1074 | 1.76k | // NOTE: Don't need unsafety because the compiler will optimize it out. | 1075 | 1.76k | let result = scalar_add(x[index], carry); | 1076 | 1.76k | x[index] = result.0; | 1077 | 1.76k | carry = result.1 as Limb; | 1078 | 1.76k | index += 1; | 1079 | 1.76k | } | 1080 | | // If we carried past all the elements, add to the end of the buffer. | 1081 | 3.30k | if carry != 0 { | 1082 | 1.37k | x.try_push(carry)?; | 1083 | 1.93k | } | 1084 | 3.30k | Some(()) | 1085 | 3.30k | } |
Unexecuted instantiation: lexical_parse_float::bigint::small_add_from::<62> |
1086 | | |
1087 | | /// Add small integer to bigint. |
1088 | | #[inline(always)] |
1089 | 3.30k | pub fn small_add<const SIZE: usize>(x: &mut StackVec<SIZE>, y: Limb) -> Option<()> { |
1090 | 3.30k | small_add_from(x, y, 0) |
1091 | 3.30k | } lexical_parse_float::bigint::small_add::<62> Line | Count | Source | 1089 | 3.30k | pub fn small_add<const SIZE: usize>(x: &mut StackVec<SIZE>, y: Limb) -> Option<()> { | 1090 | 3.30k | small_add_from(x, y, 0) | 1091 | 3.30k | } |
Unexecuted instantiation: lexical_parse_float::bigint::small_add::<_> |
1092 | | |
1093 | | /// Multiply bigint by small integer. |
1094 | | #[inline(always)] |
1095 | 4.90k | pub fn small_mul<const SIZE: usize>(x: &mut StackVec<SIZE>, y: Limb) -> Option<()> { |
1096 | 4.90k | let mut carry = 0; |
1097 | 6.99k | for xi in x.iter_mut() { |
1098 | 6.99k | let result = scalar_mul(*xi, y, carry); |
1099 | 6.99k | *xi = result.0; |
1100 | 6.99k | carry = result.1; |
1101 | 6.99k | } |
1102 | | // If we carried past all the elements, add to the end of the buffer. |
1103 | 4.90k | if carry != 0 { |
1104 | 3.17k | x.try_push(carry)?; |
1105 | 1.72k | } |
1106 | 4.90k | Some(()) |
1107 | 4.90k | } lexical_parse_float::bigint::small_mul::<62> Line | Count | Source | 1095 | 4.62k | pub fn small_mul<const SIZE: usize>(x: &mut StackVec<SIZE>, y: Limb) -> Option<()> { | 1096 | 4.62k | let mut carry = 0; | 1097 | 5.58k | for xi in x.iter_mut() { | 1098 | 5.58k | let result = scalar_mul(*xi, y, carry); | 1099 | 5.58k | *xi = result.0; | 1100 | 5.58k | carry = result.1; | 1101 | 5.58k | } | 1102 | | // If we carried past all the elements, add to the end of the buffer. | 1103 | 4.62k | if carry != 0 { | 1104 | 2.89k | x.try_push(carry)?; | 1105 | 1.72k | } | 1106 | 4.62k | Some(()) | 1107 | 4.62k | } |
lexical_parse_float::bigint::small_mul::<62> Line | Count | Source | 1095 | 282 | pub fn small_mul<const SIZE: usize>(x: &mut StackVec<SIZE>, y: Limb) -> Option<()> { | 1096 | 282 | let mut carry = 0; | 1097 | 1.41k | for xi in x.iter_mut() { | 1098 | 1.41k | let result = scalar_mul(*xi, y, carry); | 1099 | 1.41k | *xi = result.0; | 1100 | 1.41k | carry = result.1; | 1101 | 1.41k | } | 1102 | | // If we carried past all the elements, add to the end of the buffer. | 1103 | 282 | if carry != 0 { | 1104 | 281 | x.try_push(carry)?; | 1105 | 1 | } | 1106 | 282 | Some(()) | 1107 | 282 | } |
|
1108 | | |
1109 | | // LARGE |
1110 | | // ----- |
1111 | | |
1112 | | /// Add bigint to bigint starting from offset. |
1113 | | #[allow(clippy::missing_inline_in_public_items)] // reason="only public for testing" |
1114 | 210 | pub fn large_add_from<const SIZE: usize>( |
1115 | 210 | x: &mut StackVec<SIZE>, |
1116 | 210 | y: &[Limb], |
1117 | 210 | start: usize, |
1118 | 210 | ) -> Option<()> { |
1119 | | // The effective `x` buffer is from `xstart..x.len()`, so we need to treat |
1120 | | // that as the current range. If the effective `y` buffer is longer, need |
1121 | | // to resize to that, + the start index. |
1122 | 210 | if y.len() > x.len().saturating_sub(start) { |
1123 | | // Ensure we panic if we can't extend the buffer. |
1124 | | // This avoids any unsafe behavior afterwards. |
1125 | 209 | x.try_resize(y.len() + start, 0)?; |
1126 | 1 | } |
1127 | | |
1128 | | // Iteratively add elements from `y` to `x`. |
1129 | 210 | let mut carry = false; |
1130 | 1.25k | for index in 0..y.len() { |
1131 | 1.25k | let xi = &mut x[start + index]; |
1132 | 1.25k | let yi = y[index]; |
1133 | | |
1134 | | // Only one op of the two ops can overflow, since we added at max |
1135 | | // `Limb::max_value() + Limb::max_value()`. Add the previous carry, |
1136 | | // and store the current carry for the next. |
1137 | 1.25k | let result = scalar_add(*xi, yi); |
1138 | 1.25k | *xi = result.0; |
1139 | 1.25k | let mut tmp = result.1; |
1140 | 1.25k | if carry { |
1141 | 455 | let result = scalar_add(*xi, 1); |
1142 | 455 | *xi = result.0; |
1143 | 455 | tmp |= result.1; |
1144 | 804 | } |
1145 | 1.25k | carry = tmp; |
1146 | | } |
1147 | | |
1148 | | // Handle overflow. |
1149 | 210 | if carry { |
1150 | 0 | small_add_from(x, 1, y.len() + start)?; |
1151 | 210 | } |
1152 | 210 | Some(()) |
1153 | 210 | } |
1154 | | |
1155 | | /// Add bigint to bigint. |
1156 | | #[inline(always)] |
1157 | 0 | pub fn large_add<const SIZE: usize>(x: &mut StackVec<SIZE>, y: &[Limb]) -> Option<()> { |
1158 | 0 | large_add_from(x, y, 0) |
1159 | 0 | } |
1160 | | |
1161 | | /// Grade-school multiplication algorithm. |
1162 | | /// |
1163 | | /// Slow, naive algorithm, using limb-bit bases and just shifting left for |
1164 | | /// each iteration. This could be optimized with numerous other algorithms, |
1165 | | /// but it's extremely simple, and works in O(n*m) time, which is fine |
1166 | | /// by me. Each iteration, of which there are `m` iterations, requires |
1167 | | /// `n` multiplications, and `n` additions, or grade-school multiplication. |
1168 | | /// |
1169 | | /// Don't use Karatsuba multiplication, since out implementation seems to |
1170 | | /// be slower asymptotically, which is likely just due to the small sizes |
1171 | | /// we deal with here. For example, running on the following data: |
1172 | | /// |
1173 | | /// ```text |
1174 | | /// const SMALL_X: &[u32] = &[ |
1175 | | /// 766857581, 3588187092, 1583923090, 2204542082, 1564708913, 2695310100, 3676050286, |
1176 | | /// 1022770393, 468044626, 446028186 |
1177 | | /// ]; |
1178 | | /// const SMALL_Y: &[u32] = &[ |
1179 | | /// 3945492125, 3250752032, 1282554898, 1708742809, 1131807209, 3171663979, 1353276095, |
1180 | | /// 1678845844, 2373924447, 3640713171 |
1181 | | /// ]; |
1182 | | /// const LARGE_X: &[u32] = &[ |
1183 | | /// 3647536243, 2836434412, 2154401029, 1297917894, 137240595, 790694805, 2260404854, |
1184 | | /// 3872698172, 690585094, 99641546, 3510774932, 1672049983, 2313458559, 2017623719, |
1185 | | /// 638180197, 1140936565, 1787190494, 1797420655, 14113450, 2350476485, 3052941684, |
1186 | | /// 1993594787, 2901001571, 4156930025, 1248016552, 848099908, 2660577483, 4030871206, |
1187 | | /// 692169593, 2835966319, 1781364505, 4266390061, 1813581655, 4210899844, 2137005290, |
1188 | | /// 2346701569, 3715571980, 3386325356, 1251725092, 2267270902, 474686922, 2712200426, |
1189 | | /// 197581715, 3087636290, 1379224439, 1258285015, 3230794403, 2759309199, 1494932094, |
1190 | | /// 326310242 |
1191 | | /// ]; |
1192 | | /// const LARGE_Y: &[u32] = &[ |
1193 | | /// 1574249566, 868970575, 76716509, 3198027972, 1541766986, 1095120699, 3891610505, |
1194 | | /// 2322545818, 1677345138, 865101357, 2650232883, 2831881215, 3985005565, 2294283760, |
1195 | | /// 3468161605, 393539559, 3665153349, 1494067812, 106699483, 2596454134, 797235106, |
1196 | | /// 705031740, 1209732933, 2732145769, 4122429072, 141002534, 790195010, 4014829800, |
1197 | | /// 1303930792, 3649568494, 308065964, 1233648836, 2807326116, 79326486, 1262500691, |
1198 | | /// 621809229, 2258109428, 3819258501, 171115668, 1139491184, 2979680603, 1333372297, |
1199 | | /// 1657496603, 2790845317, 4090236532, 4220374789, 601876604, 1828177209, 2372228171, |
1200 | | /// 2247372529 |
1201 | | /// ]; |
1202 | | /// ``` |
1203 | | /// |
1204 | | /// We get the following results: |
1205 | | /// |
1206 | | /// ```text |
1207 | | /// mul/small:long time: [220.23 ns 221.47 ns 222.81 ns] |
1208 | | /// Found 4 outliers among 100 measurements (4.00%) |
1209 | | /// 2 (2.00%) high mild |
1210 | | /// 2 (2.00%) high severe |
1211 | | /// mul/small:karatsuba time: [233.88 ns 234.63 ns 235.44 ns] |
1212 | | /// Found 11 outliers among 100 measurements (11.00%) |
1213 | | /// 8 (8.00%) high mild |
1214 | | /// 3 (3.00%) high severe |
1215 | | /// mul/large:long time: [1.9365 us 1.9455 us 1.9558 us] |
1216 | | /// Found 12 outliers among 100 measurements (12.00%) |
1217 | | /// 7 (7.00%) high mild |
1218 | | /// 5 (5.00%) high severe |
1219 | | /// mul/large:karatsuba time: [4.4250 us 4.4515 us 4.4812 us] |
1220 | | /// ``` |
1221 | | /// |
1222 | | /// In short, Karatsuba multiplication is never worthwhile for out use-case. |
1223 | | #[must_use] |
1224 | | #[allow(clippy::needless_range_loop)] // reason="required for performance, see benches" |
1225 | | #[allow(clippy::missing_inline_in_public_items)] // reason="only public for testing" |
1226 | 72 | pub fn long_mul<const SIZE: usize>(x: &[Limb], y: &[Limb]) -> Option<StackVec<SIZE>> { |
1227 | | // Using the immutable value, multiply by all the scalars in y, using |
1228 | | // the algorithm defined above. Use a single buffer to avoid |
1229 | | // frequent reallocations. Handle the first case to avoid a redundant |
1230 | | // addition, since we know y.len() >= 1. |
1231 | 72 | let mut z = StackVec::<SIZE>::try_from(x)?; |
1232 | 72 | if let Some(&y0) = y.first() { |
1233 | 72 | small_mul(&mut z, y0)?; |
1234 | | |
1235 | | // NOTE: Don't use enumerate/skip since it's slow. |
1236 | 210 | for index in 1..y.len() { |
1237 | 210 | let yi = y[index]; |
1238 | 210 | if yi != 0 { |
1239 | 210 | let mut zi = StackVec::<SIZE>::try_from(x)?; |
1240 | 210 | small_mul(&mut zi, yi)?; |
1241 | 210 | large_add_from(&mut z, &zi, index)?; |
1242 | 0 | } |
1243 | | } |
1244 | 0 | } |
1245 | | |
1246 | 72 | z.normalize(); |
1247 | 72 | Some(z) |
1248 | 72 | } |
1249 | | |
1250 | | /// Multiply bigint by bigint using grade-school multiplication algorithm. |
1251 | | #[inline(always)] |
1252 | 72 | pub fn large_mul<const SIZE: usize>(x: &mut StackVec<SIZE>, y: &[Limb]) -> Option<()> { |
1253 | | // Karatsuba multiplication never makes sense, so just use grade school |
1254 | | // multiplication. |
1255 | 72 | if y.len() == 1 { |
1256 | | // SAFETY: safe since `y.len() == 1`. |
1257 | | // NOTE: The compiler does not seem to optimize this out correctly. |
1258 | 0 | small_mul(x, unsafe { index_unchecked!(y[0]) })?; |
1259 | | } else { |
1260 | 72 | *x = long_mul(y, x)?; |
1261 | | } |
1262 | 72 | Some(()) |
1263 | 72 | } lexical_parse_float::bigint::large_mul::<62> Line | Count | Source | 1252 | 72 | pub fn large_mul<const SIZE: usize>(x: &mut StackVec<SIZE>, y: &[Limb]) -> Option<()> { | 1253 | | // Karatsuba multiplication never makes sense, so just use grade school | 1254 | | // multiplication. | 1255 | 72 | if y.len() == 1 { | 1256 | | // SAFETY: safe since `y.len() == 1`. | 1257 | | // NOTE: The compiler does not seem to optimize this out correctly. | 1258 | 0 | small_mul(x, unsafe { index_unchecked!(y[0]) })?; | 1259 | | } else { | 1260 | 72 | *x = long_mul(y, x)?; | 1261 | | } | 1262 | 72 | Some(()) | 1263 | 72 | } |
Unexecuted instantiation: lexical_parse_float::bigint::large_mul::<62> |
1264 | | |
1265 | | /// Emit a single digit for the quotient and store the remainder in-place. |
1266 | | /// |
1267 | | /// An extremely efficient division algorithm for small quotients, requiring |
1268 | | /// you to know the full range of the quotient prior to use. For example, |
1269 | | /// with a quotient that can range from [0, 10), you must have 4 leading |
1270 | | /// zeros in the divisor, so we can use a single-limb division to get |
1271 | | /// an accurate estimate of the quotient. Since we always underestimate |
1272 | | /// the quotient, we can add 1 and then emit the digit. |
1273 | | /// |
1274 | | /// Requires a non-normalized denominator, with at least [1-6] leading |
1275 | | /// zeros, depending on the base (for example, 1 for base2, 6 for base36). |
1276 | | /// |
1277 | | /// Adapted from David M. Gay's dtoa, and therefore under an MIT license: |
1278 | | /// www.netlib.org/fp/dtoa.c |
1279 | | #[cfg(feature = "radix")] |
1280 | | #[allow(clippy::many_single_char_names)] // reason = "mathematical names of variables" |
1281 | | pub fn large_quorem<const SIZE: usize>(x: &mut StackVec<SIZE>, y: &[Limb]) -> Limb { |
1282 | | // If we have an empty divisor, error out early. |
1283 | | assert!(!y.is_empty(), "large_quorem:: division by zero error."); |
1284 | | assert!(x.len() <= y.len(), "large_quorem:: oversized numerator."); |
1285 | | let mask = Limb::MAX as Wide; |
1286 | | |
1287 | | // Numerator is smaller the denominator, quotient always 0. |
1288 | | if x.len() < y.len() { |
1289 | | return 0; |
1290 | | } |
1291 | | |
1292 | | // Calculate our initial estimate for q. |
1293 | | let xm_1 = x[x.len() - 1]; |
1294 | | let yn_1 = y[y.len() - 1]; |
1295 | | let mut q = xm_1 / (yn_1 + 1); |
1296 | | |
1297 | | // Need to calculate the remainder if we don't have a 0 quotient. |
1298 | | if q != 0 { |
1299 | | let mut borrow: Wide = 0; |
1300 | | let mut carry: Wide = 0; |
1301 | | for j in 0..x.len() { |
1302 | | let yj = y[j] as Wide; |
1303 | | let p = yj * q as Wide + carry; |
1304 | | carry = p >> Limb::BITS; |
1305 | | let xj = x[j] as Wide; |
1306 | | let t = xj.wrapping_sub(p & mask).wrapping_sub(borrow); |
1307 | | borrow = (t >> Limb::BITS) & 1; |
1308 | | x[j] = t as Limb; |
1309 | | } |
1310 | | x.normalize(); |
1311 | | } |
1312 | | |
1313 | | // Check if we under-estimated x. |
1314 | | if compare(x, y) != cmp::Ordering::Less { |
1315 | | q += 1; |
1316 | | let mut borrow: Wide = 0; |
1317 | | let mut carry: Wide = 0; |
1318 | | for j in 0..x.len() { |
1319 | | let yj = y[j] as Wide; |
1320 | | let p = yj + carry; |
1321 | | carry = p >> Limb::BITS; |
1322 | | let xj = x[j] as Wide; |
1323 | | let t = xj.wrapping_sub(p & mask).wrapping_sub(borrow); |
1324 | | borrow = (t >> Limb::BITS) & 1; |
1325 | | x[j] = t as Limb; |
1326 | | } |
1327 | | x.normalize(); |
1328 | | } |
1329 | | |
1330 | | q |
1331 | | } |
1332 | | |
1333 | | // COMPARE |
1334 | | // ------- |
1335 | | |
1336 | | /// Compare `x` to `y`, in little-endian order. |
1337 | | #[must_use] |
1338 | | #[inline(always)] |
1339 | 868 | pub fn compare(x: &[Limb], y: &[Limb]) -> cmp::Ordering { |
1340 | 868 | match x.len().cmp(&y.len()) { |
1341 | | cmp::Ordering::Equal => { |
1342 | 868 | let iter = x.iter().rev().zip(y.iter().rev()); |
1343 | 1.82k | for (&xi, yi) in iter { |
1344 | 1.80k | match xi.cmp(yi) { |
1345 | 956 | cmp::Ordering::Equal => (), |
1346 | 851 | ord => return ord, |
1347 | | } |
1348 | | } |
1349 | | // Equal case. |
1350 | 17 | cmp::Ordering::Equal |
1351 | | }, |
1352 | 0 | ord => ord, |
1353 | | } |
1354 | 868 | } |
1355 | | |
1356 | | // SHIFT |
1357 | | // ----- |
1358 | | |
1359 | | /// Shift-left `n` bits inside a buffer. |
1360 | | #[inline(always)] |
1361 | 910 | pub fn shl_bits<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { |
1362 | 910 | debug_assert!(n != 0, "cannot shift left by 0 bits"); |
1363 | | |
1364 | | // Internally, for each item, we shift left by n, and add the previous |
1365 | | // right shifted limb-bits. |
1366 | | // For example, we transform (for u8) shifted left 2, to: |
1367 | | // b10100100 b01000010 |
1368 | | // b10 b10010001 b00001000 |
1369 | 910 | debug_assert!(n < Limb::BITS as usize, "cannot shift left more bits than in our limb"); |
1370 | 910 | let rshift = Limb::BITS as usize - n; |
1371 | 910 | let lshift = n; |
1372 | 910 | let mut prev: Limb = 0; |
1373 | 2.35k | for xi in x.iter_mut() { |
1374 | 2.35k | let tmp = *xi; |
1375 | 2.35k | *xi <<= lshift; |
1376 | 2.35k | *xi |= prev >> rshift; |
1377 | 2.35k | prev = tmp; |
1378 | 2.35k | } |
1379 | | |
1380 | | // Always push the carry, even if it creates a non-normal result. |
1381 | 910 | let carry = prev >> rshift; |
1382 | 910 | if carry != 0 { |
1383 | 272 | x.try_push(carry)?; |
1384 | 638 | } |
1385 | | |
1386 | 910 | Some(()) |
1387 | 910 | } lexical_parse_float::bigint::shl_bits::<62> Line | Count | Source | 1361 | 910 | pub fn shl_bits<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { | 1362 | 910 | debug_assert!(n != 0, "cannot shift left by 0 bits"); | 1363 | | | 1364 | | // Internally, for each item, we shift left by n, and add the previous | 1365 | | // right shifted limb-bits. | 1366 | | // For example, we transform (for u8) shifted left 2, to: | 1367 | | // b10100100 b01000010 | 1368 | | // b10 b10010001 b00001000 | 1369 | 910 | debug_assert!(n < Limb::BITS as usize, "cannot shift left more bits than in our limb"); | 1370 | 910 | let rshift = Limb::BITS as usize - n; | 1371 | 910 | let lshift = n; | 1372 | 910 | let mut prev: Limb = 0; | 1373 | 2.35k | for xi in x.iter_mut() { | 1374 | 2.35k | let tmp = *xi; | 1375 | 2.35k | *xi <<= lshift; | 1376 | 2.35k | *xi |= prev >> rshift; | 1377 | 2.35k | prev = tmp; | 1378 | 2.35k | } | 1379 | | | 1380 | | // Always push the carry, even if it creates a non-normal result. | 1381 | 910 | let carry = prev >> rshift; | 1382 | 910 | if carry != 0 { | 1383 | 272 | x.try_push(carry)?; | 1384 | 638 | } | 1385 | | | 1386 | 910 | Some(()) | 1387 | 910 | } |
Unexecuted instantiation: lexical_parse_float::bigint::shl_bits::<_> |
1388 | | |
1389 | | /// Shift-left `n` limbs inside a buffer. |
1390 | | #[inline(always)] |
1391 | 103 | pub fn shl_limbs<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { |
1392 | 103 | debug_assert!(n != 0, "cannot shift left by 0 bits"); |
1393 | 103 | if n + x.len() > x.capacity() { |
1394 | 0 | None |
1395 | 103 | } else if !x.is_empty() { |
1396 | 103 | let len = n + x.len(); |
1397 | 103 | let x_len = x.len(); |
1398 | 103 | let ptr = x.as_mut_ptr(); |
1399 | 103 | let src = ptr; |
1400 | | // SAFETY: since x is not empty, and `x.len() + n <= x.capacity()`. |
1401 | 103 | unsafe { |
1402 | 103 | // Move the elements. |
1403 | 103 | let dst = ptr.add(n); |
1404 | 103 | ptr::copy(src, dst, x_len); |
1405 | 103 | // Write our 0s. |
1406 | 103 | ptr::write_bytes(ptr, 0, n); |
1407 | 103 | x.set_len(len); |
1408 | 103 | } |
1409 | 103 | Some(()) |
1410 | | } else { |
1411 | 0 | Some(()) |
1412 | | } |
1413 | 103 | } lexical_parse_float::bigint::shl_limbs::<62> Line | Count | Source | 1391 | 103 | pub fn shl_limbs<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { | 1392 | 103 | debug_assert!(n != 0, "cannot shift left by 0 bits"); | 1393 | 103 | if n + x.len() > x.capacity() { | 1394 | 0 | None | 1395 | 103 | } else if !x.is_empty() { | 1396 | 103 | let len = n + x.len(); | 1397 | 103 | let x_len = x.len(); | 1398 | 103 | let ptr = x.as_mut_ptr(); | 1399 | 103 | let src = ptr; | 1400 | | // SAFETY: since x is not empty, and `x.len() + n <= x.capacity()`. | 1401 | 103 | unsafe { | 1402 | 103 | // Move the elements. | 1403 | 103 | let dst = ptr.add(n); | 1404 | 103 | ptr::copy(src, dst, x_len); | 1405 | 103 | // Write our 0s. | 1406 | 103 | ptr::write_bytes(ptr, 0, n); | 1407 | 103 | x.set_len(len); | 1408 | 103 | } | 1409 | 103 | Some(()) | 1410 | | } else { | 1411 | 0 | Some(()) | 1412 | | } | 1413 | 103 | } |
Unexecuted instantiation: lexical_parse_float::bigint::shl_limbs::<_> |
1414 | | |
1415 | | /// Shift-left buffer by n bits. |
1416 | | #[must_use] |
1417 | | #[inline(always)] |
1418 | 1.36k | pub fn shl<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { |
1419 | 1.36k | let rem = n % Limb::BITS as usize; |
1420 | 1.36k | let div = n / Limb::BITS as usize; |
1421 | 1.36k | if rem != 0 { |
1422 | 910 | shl_bits(x, rem)?; |
1423 | 450 | } |
1424 | 1.36k | if div != 0 { |
1425 | 103 | shl_limbs(x, div)?; |
1426 | 1.25k | } |
1427 | 1.36k | Some(()) |
1428 | 1.36k | } lexical_parse_float::bigint::shl::<62> Line | Count | Source | 1418 | 1.36k | pub fn shl<const SIZE: usize>(x: &mut StackVec<SIZE>, n: usize) -> Option<()> { | 1419 | 1.36k | let rem = n % Limb::BITS as usize; | 1420 | 1.36k | let div = n / Limb::BITS as usize; | 1421 | 1.36k | if rem != 0 { | 1422 | 910 | shl_bits(x, rem)?; | 1423 | 450 | } | 1424 | 1.36k | if div != 0 { | 1425 | 103 | shl_limbs(x, div)?; | 1426 | 1.25k | } | 1427 | 1.36k | Some(()) | 1428 | 1.36k | } |
Unexecuted instantiation: lexical_parse_float::bigint::shl::<_> |
1429 | | |
1430 | | /// Get number of leading zero bits in the storage. |
1431 | | #[must_use] |
1432 | | #[inline(always)] |
1433 | 507 | pub fn leading_zeros(x: &[Limb]) -> u32 { |
1434 | 507 | let length = x.len(); |
1435 | | // `wrapping_sub` is fine, since it'll just return None. |
1436 | 507 | if let Some(&value) = x.get(length.wrapping_sub(1)) { |
1437 | 507 | value.leading_zeros() |
1438 | | } else { |
1439 | 0 | 0 |
1440 | | } |
1441 | 507 | } |
1442 | | |
1443 | | /// Calculate the bit-length of the big-integer. |
1444 | | #[must_use] |
1445 | | #[inline(always)] |
1446 | 507 | pub fn bit_length(x: &[Limb]) -> u32 { |
1447 | 507 | let nlz = leading_zeros(x); |
1448 | 507 | Limb::BITS * x.len() as u32 - nlz |
1449 | 507 | } |
1450 | | |
1451 | | // RADIX |
1452 | | // ----- |
1453 | | |
1454 | | /// Get the base, odd radix, and the power-of-two for the type. |
1455 | | #[must_use] |
1456 | | #[inline(always)] |
1457 | | #[cfg(feature = "radix")] |
1458 | | pub const fn split_radix(radix: u32) -> (u32, u32) { |
1459 | | match radix { |
1460 | | 2 => (0, 1), |
1461 | | 3 => (3, 0), |
1462 | | 4 => (0, 2), |
1463 | | 5 => (5, 0), |
1464 | | 6 => (3, 1), |
1465 | | 7 => (7, 0), |
1466 | | 8 => (0, 3), |
1467 | | 9 => (9, 0), |
1468 | | 10 => (5, 1), |
1469 | | 11 => (11, 0), |
1470 | | 12 => (6, 1), |
1471 | | 13 => (13, 0), |
1472 | | 14 => (7, 1), |
1473 | | 15 => (15, 0), |
1474 | | 16 => (0, 4), |
1475 | | 17 => (17, 0), |
1476 | | 18 => (9, 1), |
1477 | | 19 => (19, 0), |
1478 | | 20 => (5, 2), |
1479 | | 21 => (21, 0), |
1480 | | 22 => (11, 1), |
1481 | | 23 => (23, 0), |
1482 | | 24 => (3, 3), |
1483 | | 25 => (25, 0), |
1484 | | 26 => (13, 1), |
1485 | | 27 => (27, 0), |
1486 | | 28 => (7, 2), |
1487 | | 29 => (29, 0), |
1488 | | 30 => (15, 1), |
1489 | | 31 => (31, 0), |
1490 | | 32 => (0, 5), |
1491 | | 33 => (33, 0), |
1492 | | 34 => (17, 1), |
1493 | | 35 => (35, 0), |
1494 | | 36 => (9, 2), |
1495 | | // Any other radix should be unreachable. |
1496 | | _ => (0, 0), |
1497 | | } |
1498 | | } |
1499 | | |
1500 | | /// Get the base, odd radix, and the power-of-two for the type. |
1501 | | #[must_use] |
1502 | | #[inline(always)] |
1503 | | #[cfg(all(feature = "power-of-two", not(feature = "radix")))] |
1504 | | pub const fn split_radix(radix: u32) -> (u32, u32) { |
1505 | | match radix { |
1506 | | // Is also needed for decimal floats, due to `negative_digit_comp`. |
1507 | | 2 => (0, 1), |
1508 | | 4 => (0, 2), |
1509 | | // Is also needed for decimal floats, due to `negative_digit_comp`. |
1510 | | 5 => (5, 0), |
1511 | | 8 => (0, 3), |
1512 | | 10 => (5, 1), |
1513 | | 16 => (0, 4), |
1514 | | 32 => (0, 5), |
1515 | | // Any other radix should be unreachable. |
1516 | | _ => (0, 0), |
1517 | | } |
1518 | | } |
1519 | | |
1520 | | /// Get the base, odd radix, and the power-of-two for the type. |
1521 | | #[must_use] |
1522 | | #[inline(always)] |
1523 | | #[cfg(not(feature = "power-of-two"))] |
1524 | 2.22k | pub const fn split_radix(radix: u32) -> (u32, u32) { |
1525 | 2.22k | match radix { |
1526 | | // Is also needed for decimal floats, due to `negative_digit_comp`. |
1527 | 853 | 2 => (0, 1), |
1528 | | // Is also needed for decimal floats, due to `negative_digit_comp`. |
1529 | 868 | 5 => (5, 0), |
1530 | 507 | 10 => (5, 1), |
1531 | | // Any other radix should be unreachable. |
1532 | 0 | _ => (0, 0), |
1533 | | } |
1534 | 2.22k | } |
1535 | | |
1536 | | // LIMB |
1537 | | // ---- |
1538 | | |
1539 | | // Type for a single limb of the big integer. |
1540 | | // |
1541 | | // A limb is analogous to a digit in base10, except, it stores 32-bit |
1542 | | // or 64-bit numbers instead. We want types where 64-bit multiplication |
1543 | | // is well-supported by the architecture, rather than emulated in 3 |
1544 | | // instructions. The quickest way to check this support is using a |
1545 | | // cross-compiler for numerous architectures, along with the following |
1546 | | // source file and command: |
1547 | | // |
1548 | | // Compile with `gcc main.c -c -S -O3 -masm=intel` |
1549 | | // |
1550 | | // And the source code is: |
1551 | | // ```text |
1552 | | // #include <stdint.h> |
1553 | | // |
1554 | | // struct i128 { |
1555 | | // uint64_t hi; |
1556 | | // uint64_t lo; |
1557 | | // }; |
1558 | | // |
1559 | | // // Type your code here, or load an example. |
1560 | | // struct i128 square(uint64_t x, uint64_t y) { |
1561 | | // __int128 prod = (__int128)x * (__int128)y; |
1562 | | // struct i128 z; |
1563 | | // z.hi = (uint64_t)(prod >> 64); |
1564 | | // z.lo = (uint64_t)prod; |
1565 | | // return z; |
1566 | | // } |
1567 | | // ``` |
1568 | | // |
1569 | | // If the result contains `call __multi3`, then the multiplication |
1570 | | // is emulated by the compiler. Otherwise, it's natively supported. |
1571 | | // |
1572 | | // This should be all-known 64-bit platforms supported by Rust. |
1573 | | // https://forge.rust-lang.org/platform-support.html |
1574 | | // |
1575 | | // # Supported |
1576 | | // |
1577 | | // Platforms where native 128-bit multiplication is explicitly supported: |
1578 | | // - x86_64 (Supported via `MUL`). |
1579 | | // - mips64 (Supported via `DMULTU`, which `HI` and `LO` can be read-from). |
1580 | | // - s390x (Supported via `MLGR`). |
1581 | | // |
1582 | | // # Efficient |
1583 | | // |
1584 | | // Platforms where native 64-bit multiplication is supported and |
1585 | | // you can extract hi-lo for 64-bit multiplications. |
1586 | | // - aarch64 (Requires `UMULH` and `MUL` to capture high and low bits). |
1587 | | // - powerpc64 (Requires `MULHDU` and `MULLD` to capture high and low |
1588 | | // bits). |
1589 | | // - riscv64 (Requires `MUL` and `MULH` to capture high and low bits). |
1590 | | // |
1591 | | // # Unsupported |
1592 | | // |
1593 | | // Platforms where native 128-bit multiplication is not supported, |
1594 | | // requiring software emulation. |
1595 | | // sparc64 (`UMUL` only supports double-word arguments). |
1596 | | // sparcv9 (Same as sparc64). |
1597 | | // |
1598 | | // These tests are run via `xcross`, my own library for C cross-compiling, |
1599 | | // which supports numerous targets (far in excess of Rust's tier 1 support, |
1600 | | // or rust-embedded/cross's list). xcross may be found here: |
1601 | | // https://github.com/Alexhuszagh/xcross |
1602 | | // |
1603 | | // To compile for the given target, run: |
1604 | | // `xcross gcc main.c -c -S -O3 --target $target` |
1605 | | // |
1606 | | // All 32-bit architectures inherently do not have support. That means |
1607 | | // we can essentially look for 64-bit architectures that are not SPARC. |
1608 | | |
1609 | | #[cfg(all(target_pointer_width = "64", not(target_arch = "sparc")))] |
1610 | | pub type Limb = u64; |
1611 | | #[cfg(all(target_pointer_width = "64", not(target_arch = "sparc")))] |
1612 | | pub type Wide = u128; |
1613 | | #[cfg(all(target_pointer_width = "64", not(target_arch = "sparc")))] |
1614 | | pub type SignedWide = i128; |
1615 | | |
1616 | | #[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))] |
1617 | | pub type Limb = u32; |
1618 | | #[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))] |
1619 | | pub type Wide = u64; |
1620 | | #[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))] |
1621 | | pub type SignedWide = i64; |