/Users/andrewlamb/Software/arrow-rs/arrow-buffer/src/bigint/mod.rs
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | use crate::arith::derive_arith; |
19 | | use crate::bigint::div::div_rem; |
20 | | use num::cast::AsPrimitive; |
21 | | use num::{BigInt, FromPrimitive, ToPrimitive}; |
22 | | use std::cmp::Ordering; |
23 | | use std::num::ParseIntError; |
24 | | use std::ops::{BitAnd, BitOr, BitXor, Neg, Shl, Shr}; |
25 | | use std::str::FromStr; |
26 | | |
27 | | mod div; |
28 | | |
29 | | /// An opaque error similar to [`std::num::ParseIntError`] |
30 | | #[derive(Debug)] |
31 | | pub struct ParseI256Error {} |
32 | | |
33 | | impl From<ParseIntError> for ParseI256Error { |
34 | 0 | fn from(_: ParseIntError) -> Self { |
35 | 0 | Self {} |
36 | 0 | } |
37 | | } |
38 | | |
39 | | impl std::fmt::Display for ParseI256Error { |
40 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
41 | 0 | write!(f, "Failed to parse as i256") |
42 | 0 | } |
43 | | } |
44 | | impl std::error::Error for ParseI256Error {} |
45 | | |
46 | | /// Error returned by i256::DivRem |
47 | | enum DivRemError { |
48 | | /// Division by zero |
49 | | DivideByZero, |
50 | | /// Division overflow |
51 | | DivideOverflow, |
52 | | } |
53 | | |
54 | | /// A signed 256-bit integer |
55 | | #[allow(non_camel_case_types)] |
56 | | #[derive(Copy, Clone, Default, Eq, PartialEq, Hash)] |
57 | | #[repr(C)] |
58 | | pub struct i256 { |
59 | | low: u128, |
60 | | high: i128, |
61 | | } |
62 | | |
63 | | impl std::fmt::Debug for i256 { |
64 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
65 | 0 | write!(f, "{self}") |
66 | 0 | } |
67 | | } |
68 | | |
69 | | impl std::fmt::Display for i256 { |
70 | 2 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
71 | 2 | write!(f, "{}", BigInt::from_signed_bytes_le(&self.to_le_bytes())) |
72 | 2 | } |
73 | | } |
74 | | |
75 | | impl FromStr for i256 { |
76 | | type Err = ParseI256Error; |
77 | | |
78 | 0 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
79 | | // i128 can store up to 38 decimal digits |
80 | 0 | if s.len() <= 38 { |
81 | 0 | return Ok(Self::from_i128(i128::from_str(s)?)); |
82 | 0 | } |
83 | | |
84 | 0 | let (negative, s) = match s.as_bytes()[0] { |
85 | 0 | b'-' => (true, &s[1..]), |
86 | 0 | b'+' => (false, &s[1..]), |
87 | 0 | _ => (false, s), |
88 | | }; |
89 | | |
90 | | // Trim leading 0s |
91 | 0 | let s = s.trim_start_matches('0'); |
92 | 0 | if s.is_empty() { |
93 | 0 | return Ok(i256::ZERO); |
94 | 0 | } |
95 | | |
96 | 0 | if !s.as_bytes()[0].is_ascii_digit() { |
97 | | // Ensures no duplicate sign |
98 | 0 | return Err(ParseI256Error {}); |
99 | 0 | } |
100 | | |
101 | 0 | parse_impl(s, negative) |
102 | 0 | } |
103 | | } |
104 | | |
105 | | impl From<i8> for i256 { |
106 | 0 | fn from(value: i8) -> Self { |
107 | 0 | Self::from_i128(value.into()) |
108 | 0 | } |
109 | | } |
110 | | |
111 | | impl From<i16> for i256 { |
112 | 0 | fn from(value: i16) -> Self { |
113 | 0 | Self::from_i128(value.into()) |
114 | 0 | } |
115 | | } |
116 | | |
117 | | impl From<i32> for i256 { |
118 | 0 | fn from(value: i32) -> Self { |
119 | 0 | Self::from_i128(value.into()) |
120 | 0 | } |
121 | | } |
122 | | |
123 | | impl From<i64> for i256 { |
124 | 0 | fn from(value: i64) -> Self { |
125 | 0 | Self::from_i128(value.into()) |
126 | 0 | } |
127 | | } |
128 | | |
129 | | /// Parse `s` with any sign and leading 0s removed |
130 | 0 | fn parse_impl(s: &str, negative: bool) -> Result<i256, ParseI256Error> { |
131 | 0 | if s.len() <= 38 { |
132 | 0 | let low = i128::from_str(s)?; |
133 | 0 | return Ok(match negative { |
134 | 0 | true => i256::from_parts(low.neg() as _, -1), |
135 | 0 | false => i256::from_parts(low as _, 0), |
136 | | }); |
137 | 0 | } |
138 | | |
139 | 0 | let split = s.len() - 38; |
140 | 0 | if !s.as_bytes()[split].is_ascii_digit() { |
141 | | // Ensures not splitting codepoint and no sign |
142 | 0 | return Err(ParseI256Error {}); |
143 | 0 | } |
144 | 0 | let (hs, ls) = s.split_at(split); |
145 | | |
146 | 0 | let mut low = i128::from_str(ls)?; |
147 | 0 | let high = parse_impl(hs, negative)?; |
148 | | |
149 | 0 | if negative { |
150 | 0 | low = -low; |
151 | 0 | } |
152 | | |
153 | 0 | let low = i256::from_i128(low); |
154 | | |
155 | 0 | high.checked_mul(i256::from_i128(10_i128.pow(38))) |
156 | 0 | .and_then(|high| high.checked_add(low)) |
157 | 0 | .ok_or(ParseI256Error {}) |
158 | 0 | } |
159 | | |
160 | | impl PartialOrd for i256 { |
161 | 0 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
162 | 0 | Some(self.cmp(other)) |
163 | 0 | } |
164 | | } |
165 | | |
166 | | impl Ord for i256 { |
167 | 0 | fn cmp(&self, other: &Self) -> Ordering { |
168 | | // This is 25x faster than using a variable length encoding such |
169 | | // as BigInt as it avoids allocation and branching |
170 | 0 | self.high.cmp(&other.high).then(self.low.cmp(&other.low)) |
171 | 0 | } |
172 | | } |
173 | | |
174 | | impl i256 { |
175 | | /// The additive identity for this integer type, i.e. `0`. |
176 | | pub const ZERO: Self = i256 { low: 0, high: 0 }; |
177 | | |
178 | | /// The multiplicative identity for this integer type, i.e. `1`. |
179 | | pub const ONE: Self = i256 { low: 1, high: 0 }; |
180 | | |
181 | | /// The multiplicative inverse for this integer type, i.e. `-1`. |
182 | | pub const MINUS_ONE: Self = i256 { |
183 | | low: u128::MAX, |
184 | | high: -1, |
185 | | }; |
186 | | |
187 | | /// The maximum value that can be represented by this integer type |
188 | | pub const MAX: Self = i256 { |
189 | | low: u128::MAX, |
190 | | high: i128::MAX, |
191 | | }; |
192 | | |
193 | | /// The minimum value that can be represented by this integer type |
194 | | pub const MIN: Self = i256 { |
195 | | low: u128::MIN, |
196 | | high: i128::MIN, |
197 | | }; |
198 | | |
199 | | /// Create an integer value from its representation as a byte array in little-endian. |
200 | | #[inline] |
201 | 0 | pub const fn from_le_bytes(b: [u8; 32]) -> Self { |
202 | 0 | let (low, high) = split_array(b); |
203 | 0 | Self { |
204 | 0 | high: i128::from_le_bytes(high), |
205 | 0 | low: u128::from_le_bytes(low), |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | /// Create an integer value from its representation as a byte array in big-endian. |
210 | | #[inline] |
211 | 2 | pub const fn from_be_bytes(b: [u8; 32]) -> Self { |
212 | 2 | let (high, low) = split_array(b); |
213 | 2 | Self { |
214 | 2 | high: i128::from_be_bytes(high), |
215 | 2 | low: u128::from_be_bytes(low), |
216 | 2 | } |
217 | 2 | } |
218 | | |
219 | | /// Create an `i256` value from a 128-bit value. |
220 | 0 | pub const fn from_i128(v: i128) -> Self { |
221 | 0 | Self::from_parts(v as u128, v >> 127) |
222 | 0 | } |
223 | | |
224 | | /// Create an integer value from its representation as string. |
225 | | #[inline] |
226 | 0 | pub fn from_string(value_str: &str) -> Option<Self> { |
227 | 0 | value_str.parse().ok() |
228 | 0 | } |
229 | | |
230 | | /// Create an optional i256 from the provided `f64`. Returning `None` |
231 | | /// if overflow occurred |
232 | 0 | pub fn from_f64(v: f64) -> Option<Self> { |
233 | 0 | BigInt::from_f64(v).and_then(|i| { |
234 | 0 | let (integer, overflow) = i256::from_bigint_with_overflow(i); |
235 | 0 | if overflow { |
236 | 0 | None |
237 | | } else { |
238 | 0 | Some(integer) |
239 | | } |
240 | 0 | }) |
241 | 0 | } |
242 | | |
243 | | /// Create an i256 from the provided low u128 and high i128 |
244 | | #[inline] |
245 | 0 | pub const fn from_parts(low: u128, high: i128) -> Self { |
246 | 0 | Self { low, high } |
247 | 0 | } |
248 | | |
249 | | /// Returns this `i256` as a low u128 and high i128 |
250 | 0 | pub const fn to_parts(self) -> (u128, i128) { |
251 | 0 | (self.low, self.high) |
252 | 0 | } |
253 | | |
254 | | /// Converts this `i256` into an `i128` returning `None` if this would result |
255 | | /// in truncation/overflow |
256 | 0 | pub fn to_i128(self) -> Option<i128> { |
257 | 0 | let as_i128 = self.low as i128; |
258 | | |
259 | 0 | let high_negative = self.high < 0; |
260 | 0 | let low_negative = as_i128 < 0; |
261 | 0 | let high_valid = self.high == -1 || self.high == 0; |
262 | | |
263 | 0 | (high_negative == low_negative && high_valid).then_some(self.low as i128) |
264 | 0 | } |
265 | | |
266 | | /// Wraps this `i256` into an `i128` |
267 | 0 | pub fn as_i128(self) -> i128 { |
268 | 0 | self.low as i128 |
269 | 0 | } |
270 | | |
271 | | /// Return the memory representation of this integer as a byte array in little-endian byte order. |
272 | | #[inline] |
273 | 2 | pub const fn to_le_bytes(self) -> [u8; 32] { |
274 | 2 | let low = self.low.to_le_bytes(); |
275 | 2 | let high = self.high.to_le_bytes(); |
276 | 2 | let mut t = [0; 32]; |
277 | 2 | let mut i = 0; |
278 | 34 | while i != 16 { |
279 | 32 | t[i] = low[i]; |
280 | 32 | t[i + 16] = high[i]; |
281 | 32 | i += 1; |
282 | 32 | } |
283 | 2 | t |
284 | 2 | } |
285 | | |
286 | | /// Return the memory representation of this integer as a byte array in big-endian byte order. |
287 | | #[inline] |
288 | 0 | pub const fn to_be_bytes(self) -> [u8; 32] { |
289 | 0 | let low = self.low.to_be_bytes(); |
290 | 0 | let high = self.high.to_be_bytes(); |
291 | 0 | let mut t = [0; 32]; |
292 | 0 | let mut i = 0; |
293 | 0 | while i != 16 { |
294 | 0 | t[i] = high[i]; |
295 | 0 | t[i + 16] = low[i]; |
296 | 0 | i += 1; |
297 | 0 | } |
298 | 0 | t |
299 | 0 | } |
300 | | |
301 | | /// Create an i256 from the provided [`BigInt`] returning a bool indicating |
302 | | /// if overflow occurred |
303 | 0 | fn from_bigint_with_overflow(v: BigInt) -> (Self, bool) { |
304 | 0 | let v_bytes = v.to_signed_bytes_le(); |
305 | 0 | match v_bytes.len().cmp(&32) { |
306 | | Ordering::Less => { |
307 | 0 | let mut bytes = if num::Signed::is_negative(&v) { |
308 | 0 | [255_u8; 32] |
309 | | } else { |
310 | 0 | [0; 32] |
311 | | }; |
312 | 0 | bytes[0..v_bytes.len()].copy_from_slice(&v_bytes[..v_bytes.len()]); |
313 | 0 | (Self::from_le_bytes(bytes), false) |
314 | | } |
315 | 0 | Ordering::Equal => (Self::from_le_bytes(v_bytes.try_into().unwrap()), false), |
316 | 0 | Ordering::Greater => (Self::from_le_bytes(v_bytes[..32].try_into().unwrap()), true), |
317 | | } |
318 | 0 | } |
319 | | |
320 | | /// Computes the absolute value of this i256 |
321 | | #[inline] |
322 | 0 | pub fn wrapping_abs(self) -> Self { |
323 | | // -1 if negative, otherwise 0 |
324 | 0 | let sa = self.high >> 127; |
325 | 0 | let sa = Self::from_parts(sa as u128, sa); |
326 | | |
327 | | // Inverted if negative |
328 | 0 | Self::from_parts(self.low ^ sa.low, self.high ^ sa.high).wrapping_sub(sa) |
329 | 0 | } |
330 | | |
331 | | /// Computes the absolute value of this i256 returning `None` if `Self == Self::MIN` |
332 | | #[inline] |
333 | 0 | pub fn checked_abs(self) -> Option<Self> { |
334 | 0 | (self != Self::MIN).then(|| self.wrapping_abs()) |
335 | 0 | } |
336 | | |
337 | | /// Negates this i256 |
338 | | #[inline] |
339 | 0 | pub fn wrapping_neg(self) -> Self { |
340 | 0 | Self::from_parts(!self.low, !self.high).wrapping_add(i256::ONE) |
341 | 0 | } |
342 | | |
343 | | /// Negates this i256 returning `None` if `Self == Self::MIN` |
344 | | #[inline] |
345 | 0 | pub fn checked_neg(self) -> Option<Self> { |
346 | 0 | (self != Self::MIN).then(|| self.wrapping_neg()) |
347 | 0 | } |
348 | | |
349 | | /// Performs wrapping addition |
350 | | #[inline] |
351 | 0 | pub fn wrapping_add(self, other: Self) -> Self { |
352 | 0 | let (low, carry) = self.low.overflowing_add(other.low); |
353 | 0 | let high = self.high.wrapping_add(other.high).wrapping_add(carry as _); |
354 | 0 | Self { low, high } |
355 | 0 | } |
356 | | |
357 | | /// Performs checked addition |
358 | | #[inline] |
359 | 0 | pub fn checked_add(self, other: Self) -> Option<Self> { |
360 | 0 | let r = self.wrapping_add(other); |
361 | 0 | ((other.is_negative() && r < self) || (!other.is_negative() && r >= self)).then_some(r) |
362 | 0 | } |
363 | | |
364 | | /// Performs wrapping subtraction |
365 | | #[inline] |
366 | 0 | pub fn wrapping_sub(self, other: Self) -> Self { |
367 | 0 | let (low, carry) = self.low.overflowing_sub(other.low); |
368 | 0 | let high = self.high.wrapping_sub(other.high).wrapping_sub(carry as _); |
369 | 0 | Self { low, high } |
370 | 0 | } |
371 | | |
372 | | /// Performs checked subtraction |
373 | | #[inline] |
374 | 0 | pub fn checked_sub(self, other: Self) -> Option<Self> { |
375 | 0 | let r = self.wrapping_sub(other); |
376 | 0 | ((other.is_negative() && r > self) || (!other.is_negative() && r <= self)).then_some(r) |
377 | 0 | } |
378 | | |
379 | | /// Performs wrapping multiplication |
380 | | #[inline] |
381 | 0 | pub fn wrapping_mul(self, other: Self) -> Self { |
382 | 0 | let (low, high) = mulx(self.low, other.low); |
383 | | |
384 | | // Compute the high multiples, only impacting the high 128-bits |
385 | 0 | let hl = self.high.wrapping_mul(other.low as i128); |
386 | 0 | let lh = (self.low as i128).wrapping_mul(other.high); |
387 | | |
388 | 0 | Self { |
389 | 0 | low, |
390 | 0 | high: (high as i128).wrapping_add(hl).wrapping_add(lh), |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | /// Performs checked multiplication |
395 | | #[inline] |
396 | 0 | pub fn checked_mul(self, other: Self) -> Option<Self> { |
397 | 0 | if self == i256::ZERO || other == i256::ZERO { |
398 | 0 | return Some(i256::ZERO); |
399 | 0 | } |
400 | | |
401 | | // Shift sign bit down to construct mask of all set bits if negative |
402 | 0 | let l_sa = self.high >> 127; |
403 | 0 | let r_sa = other.high >> 127; |
404 | 0 | let out_sa = (l_sa ^ r_sa) as u128; |
405 | | |
406 | | // Compute absolute values |
407 | 0 | let l_abs = self.wrapping_abs(); |
408 | 0 | let r_abs = other.wrapping_abs(); |
409 | | |
410 | | // Overflow if both high parts are non-zero |
411 | 0 | if l_abs.high != 0 && r_abs.high != 0 { |
412 | 0 | return None; |
413 | 0 | } |
414 | | |
415 | | // Perform checked multiplication on absolute values |
416 | 0 | let (low, high) = mulx(l_abs.low, r_abs.low); |
417 | | |
418 | | // Compute the high multiples, only impacting the high 128-bits |
419 | 0 | let hl = (l_abs.high as u128).checked_mul(r_abs.low)?; |
420 | 0 | let lh = l_abs.low.checked_mul(r_abs.high as u128)?; |
421 | | |
422 | 0 | let high = high.checked_add(hl)?.checked_add(lh)?; |
423 | | |
424 | | // Reverse absolute value, if necessary |
425 | 0 | let (low, c) = (low ^ out_sa).overflowing_sub(out_sa); |
426 | 0 | let high = (high ^ out_sa).wrapping_sub(out_sa).wrapping_sub(c as u128) as i128; |
427 | | |
428 | | // Check for overflow in final conversion |
429 | 0 | (high.is_negative() == (self.is_negative() ^ other.is_negative())) |
430 | 0 | .then_some(Self { low, high }) |
431 | 0 | } |
432 | | |
433 | | /// Division operation, returns (quotient, remainder). |
434 | | /// This basically implements [Long division]: `<https://en.wikipedia.org/wiki/Division_algorithm>` |
435 | | #[inline] |
436 | 0 | fn div_rem(self, other: Self) -> Result<(Self, Self), DivRemError> { |
437 | 0 | if other == Self::ZERO { |
438 | 0 | return Err(DivRemError::DivideByZero); |
439 | 0 | } |
440 | 0 | if other == Self::MINUS_ONE && self == Self::MIN { |
441 | 0 | return Err(DivRemError::DivideOverflow); |
442 | 0 | } |
443 | | |
444 | 0 | let a = self.wrapping_abs(); |
445 | 0 | let b = other.wrapping_abs(); |
446 | | |
447 | 0 | let (div, rem) = div_rem(&a.as_digits(), &b.as_digits()); |
448 | 0 | let div = Self::from_digits(div); |
449 | 0 | let rem = Self::from_digits(rem); |
450 | | |
451 | | Ok(( |
452 | 0 | if self.is_negative() == other.is_negative() { |
453 | 0 | div |
454 | | } else { |
455 | 0 | div.wrapping_neg() |
456 | | }, |
457 | 0 | if self.is_negative() { |
458 | 0 | rem.wrapping_neg() |
459 | | } else { |
460 | 0 | rem |
461 | | }, |
462 | | )) |
463 | 0 | } |
464 | | |
465 | | /// Interpret this [`i256`] as 4 `u64` digits, least significant first |
466 | 0 | fn as_digits(self) -> [u64; 4] { |
467 | 0 | [ |
468 | 0 | self.low as u64, |
469 | 0 | (self.low >> 64) as u64, |
470 | 0 | self.high as u64, |
471 | 0 | (self.high as u128 >> 64) as u64, |
472 | 0 | ] |
473 | 0 | } |
474 | | |
475 | | /// Interpret 4 `u64` digits, least significant first, as a [`i256`] |
476 | 0 | fn from_digits(digits: [u64; 4]) -> Self { |
477 | 0 | Self::from_parts( |
478 | 0 | digits[0] as u128 | ((digits[1] as u128) << 64), |
479 | 0 | digits[2] as i128 | ((digits[3] as i128) << 64), |
480 | | ) |
481 | 0 | } |
482 | | |
483 | | /// Performs wrapping division |
484 | | #[inline] |
485 | 0 | pub fn wrapping_div(self, other: Self) -> Self { |
486 | 0 | match self.div_rem(other) { |
487 | 0 | Ok((v, _)) => v, |
488 | 0 | Err(DivRemError::DivideByZero) => panic!("attempt to divide by zero"), |
489 | 0 | Err(_) => Self::MIN, |
490 | | } |
491 | 0 | } |
492 | | |
493 | | /// Performs checked division |
494 | | #[inline] |
495 | 0 | pub fn checked_div(self, other: Self) -> Option<Self> { |
496 | 0 | self.div_rem(other).map(|(v, _)| v).ok() |
497 | 0 | } |
498 | | |
499 | | /// Performs wrapping remainder |
500 | | #[inline] |
501 | 0 | pub fn wrapping_rem(self, other: Self) -> Self { |
502 | 0 | match self.div_rem(other) { |
503 | 0 | Ok((_, v)) => v, |
504 | 0 | Err(DivRemError::DivideByZero) => panic!("attempt to divide by zero"), |
505 | 0 | Err(_) => Self::ZERO, |
506 | | } |
507 | 0 | } |
508 | | |
509 | | /// Performs checked remainder |
510 | | #[inline] |
511 | 0 | pub fn checked_rem(self, other: Self) -> Option<Self> { |
512 | 0 | self.div_rem(other).map(|(_, v)| v).ok() |
513 | 0 | } |
514 | | |
515 | | /// Performs checked exponentiation |
516 | | #[inline] |
517 | 0 | pub fn checked_pow(self, mut exp: u32) -> Option<Self> { |
518 | 0 | if exp == 0 { |
519 | 0 | return Some(i256::from_i128(1)); |
520 | 0 | } |
521 | | |
522 | 0 | let mut base = self; |
523 | 0 | let mut acc: Self = i256::from_i128(1); |
524 | | |
525 | 0 | while exp > 1 { |
526 | 0 | if (exp & 1) == 1 { |
527 | 0 | acc = acc.checked_mul(base)?; |
528 | 0 | } |
529 | 0 | exp /= 2; |
530 | 0 | base = base.checked_mul(base)?; |
531 | | } |
532 | | // since exp!=0, finally the exp must be 1. |
533 | | // Deal with the final bit of the exponent separately, since |
534 | | // squaring the base afterwards is not necessary and may cause a |
535 | | // needless overflow. |
536 | 0 | acc.checked_mul(base) |
537 | 0 | } |
538 | | |
539 | | /// Performs wrapping exponentiation |
540 | | #[inline] |
541 | 0 | pub fn wrapping_pow(self, mut exp: u32) -> Self { |
542 | 0 | if exp == 0 { |
543 | 0 | return i256::from_i128(1); |
544 | 0 | } |
545 | | |
546 | 0 | let mut base = self; |
547 | 0 | let mut acc: Self = i256::from_i128(1); |
548 | | |
549 | 0 | while exp > 1 { |
550 | 0 | if (exp & 1) == 1 { |
551 | 0 | acc = acc.wrapping_mul(base); |
552 | 0 | } |
553 | 0 | exp /= 2; |
554 | 0 | base = base.wrapping_mul(base); |
555 | | } |
556 | | |
557 | | // since exp!=0, finally the exp must be 1. |
558 | | // Deal with the final bit of the exponent separately, since |
559 | | // squaring the base afterwards is not necessary and may cause a |
560 | | // needless overflow. |
561 | 0 | acc.wrapping_mul(base) |
562 | 0 | } |
563 | | |
564 | | /// Returns a number [`i256`] representing sign of this [`i256`]. |
565 | | /// |
566 | | /// 0 if the number is zero |
567 | | /// 1 if the number is positive |
568 | | /// -1 if the number is negative |
569 | 0 | pub const fn signum(self) -> Self { |
570 | 0 | if self.is_positive() { |
571 | 0 | i256::ONE |
572 | 0 | } else if self.is_negative() { |
573 | 0 | i256::MINUS_ONE |
574 | | } else { |
575 | 0 | i256::ZERO |
576 | | } |
577 | 0 | } |
578 | | |
579 | | /// Returns `true` if this [`i256`] is negative |
580 | | #[inline] |
581 | 0 | pub const fn is_negative(self) -> bool { |
582 | 0 | self.high.is_negative() |
583 | 0 | } |
584 | | |
585 | | /// Returns `true` if this [`i256`] is positive |
586 | 0 | pub const fn is_positive(self) -> bool { |
587 | 0 | self.high.is_positive() || self.high == 0 && self.low != 0 |
588 | 0 | } |
589 | | } |
590 | | |
591 | | /// Temporary workaround due to lack of stable const array slicing |
592 | | /// See <https://github.com/rust-lang/rust/issues/90091> |
593 | 2 | const fn split_array<const N: usize, const M: usize>(vals: [u8; N]) -> ([u8; M], [u8; M]) { |
594 | 2 | let mut a = [0; M]; |
595 | 2 | let mut b = [0; M]; |
596 | 2 | let mut i = 0; |
597 | 34 | while i != M { |
598 | 32 | a[i] = vals[i]; |
599 | 32 | b[i] = vals[i + M]; |
600 | 32 | i += 1; |
601 | 32 | } |
602 | 2 | (a, b) |
603 | 2 | } |
604 | | |
605 | | /// Performs an unsigned multiplication of `a * b` returning a tuple of |
606 | | /// `(low, high)` where `low` contains the lower 128-bits of the result |
607 | | /// and `high` the higher 128-bits |
608 | | /// |
609 | | /// This mirrors the x86 mulx instruction but for 128-bit types |
610 | | #[inline] |
611 | 0 | fn mulx(a: u128, b: u128) -> (u128, u128) { |
612 | 0 | let split = |a: u128| (a & (u64::MAX as u128), a >> 64); |
613 | | |
614 | | const MASK: u128 = u64::MAX as _; |
615 | | |
616 | 0 | let (a_low, a_high) = split(a); |
617 | 0 | let (b_low, b_high) = split(b); |
618 | | |
619 | | // Carry stores the upper 64-bits of low and lower 64-bits of high |
620 | 0 | let (mut low, mut carry) = split(a_low * b_low); |
621 | 0 | carry += a_high * b_low; |
622 | | |
623 | | // Update low and high with corresponding parts of carry |
624 | 0 | low += carry << 64; |
625 | 0 | let mut high = carry >> 64; |
626 | | |
627 | | // Update carry with overflow from low |
628 | 0 | carry = low >> 64; |
629 | 0 | low &= MASK; |
630 | | |
631 | | // Perform multiply including overflow from low |
632 | 0 | carry += b_high * a_low; |
633 | | |
634 | | // Update low and high with values from carry |
635 | 0 | low += carry << 64; |
636 | 0 | high += carry >> 64; |
637 | | |
638 | | // Perform 4th multiplication |
639 | 0 | high += a_high * b_high; |
640 | | |
641 | 0 | (low, high) |
642 | 0 | } |
643 | | |
644 | | derive_arith!( |
645 | | i256, |
646 | | Add, |
647 | | AddAssign, |
648 | | add, |
649 | | add_assign, |
650 | | wrapping_add, |
651 | | checked_add |
652 | | ); |
653 | | derive_arith!( |
654 | | i256, |
655 | | Sub, |
656 | | SubAssign, |
657 | | sub, |
658 | | sub_assign, |
659 | | wrapping_sub, |
660 | | checked_sub |
661 | | ); |
662 | | derive_arith!( |
663 | | i256, |
664 | | Mul, |
665 | | MulAssign, |
666 | | mul, |
667 | | mul_assign, |
668 | | wrapping_mul, |
669 | | checked_mul |
670 | | ); |
671 | | derive_arith!( |
672 | | i256, |
673 | | Div, |
674 | | DivAssign, |
675 | | div, |
676 | | div_assign, |
677 | | wrapping_div, |
678 | | checked_div |
679 | | ); |
680 | | derive_arith!( |
681 | | i256, |
682 | | Rem, |
683 | | RemAssign, |
684 | | rem, |
685 | | rem_assign, |
686 | | wrapping_rem, |
687 | | checked_rem |
688 | | ); |
689 | | |
690 | | impl Neg for i256 { |
691 | | type Output = i256; |
692 | | |
693 | | #[cfg(debug_assertions)] |
694 | 0 | fn neg(self) -> Self::Output { |
695 | 0 | self.checked_neg().expect("i256 overflow") |
696 | 0 | } |
697 | | |
698 | | #[cfg(not(debug_assertions))] |
699 | | fn neg(self) -> Self::Output { |
700 | | self.wrapping_neg() |
701 | | } |
702 | | } |
703 | | |
704 | | impl BitAnd for i256 { |
705 | | type Output = i256; |
706 | | |
707 | | #[inline] |
708 | | fn bitand(self, rhs: Self) -> Self::Output { |
709 | | Self { |
710 | | low: self.low & rhs.low, |
711 | | high: self.high & rhs.high, |
712 | | } |
713 | | } |
714 | | } |
715 | | |
716 | | impl BitOr for i256 { |
717 | | type Output = i256; |
718 | | |
719 | | #[inline] |
720 | | fn bitor(self, rhs: Self) -> Self::Output { |
721 | | Self { |
722 | | low: self.low | rhs.low, |
723 | | high: self.high | rhs.high, |
724 | | } |
725 | | } |
726 | | } |
727 | | |
728 | | impl BitXor for i256 { |
729 | | type Output = i256; |
730 | | |
731 | | #[inline] |
732 | | fn bitxor(self, rhs: Self) -> Self::Output { |
733 | | Self { |
734 | | low: self.low ^ rhs.low, |
735 | | high: self.high ^ rhs.high, |
736 | | } |
737 | | } |
738 | | } |
739 | | |
740 | | impl Shl<u8> for i256 { |
741 | | type Output = i256; |
742 | | |
743 | | #[inline] |
744 | | fn shl(self, rhs: u8) -> Self::Output { |
745 | | if rhs == 0 { |
746 | | self |
747 | | } else if rhs < 128 { |
748 | | Self { |
749 | | high: (self.high << rhs) | (self.low >> (128 - rhs)) as i128, |
750 | | low: self.low << rhs, |
751 | | } |
752 | | } else { |
753 | | Self { |
754 | | high: (self.low << (rhs - 128)) as i128, |
755 | | low: 0, |
756 | | } |
757 | | } |
758 | | } |
759 | | } |
760 | | |
761 | | impl Shr<u8> for i256 { |
762 | | type Output = i256; |
763 | | |
764 | | #[inline] |
765 | | fn shr(self, rhs: u8) -> Self::Output { |
766 | | if rhs == 0 { |
767 | | self |
768 | | } else if rhs < 128 { |
769 | | Self { |
770 | | high: self.high >> rhs, |
771 | | low: (self.low >> rhs) | ((self.high as u128) << (128 - rhs)), |
772 | | } |
773 | | } else { |
774 | | Self { |
775 | | high: self.high >> 127, |
776 | | low: (self.high >> (rhs - 128)) as u128, |
777 | | } |
778 | | } |
779 | | } |
780 | | } |
781 | | |
782 | | macro_rules! define_as_primitive { |
783 | | ($native_ty:ty) => { |
784 | | impl AsPrimitive<i256> for $native_ty { |
785 | 0 | fn as_(self) -> i256 { |
786 | 0 | i256::from_i128(self as i128) |
787 | 0 | } |
788 | | } |
789 | | }; |
790 | | } |
791 | | |
792 | | define_as_primitive!(i8); |
793 | | define_as_primitive!(i16); |
794 | | define_as_primitive!(i32); |
795 | | define_as_primitive!(i64); |
796 | | define_as_primitive!(u8); |
797 | | define_as_primitive!(u16); |
798 | | define_as_primitive!(u32); |
799 | | define_as_primitive!(u64); |
800 | | |
801 | | impl ToPrimitive for i256 { |
802 | 0 | fn to_i64(&self) -> Option<i64> { |
803 | 0 | let as_i128 = self.low as i128; |
804 | | |
805 | 0 | let high_negative = self.high < 0; |
806 | 0 | let low_negative = as_i128 < 0; |
807 | 0 | let high_valid = self.high == -1 || self.high == 0; |
808 | | |
809 | 0 | if high_negative == low_negative && high_valid { |
810 | 0 | let (low_bytes, high_bytes) = split_array(u128::to_le_bytes(self.low)); |
811 | 0 | let high = i64::from_le_bytes(high_bytes); |
812 | 0 | let low = i64::from_le_bytes(low_bytes); |
813 | | |
814 | 0 | let high_negative = high < 0; |
815 | 0 | let low_negative = low < 0; |
816 | 0 | let high_valid = self.high == -1 || self.high == 0; |
817 | | |
818 | 0 | (high_negative == low_negative && high_valid).then_some(low) |
819 | | } else { |
820 | 0 | None |
821 | | } |
822 | 0 | } |
823 | | |
824 | 0 | fn to_f64(&self) -> Option<f64> { |
825 | 0 | let mag = if let Some(u) = self.checked_abs() { |
826 | 0 | let (low, high) = u.to_parts(); |
827 | 0 | (high as f64) * 2_f64.powi(128) + (low as f64) |
828 | | } else { |
829 | | // self == MIN |
830 | 0 | 2_f64.powi(255) |
831 | | }; |
832 | 0 | if *self < i256::ZERO { |
833 | 0 | Some(-mag) |
834 | | } else { |
835 | 0 | Some(mag) |
836 | | } |
837 | 0 | } |
838 | 0 | fn to_u64(&self) -> Option<u64> { |
839 | 0 | let as_i128 = self.low as i128; |
840 | | |
841 | 0 | let high_negative = self.high < 0; |
842 | 0 | let low_negative = as_i128 < 0; |
843 | 0 | let high_valid = self.high == -1 || self.high == 0; |
844 | | |
845 | 0 | if high_negative == low_negative && high_valid { |
846 | 0 | self.low.to_u64() |
847 | | } else { |
848 | 0 | None |
849 | | } |
850 | 0 | } |
851 | | } |
852 | | |
853 | | #[cfg(all(test, not(miri)))] // llvm.x86.subborrow.64 not supported by MIRI |
854 | | mod tests { |
855 | | use super::*; |
856 | | use num::Signed; |
857 | | use rand::{rng, Rng}; |
858 | | |
859 | | #[test] |
860 | | fn test_signed_cmp() { |
861 | | let a = i256::from_parts(i128::MAX as u128, 12); |
862 | | let b = i256::from_parts(i128::MIN as u128, 12); |
863 | | assert!(a < b); |
864 | | |
865 | | let a = i256::from_parts(i128::MAX as u128, 12); |
866 | | let b = i256::from_parts(i128::MIN as u128, -12); |
867 | | assert!(a > b); |
868 | | } |
869 | | |
870 | | #[test] |
871 | | fn test_to_i128() { |
872 | | let vals = [ |
873 | | BigInt::from_i128(-1).unwrap(), |
874 | | BigInt::from_i128(i128::MAX).unwrap(), |
875 | | BigInt::from_i128(i128::MIN).unwrap(), |
876 | | BigInt::from_u128(u128::MIN).unwrap(), |
877 | | BigInt::from_u128(u128::MAX).unwrap(), |
878 | | ]; |
879 | | |
880 | | for v in vals { |
881 | | let (t, overflow) = i256::from_bigint_with_overflow(v.clone()); |
882 | | assert!(!overflow); |
883 | | assert_eq!(t.to_i128(), v.to_i128(), "{v} vs {t}"); |
884 | | } |
885 | | } |
886 | | |
887 | | /// Tests operations against the two provided [`i256`] |
888 | | fn test_ops(il: i256, ir: i256) { |
889 | | let bl = BigInt::from_signed_bytes_le(&il.to_le_bytes()); |
890 | | let br = BigInt::from_signed_bytes_le(&ir.to_le_bytes()); |
891 | | |
892 | | // Comparison |
893 | | assert_eq!(il.cmp(&ir), bl.cmp(&br), "{bl} cmp {br}"); |
894 | | |
895 | | // Conversions |
896 | | assert_eq!(i256::from_le_bytes(il.to_le_bytes()), il); |
897 | | assert_eq!(i256::from_be_bytes(il.to_be_bytes()), il); |
898 | | assert_eq!(i256::from_le_bytes(ir.to_le_bytes()), ir); |
899 | | assert_eq!(i256::from_be_bytes(ir.to_be_bytes()), ir); |
900 | | |
901 | | // To i128 |
902 | | assert_eq!(il.to_i128(), bl.to_i128(), "{bl}"); |
903 | | assert_eq!(ir.to_i128(), br.to_i128(), "{br}"); |
904 | | |
905 | | // Absolute value |
906 | | let (abs, overflow) = i256::from_bigint_with_overflow(bl.abs()); |
907 | | assert_eq!(il.wrapping_abs(), abs); |
908 | | assert_eq!(il.checked_abs().is_none(), overflow); |
909 | | |
910 | | let (abs, overflow) = i256::from_bigint_with_overflow(br.abs()); |
911 | | assert_eq!(ir.wrapping_abs(), abs); |
912 | | assert_eq!(ir.checked_abs().is_none(), overflow); |
913 | | |
914 | | // Negation |
915 | | let (neg, overflow) = i256::from_bigint_with_overflow(bl.clone().neg()); |
916 | | assert_eq!(il.wrapping_neg(), neg); |
917 | | assert_eq!(il.checked_neg().is_none(), overflow); |
918 | | |
919 | | // Negation |
920 | | let (neg, overflow) = i256::from_bigint_with_overflow(br.clone().neg()); |
921 | | assert_eq!(ir.wrapping_neg(), neg); |
922 | | assert_eq!(ir.checked_neg().is_none(), overflow); |
923 | | |
924 | | // Addition |
925 | | let actual = il.wrapping_add(ir); |
926 | | let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() + br.clone()); |
927 | | assert_eq!(actual, expected); |
928 | | |
929 | | let checked = il.checked_add(ir); |
930 | | match overflow { |
931 | | true => assert!(checked.is_none()), |
932 | | false => assert_eq!(checked, Some(actual)), |
933 | | } |
934 | | |
935 | | // Subtraction |
936 | | let actual = il.wrapping_sub(ir); |
937 | | let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() - br.clone()); |
938 | | assert_eq!(actual.to_string(), expected.to_string()); |
939 | | |
940 | | let checked = il.checked_sub(ir); |
941 | | match overflow { |
942 | | true => assert!(checked.is_none()), |
943 | | false => assert_eq!(checked, Some(actual), "{bl} - {br} = {expected}"), |
944 | | } |
945 | | |
946 | | // Multiplication |
947 | | let actual = il.wrapping_mul(ir); |
948 | | let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() * br.clone()); |
949 | | assert_eq!(actual.to_string(), expected.to_string()); |
950 | | |
951 | | let checked = il.checked_mul(ir); |
952 | | match overflow { |
953 | | true => assert!( |
954 | | checked.is_none(), |
955 | | "{il} * {ir} = {actual} vs {bl} * {br} = {expected}" |
956 | | ), |
957 | | false => assert_eq!( |
958 | | checked, |
959 | | Some(actual), |
960 | | "{il} * {ir} = {actual} vs {bl} * {br} = {expected}" |
961 | | ), |
962 | | } |
963 | | |
964 | | // Division |
965 | | if ir != i256::ZERO { |
966 | | let actual = il.wrapping_div(ir); |
967 | | let expected = bl.clone() / br.clone(); |
968 | | let checked = il.checked_div(ir); |
969 | | |
970 | | if ir == i256::MINUS_ONE && il == i256::MIN { |
971 | | // BigInt produces an integer over i256::MAX |
972 | | assert_eq!(actual, i256::MIN); |
973 | | assert!(checked.is_none()); |
974 | | } else { |
975 | | assert_eq!(actual.to_string(), expected.to_string()); |
976 | | assert_eq!(checked.unwrap().to_string(), expected.to_string()); |
977 | | } |
978 | | } else { |
979 | | // `wrapping_div` panics on division by zero |
980 | | assert!(il.checked_div(ir).is_none()); |
981 | | } |
982 | | |
983 | | // Remainder |
984 | | if ir != i256::ZERO { |
985 | | let actual = il.wrapping_rem(ir); |
986 | | let expected = bl.clone() % br.clone(); |
987 | | let checked = il.checked_rem(ir); |
988 | | |
989 | | assert_eq!(actual.to_string(), expected.to_string(), "{il} % {ir}"); |
990 | | |
991 | | if ir == i256::MINUS_ONE && il == i256::MIN { |
992 | | assert!(checked.is_none()); |
993 | | } else { |
994 | | assert_eq!(checked.unwrap().to_string(), expected.to_string()); |
995 | | } |
996 | | } else { |
997 | | // `wrapping_rem` panics on division by zero |
998 | | assert!(il.checked_rem(ir).is_none()); |
999 | | } |
1000 | | |
1001 | | // Exponentiation |
1002 | | for exp in vec![0, 1, 2, 3, 8, 100].into_iter() { |
1003 | | let actual = il.wrapping_pow(exp); |
1004 | | let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone().pow(exp)); |
1005 | | assert_eq!(actual.to_string(), expected.to_string()); |
1006 | | |
1007 | | let checked = il.checked_pow(exp); |
1008 | | match overflow { |
1009 | | true => assert!( |
1010 | | checked.is_none(), |
1011 | | "{il} ^ {exp} = {actual} vs {bl} * {exp} = {expected}" |
1012 | | ), |
1013 | | false => assert_eq!( |
1014 | | checked, |
1015 | | Some(actual), |
1016 | | "{il} ^ {exp} = {actual} vs {bl} ^ {exp} = {expected}" |
1017 | | ), |
1018 | | } |
1019 | | } |
1020 | | |
1021 | | // Bit operations |
1022 | | let actual = il & ir; |
1023 | | let (expected, _) = i256::from_bigint_with_overflow(bl.clone() & br.clone()); |
1024 | | assert_eq!(actual.to_string(), expected.to_string()); |
1025 | | |
1026 | | let actual = il | ir; |
1027 | | let (expected, _) = i256::from_bigint_with_overflow(bl.clone() | br.clone()); |
1028 | | assert_eq!(actual.to_string(), expected.to_string()); |
1029 | | |
1030 | | let actual = il ^ ir; |
1031 | | let (expected, _) = i256::from_bigint_with_overflow(bl.clone() ^ br); |
1032 | | assert_eq!(actual.to_string(), expected.to_string()); |
1033 | | |
1034 | | for shift in [0_u8, 1, 4, 126, 128, 129, 254, 255] { |
1035 | | let actual = il << shift; |
1036 | | let (expected, _) = i256::from_bigint_with_overflow(bl.clone() << shift); |
1037 | | assert_eq!(actual.to_string(), expected.to_string()); |
1038 | | |
1039 | | let actual = il >> shift; |
1040 | | let (expected, _) = i256::from_bigint_with_overflow(bl.clone() >> shift); |
1041 | | assert_eq!(actual.to_string(), expected.to_string()); |
1042 | | } |
1043 | | } |
1044 | | |
1045 | | #[test] |
1046 | | fn test_i256() { |
1047 | | let candidates = [ |
1048 | | i256::ZERO, |
1049 | | i256::ONE, |
1050 | | i256::MINUS_ONE, |
1051 | | i256::from_i128(2), |
1052 | | i256::from_i128(-2), |
1053 | | i256::from_parts(u128::MAX, 1), |
1054 | | i256::from_parts(u128::MAX, -1), |
1055 | | i256::from_parts(0, 1), |
1056 | | i256::from_parts(0, -1), |
1057 | | i256::from_parts(1, -1), |
1058 | | i256::from_parts(1, 1), |
1059 | | i256::from_parts(0, i128::MAX), |
1060 | | i256::from_parts(0, i128::MIN), |
1061 | | i256::from_parts(1, i128::MAX), |
1062 | | i256::from_parts(1, i128::MIN), |
1063 | | i256::from_parts(u128::MAX, i128::MIN), |
1064 | | i256::from_parts(100, 32), |
1065 | | i256::MIN, |
1066 | | i256::MAX, |
1067 | | i256::MIN >> 1, |
1068 | | i256::MAX >> 1, |
1069 | | i256::ONE << 127, |
1070 | | i256::ONE << 128, |
1071 | | i256::ONE << 129, |
1072 | | i256::MINUS_ONE << 127, |
1073 | | i256::MINUS_ONE << 128, |
1074 | | i256::MINUS_ONE << 129, |
1075 | | ]; |
1076 | | |
1077 | | for il in candidates { |
1078 | | for ir in candidates { |
1079 | | test_ops(il, ir) |
1080 | | } |
1081 | | } |
1082 | | } |
1083 | | |
1084 | | #[test] |
1085 | | fn test_signed_ops() { |
1086 | | // signum |
1087 | | assert_eq!(i256::from_i128(1).signum(), i256::ONE); |
1088 | | assert_eq!(i256::from_i128(0).signum(), i256::ZERO); |
1089 | | assert_eq!(i256::from_i128(-0).signum(), i256::ZERO); |
1090 | | assert_eq!(i256::from_i128(-1).signum(), i256::MINUS_ONE); |
1091 | | |
1092 | | // is_positive |
1093 | | assert!(i256::from_i128(1).is_positive()); |
1094 | | assert!(!i256::from_i128(0).is_positive()); |
1095 | | assert!(!i256::from_i128(-0).is_positive()); |
1096 | | assert!(!i256::from_i128(-1).is_positive()); |
1097 | | |
1098 | | // is_negative |
1099 | | assert!(!i256::from_i128(1).is_negative()); |
1100 | | assert!(!i256::from_i128(0).is_negative()); |
1101 | | assert!(!i256::from_i128(-0).is_negative()); |
1102 | | assert!(i256::from_i128(-1).is_negative()); |
1103 | | } |
1104 | | |
1105 | | #[test] |
1106 | | #[cfg_attr(miri, ignore)] |
1107 | | fn test_i256_fuzz() { |
1108 | | let mut rng = rng(); |
1109 | | |
1110 | | for _ in 0..1000 { |
1111 | | let mut l = [0_u8; 32]; |
1112 | | let len = rng.random_range(0..32); |
1113 | | l.iter_mut().take(len).for_each(|x| *x = rng.random()); |
1114 | | |
1115 | | let mut r = [0_u8; 32]; |
1116 | | let len = rng.random_range(0..32); |
1117 | | r.iter_mut().take(len).for_each(|x| *x = rng.random()); |
1118 | | |
1119 | | test_ops(i256::from_le_bytes(l), i256::from_le_bytes(r)) |
1120 | | } |
1121 | | } |
1122 | | |
1123 | | #[test] |
1124 | | fn test_i256_to_primitive() { |
1125 | | let a = i256::MAX; |
1126 | | assert!(a.to_i64().is_none()); |
1127 | | assert!(a.to_u64().is_none()); |
1128 | | |
1129 | | let a = i256::from_i128(i128::MAX); |
1130 | | assert!(a.to_i64().is_none()); |
1131 | | assert!(a.to_u64().is_none()); |
1132 | | |
1133 | | let a = i256::from_i128(i64::MAX as i128); |
1134 | | assert_eq!(a.to_i64().unwrap(), i64::MAX); |
1135 | | assert_eq!(a.to_u64().unwrap(), i64::MAX as u64); |
1136 | | |
1137 | | let a = i256::from_i128(i64::MAX as i128 + 1); |
1138 | | assert!(a.to_i64().is_none()); |
1139 | | assert_eq!(a.to_u64().unwrap(), i64::MAX as u64 + 1); |
1140 | | |
1141 | | let a = i256::MIN; |
1142 | | assert!(a.to_i64().is_none()); |
1143 | | assert!(a.to_u64().is_none()); |
1144 | | |
1145 | | let a = i256::from_i128(i128::MIN); |
1146 | | assert!(a.to_i64().is_none()); |
1147 | | assert!(a.to_u64().is_none()); |
1148 | | |
1149 | | let a = i256::from_i128(i64::MIN as i128); |
1150 | | assert_eq!(a.to_i64().unwrap(), i64::MIN); |
1151 | | assert!(a.to_u64().is_none()); |
1152 | | |
1153 | | let a = i256::from_i128(i64::MIN as i128 - 1); |
1154 | | assert!(a.to_i64().is_none()); |
1155 | | assert!(a.to_u64().is_none()); |
1156 | | } |
1157 | | |
1158 | | #[test] |
1159 | | fn test_i256_as_i128() { |
1160 | | let a = i256::from_i128(i128::MAX).wrapping_add(i256::from_i128(1)); |
1161 | | let i128 = a.as_i128(); |
1162 | | assert_eq!(i128, i128::MIN); |
1163 | | |
1164 | | let a = i256::from_i128(i128::MAX).wrapping_add(i256::from_i128(2)); |
1165 | | let i128 = a.as_i128(); |
1166 | | assert_eq!(i128, i128::MIN + 1); |
1167 | | |
1168 | | let a = i256::from_i128(i128::MIN).wrapping_sub(i256::from_i128(1)); |
1169 | | let i128 = a.as_i128(); |
1170 | | assert_eq!(i128, i128::MAX); |
1171 | | |
1172 | | let a = i256::from_i128(i128::MIN).wrapping_sub(i256::from_i128(2)); |
1173 | | let i128 = a.as_i128(); |
1174 | | assert_eq!(i128, i128::MAX - 1); |
1175 | | } |
1176 | | |
1177 | | #[test] |
1178 | | fn test_string_roundtrip() { |
1179 | | let roundtrip_cases = [ |
1180 | | i256::ZERO, |
1181 | | i256::ONE, |
1182 | | i256::MINUS_ONE, |
1183 | | i256::from_i128(123456789), |
1184 | | i256::from_i128(-123456789), |
1185 | | i256::from_i128(i128::MIN), |
1186 | | i256::from_i128(i128::MAX), |
1187 | | i256::MIN, |
1188 | | i256::MAX, |
1189 | | ]; |
1190 | | for case in roundtrip_cases { |
1191 | | let formatted = case.to_string(); |
1192 | | let back: i256 = formatted.parse().unwrap(); |
1193 | | assert_eq!(case, back); |
1194 | | } |
1195 | | } |
1196 | | |
1197 | | #[test] |
1198 | | fn test_from_string() { |
1199 | | let cases = [ |
1200 | | ( |
1201 | | "000000000000000000000000000000000000000011", |
1202 | | Some(i256::from_i128(11)), |
1203 | | ), |
1204 | | ( |
1205 | | "-000000000000000000000000000000000000000011", |
1206 | | Some(i256::from_i128(-11)), |
1207 | | ), |
1208 | | ( |
1209 | | "-0000000000000000000000000000000000000000123456789", |
1210 | | Some(i256::from_i128(-123456789)), |
1211 | | ), |
1212 | | ("-", None), |
1213 | | ("+", None), |
1214 | | ("--1", None), |
1215 | | ("-+1", None), |
1216 | | ("000000000000000000000000000000000000000", Some(i256::ZERO)), |
1217 | | ("0000000000000000000000000000000000000000-11", None), |
1218 | | ("11-1111111111111111111111111111111111111", None), |
1219 | | ( |
1220 | | "115792089237316195423570985008687907853269984665640564039457584007913129639936", |
1221 | | None, |
1222 | | ), |
1223 | | ]; |
1224 | | for (case, expected) in cases { |
1225 | | assert_eq!(i256::from_string(case), expected) |
1226 | | } |
1227 | | } |
1228 | | |
1229 | | #[allow(clippy::op_ref)] |
1230 | | fn test_reference_op(il: i256, ir: i256) { |
1231 | | let r1 = il + ir; |
1232 | | let r2 = &il + ir; |
1233 | | let r3 = il + &ir; |
1234 | | let r4 = &il + &ir; |
1235 | | assert_eq!(r1, r2); |
1236 | | assert_eq!(r1, r3); |
1237 | | assert_eq!(r1, r4); |
1238 | | |
1239 | | let r1 = il - ir; |
1240 | | let r2 = &il - ir; |
1241 | | let r3 = il - &ir; |
1242 | | let r4 = &il - &ir; |
1243 | | assert_eq!(r1, r2); |
1244 | | assert_eq!(r1, r3); |
1245 | | assert_eq!(r1, r4); |
1246 | | |
1247 | | let r1 = il * ir; |
1248 | | let r2 = &il * ir; |
1249 | | let r3 = il * &ir; |
1250 | | let r4 = &il * &ir; |
1251 | | assert_eq!(r1, r2); |
1252 | | assert_eq!(r1, r3); |
1253 | | assert_eq!(r1, r4); |
1254 | | |
1255 | | let r1 = il / ir; |
1256 | | let r2 = &il / ir; |
1257 | | let r3 = il / &ir; |
1258 | | let r4 = &il / &ir; |
1259 | | assert_eq!(r1, r2); |
1260 | | assert_eq!(r1, r3); |
1261 | | assert_eq!(r1, r4); |
1262 | | } |
1263 | | |
1264 | | #[test] |
1265 | | fn test_i256_reference_op() { |
1266 | | let candidates = [ |
1267 | | i256::ONE, |
1268 | | i256::MINUS_ONE, |
1269 | | i256::from_i128(2), |
1270 | | i256::from_i128(-2), |
1271 | | i256::from_i128(3), |
1272 | | i256::from_i128(-3), |
1273 | | ]; |
1274 | | |
1275 | | for il in candidates { |
1276 | | for ir in candidates { |
1277 | | test_reference_op(il, ir) |
1278 | | } |
1279 | | } |
1280 | | } |
1281 | | |
1282 | | #[test] |
1283 | | fn test_decimal256_to_f64_typical_values() { |
1284 | | let v = i256::from_i128(42_i128); |
1285 | | assert_eq!(v.to_f64().unwrap(), 42.0); |
1286 | | |
1287 | | let v = i256::from_i128(-123456789012345678i128); |
1288 | | assert_eq!(v.to_f64().unwrap(), -123456789012345678.0); |
1289 | | } |
1290 | | |
1291 | | #[test] |
1292 | | fn test_decimal256_to_f64_large_positive_value() { |
1293 | | let max_f = f64::MAX; |
1294 | | let big = i256::from_f64(max_f * 2.0).unwrap_or(i256::MAX); |
1295 | | let out = big.to_f64().unwrap(); |
1296 | | assert!(out.is_finite() && out.is_sign_positive()); |
1297 | | } |
1298 | | |
1299 | | #[test] |
1300 | | fn test_decimal256_to_f64_large_negative_value() { |
1301 | | let max_f = f64::MAX; |
1302 | | let big_neg = i256::from_f64(-(max_f * 2.0)).unwrap_or(i256::MIN); |
1303 | | let out = big_neg.to_f64().unwrap(); |
1304 | | assert!(out.is_finite() && out.is_sign_negative()); |
1305 | | } |
1306 | | } |