ethnum/
int.rs

1//! Root module for 256-bit signed integer type.
2
3mod api;
4mod cmp;
5mod convert;
6mod fmt;
7mod iter;
8mod ops;
9mod parse;
10
11pub use self::convert::AsI256;
12use crate::uint::U256;
13use core::{mem::MaybeUninit, num::ParseIntError};
14
15/// A 256-bit signed integer type.
16#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
17#[repr(transparent)]
18pub struct I256(pub [i128; 2]);
19
20impl I256 {
21    /// The additive identity for this integer type, i.e. `0`.
22    pub const ZERO: Self = I256([0; 2]);
23
24    /// The multiplicative identity for this integer type, i.e. `1`.
25    pub const ONE: Self = I256::new(1);
26
27    /// The multiplicative inverse for this integer type, i.e. `-1`.
28    pub const MINUS_ONE: Self = I256::new(-1);
29
30    /// Creates a new 256-bit integer value from a primitive `i128` integer.
31    #[inline]
32    pub const fn new(value: i128) -> Self {
33        I256::from_words(value >> 127, value)
34    }
35
36    /// Creates a new 256-bit integer value from high and low words.
37    #[inline]
38    pub const fn from_words(hi: i128, lo: i128) -> Self {
39        #[cfg(target_endian = "little")]
40        {
41            I256([lo, hi])
42        }
43        #[cfg(target_endian = "big")]
44        {
45            I256([hi, lo])
46        }
47    }
48
49    /// Splits a 256-bit integer into high and low words.
50    #[inline]
51    pub const fn into_words(self) -> (i128, i128) {
52        #[cfg(target_endian = "little")]
53        {
54            let I256([lo, hi]) = self;
55            (hi, lo)
56        }
57        #[cfg(target_endian = "big")]
58        {
59            let I256([hi, lo]) = self;
60            (hi, lo)
61        }
62    }
63
64    /// Get the low 128-bit word for this signed integer.
65    #[inline]
66    pub fn low(&self) -> &i128 {
67        #[cfg(target_endian = "little")]
68        {
69            &self.0[0]
70        }
71        #[cfg(target_endian = "big")]
72        {
73            &self.0[1]
74        }
75    }
76
77    /// Get the low 128-bit word for this signed integer as a mutable reference.
78    #[inline]
79    pub fn low_mut(&mut self) -> &mut i128 {
80        #[cfg(target_endian = "little")]
81        {
82            &mut self.0[0]
83        }
84        #[cfg(target_endian = "big")]
85        {
86            &mut self.0[1]
87        }
88    }
89
90    /// Get the high 128-bit word for this signed integer.
91    #[inline]
92    pub fn high(&self) -> &i128 {
93        #[cfg(target_endian = "little")]
94        {
95            &self.0[1]
96        }
97        #[cfg(target_endian = "big")]
98        {
99            &self.0[0]
100        }
101    }
102
103    /// Get the high 128-bit word for this signed integer as a mutable
104    /// reference.
105    #[inline]
106    pub fn high_mut(&mut self) -> &mut i128 {
107        #[cfg(target_endian = "little")]
108        {
109            &mut self.0[1]
110        }
111        #[cfg(target_endian = "big")]
112        {
113            &mut self.0[0]
114        }
115    }
116
117    /// Converts a prefixed string slice in base 16 to an integer.
118    ///
119    /// The string is expected to be an optional `+` or `-` sign followed by
120    /// the `0x` prefix and finally the digits. Leading and trailing whitespace
121    /// represent an error.
122    ///
123    /// # Examples
124    ///
125    /// Basic usage:
126    ///
127    /// ```
128    /// # use ethnum::I256;
129    /// assert_eq!(I256::from_str_hex("0x2A"), Ok(I256::new(42)));
130    /// assert_eq!(I256::from_str_hex("-0xa"), Ok(I256::new(-10)));
131    /// ```
132    pub fn from_str_hex(src: &str) -> Result<Self, ParseIntError> {
133        crate::parse::from_str_radix(src, 16, Some("0x"))
134    }
135
136    /// Converts a prefixed string slice in a base determined by the prefix to
137    /// an integer.
138    ///
139    /// The string is expected to be an optional `+` or `-` sign followed by
140    /// the one of the supported prefixes and finally the digits. Leading and
141    /// trailing whitespace represent an error. The base is determined based
142    /// on the prefix:
143    ///
144    /// * `0b`: base `2`
145    /// * `0o`: base `8`
146    /// * `0x`: base `16`
147    /// * no prefix: base `10`
148    ///
149    /// # Examples
150    ///
151    /// Basic usage:
152    ///
153    /// ```
154    /// # use ethnum::I256;
155    /// assert_eq!(I256::from_str_prefixed("-0b101"), Ok(I256::new(-0b101)));
156    /// assert_eq!(I256::from_str_prefixed("0o17"), Ok(I256::new(0o17)));
157    /// assert_eq!(I256::from_str_prefixed("-0xa"), Ok(I256::new(-0xa)));
158    /// assert_eq!(I256::from_str_prefixed("42"), Ok(I256::new(42)));
159    /// ```
160    pub fn from_str_prefixed(src: &str) -> Result<Self, ParseIntError> {
161        crate::parse::from_str_prefixed(src)
162    }
163
164    /// Same as [`I256::from_str_prefixed`] but as a `const fn`. This method is
165    /// not intended to be used directly but rather through the [`crate::int`]
166    /// macro.
167    #[doc(hidden)]
168    pub const fn const_from_str_prefixed(src: &str) -> Self {
169        parse::const_from_str_prefixed(src)
170    }
171
172    /// Cast to a primitive `i8`.
173    #[inline]
174    pub const fn as_i8(self) -> i8 {
175        let (_, lo) = self.into_words();
176        lo as _
177    }
178
179    /// Cast to a primitive `i16`.
180    #[inline]
181    pub const fn as_i16(self) -> i16 {
182        let (_, lo) = self.into_words();
183        lo as _
184    }
185
186    /// Cast to a primitive `i32`.
187    #[inline]
188    pub const fn as_i32(self) -> i32 {
189        let (_, lo) = self.into_words();
190        lo as _
191    }
192
193    /// Cast to a primitive `i64`.
194    #[inline]
195    pub const fn as_i64(self) -> i64 {
196        let (_, lo) = self.into_words();
197        lo as _
198    }
199
200    /// Cast to a primitive `i128`.
201    #[inline]
202    pub const fn as_i128(self) -> i128 {
203        let (_, lo) = self.into_words();
204        lo as _
205    }
206
207    /// Cast to a primitive `u8`.
208    #[inline]
209    pub const fn as_u8(self) -> u8 {
210        let (_, lo) = self.into_words();
211        lo as _
212    }
213
214    /// Cast to a primitive `u16`.
215    #[inline]
216    pub const fn as_u16(self) -> u16 {
217        let (_, lo) = self.into_words();
218        lo as _
219    }
220
221    /// Cast to a primitive `u32`.
222    #[inline]
223    pub const fn as_u32(self) -> u32 {
224        let (_, lo) = self.into_words();
225        lo as _
226    }
227
228    /// Cast to a primitive `u64`.
229    #[inline]
230    pub const fn as_u64(self) -> u64 {
231        let (_, lo) = self.into_words();
232        lo as _
233    }
234
235    /// Cast to a primitive `u128`.
236    #[inline]
237    pub const fn as_u128(self) -> u128 {
238        let (_, lo) = self.into_words();
239        lo as _
240    }
241
242    /// Cast to a `U256`.
243    #[inline]
244    pub const fn as_u256(self) -> U256 {
245        let Self([a, b]) = self;
246        U256([a as _, b as _])
247    }
248
249    /// Cast to a primitive `isize`.
250    #[inline]
251    pub const fn as_isize(self) -> isize {
252        let (_, lo) = self.into_words();
253        lo as _
254    }
255
256    /// Cast to a primitive `usize`.
257    #[inline]
258    pub const fn as_usize(self) -> usize {
259        let (_, lo) = self.into_words();
260        lo as _
261    }
262
263    /// Cast to a primitive `f32`.
264    #[inline]
265    pub fn as_f32(self) -> f32 {
266        self.as_f64() as _
267    }
268
269    /// Cast to a primitive `f64`.
270    #[inline]
271    pub fn as_f64(self) -> f64 {
272        let sign = self.signum128() as f64;
273        self.unsigned_abs().as_f64() * sign
274    }
275
276    /// Performs integer and division and returns the quotient and the remainder as a tuple. This is equivelent to `(self / rhs, self % rhs)`, but more effecient.
277    ///
278    /// # Panics
279    ///
280    /// This function will panic if `rhs` is 0, and will panic on overflow iff debug assertions are enabled.
281    ///
282    /// # Examples
283    ///
284    /// Basic usage:
285    ///
286    /// ```
287    /// # use ethnum::I256;
288    /// assert_eq!(I256::new(22).div_rem(I256::new(5)), (I256::new(4), I256::new(2)));
289    /// assert_eq!(I256::new(-22).div_rem(I256::new(5)), (I256::new(-4), I256::new(-2)));
290    /// assert_eq!(I256::new(22).div_rem(I256::new(-5)), (I256::new(-4), I256::new(2)));
291    /// assert_eq!(I256::new(-22).div_rem(I256::new(-5)), (I256::new(4), I256::new(-2)));
292    /// ```
293    #[inline]
294    #[must_use = "this returns the result of the operation, \
295                  without modifying the original"]
296    #[track_caller]
297    pub fn div_rem(self, rhs: Self) -> (Self, Self) {
298        if self == Self::MIN && rhs == -1 {
299            panic!("attempt to divide with overflow")
300        }
301        self.wrapping_div_rem(rhs)
302    }
303
304    /// Performs euclidean division and returns the quotient and the remainder as a tuple.
305    ///
306    /// This computes the integers `q` and `r` such that self = q * rhs + r, with `q = self.div_euclid` and `r = self.rem_euclid(rhs)`.
307    ///
308    /// # Panics
309    ///
310    /// This function will panic if `rhs` is 0, and will panic on overflow iff debug assertions are enabled.
311    ///
312    /// # Examples
313    ///
314    /// Basic usage:
315    ///
316    /// ```
317    /// # use ethnum::I256;
318    /// assert_eq!(I256::new(22).div_rem_euclid(I256::new(5)), (I256::new(4), I256::new(2)));
319    /// assert_eq!(I256::new(-22).div_rem_euclid(I256::new(5)), (I256::new(-5), I256::new(3)));
320    /// assert_eq!(I256::new(22).div_rem_euclid(I256::new(-5)), (I256::new(-4), I256::new(2)));
321    /// assert_eq!(I256::new(-22).div_rem_euclid(I256::new(-5)), (I256::new(5), I256::new(3)));
322    ///
323    /// # assert_eq!(I256::new(20).div_rem_euclid(I256::new(5)), (I256::new(4), I256::new(0)));
324    /// # assert_eq!(I256::new(-20).div_rem_euclid(I256::new(5)), (I256::new(-4), I256::new(0)));
325    /// # assert_eq!(I256::new(20).div_rem_euclid(I256::new(-5)), (I256::new(-4), I256::new(0)));
326    /// # assert_eq!(I256::new(-20).div_rem_euclid(I256::new(-5)), (I256::new(4), I256::new(0)));
327    /// ```
328    #[inline]
329    #[must_use = "this returns the result of the operation, \
330                  without modifying the original"]
331    #[track_caller]
332    pub fn div_rem_euclid(self, rhs: Self) -> (Self, Self) {
333        if self == Self::MIN && rhs == -1 {
334            panic!("attempt to divide with overflow")
335        }
336        self.wrapping_div_rem_euclid(rhs)
337    }
338
339    /// Checked division. Computes `self.div_rem(rhs)`,
340    /// returning `None` if `rhs == 0` or the division results in overflow.
341    ///
342    /// # Examples
343    ///
344    /// Basic usage:
345    ///
346    /// ```
347    /// # use ethnum::I256;
348    /// assert_eq!((I256::MIN + 1).checked_div_rem(I256::new(-1)), Some((I256::MAX, I256::new(0))));
349    /// assert_eq!(I256::MIN.checked_div_rem(I256::new(-1)), None);
350    /// assert_eq!(I256::new(1).checked_div_rem(I256::new(0)), None);
351    /// ```
352    #[inline]
353    #[must_use = "this returns the result of the operation, \
354                  without modifying the original"]
355    #[track_caller]
356    pub fn checked_div_rem(self, rhs: Self) -> Option<(Self, Self)> {
357        if rhs == 0 || (self == Self::MIN && rhs == -1) {
358            None
359        } else {
360            if rhs.cmp(&I256::ZERO) == core::cmp::Ordering::Equal {
361                // The optimizer understands inequalities better
362                unsafe { core::hint::unreachable_unchecked() }
363            }
364
365            let mut res: MaybeUninit<Self> = MaybeUninit::uninit();
366            let mut rem: MaybeUninit<Self> = MaybeUninit::uninit();
367            crate::intrinsics::idivmod4(&mut res, &self, &rhs, Some(&mut rem));
368            unsafe { Some(((res.assume_init()), (rem.assume_init()))) }
369        }
370    }
371
372    /// Checked Euclidean division. Computes `self.div_rem_euclid(rhs)`,
373    /// returning `None` if `rhs == 0` or the division results in overflow.
374    ///
375    /// # Examples
376    ///
377    /// Basic usage:
378    ///
379    /// ```
380    /// # use ethnum::I256;
381    /// assert_eq!((I256::MIN + 1).checked_div_rem_euclid(I256::new(-1)), Some((I256::MAX, I256::new(0))));
382    /// assert_eq!(I256::MIN.checked_div_rem_euclid(I256::new(-1)), None);
383    /// assert_eq!(I256::new(1).checked_div_rem_euclid(I256::new(0)), None);
384    /// ```
385    #[inline]
386    #[must_use = "this returns the result of the operation, \
387                  without modifying the original"]
388    #[track_caller]
389    pub fn checked_div_rem_euclid(self, rhs: Self) -> Option<(Self, Self)> {
390        if rhs == 0 || (self == Self::MIN && rhs == -1) {
391            None
392        } else {
393            if rhs.cmp(&I256::ZERO) == core::cmp::Ordering::Equal {
394                // The optimizer understands inequalities better
395                unsafe { core::hint::unreachable_unchecked() }
396            }
397
398            Some(self.wrapping_div_rem_euclid(rhs))
399        }
400    }
401
402    /// Saturating integer division. Computes `self.div_rem(rhs)`, saturating at the
403    /// numeric bounds instead of overflowing.
404    ///
405    /// # Examples
406    ///
407    /// Basic usage:
408    ///
409    /// ```
410    /// # use ethnum::I256;
411    /// assert_eq!(I256::new(5).saturating_div_rem(I256::new(2)), (I256::new(2), I256::new(1)));
412    /// assert_eq!(I256::MAX.saturating_div_rem(I256::new(-1)), (I256::MIN + 1, I256::new(0)));
413    /// assert_eq!(I256::MIN.saturating_div_rem(I256::new(-1)), (I256::MAX, I256::new(0)));
414    /// ```
415    /// ```should_panic (expected = "attempt to divide by zero")
416    /// # use ethnum::I256;
417    /// let _ = I256::new(1).saturating_div_rem(I256::ZERO);
418    /// ```
419    #[inline]
420    #[must_use = "this returns the result of the operation, \
421                  without modifying the original"]
422    #[track_caller]
423    pub fn saturating_div_rem(self, rhs: Self) -> (Self, Self) {
424        match self.overflowing_div_rem(rhs) {
425            (q, r, false) => (q, r),
426            (_q, r, true) => (Self::MAX, r), // MIN / -1 is the only possible saturating overflow
427        }
428    }
429
430    /// Saturating integer division. Computes `self.div_rem_euclid(rhs)`, saturating at the
431    /// numeric bounds instead of overflowing.
432    ///
433    /// # Examples
434    ///
435    /// Basic usage:
436    ///
437    /// ```
438    /// # use ethnum::I256;
439    /// assert_eq!(I256::new(5).saturating_div_rem_euclid(I256::new(2)), (I256::new(2), I256::new(1)));
440    /// assert_eq!(I256::MAX.saturating_div_rem_euclid(I256::new(-1)), (I256::MIN + 1, I256::new(0)));
441    /// assert_eq!(I256::MIN.saturating_div_rem_euclid(I256::new(-1)), (I256::MAX, I256::new(0)));
442    /// ```
443    /// ```should_panic (expected = "attempt to divide by zero")
444    /// # use ethnum::I256;
445    /// let _ = I256::new(1).saturating_div_rem_euclid(I256::ZERO);
446    /// ```
447    #[inline]
448    #[must_use = "this returns the result of the operation, \
449                  without modifying the original"]
450    #[track_caller]
451    pub fn saturating_div_rem_euclid(self, rhs: Self) -> (Self, Self) {
452        match self.overflowing_div_rem_euclid(rhs) {
453            (q, r, false) => (q, r),
454            (_q, r, true) => (Self::MAX, r),
455        }
456    }
457
458    /// Performs integer and division and returns the quotient and the remainder as a tuple. This is equivelent to `(self.wrapping_div(rhs), self.wrapping_rem(rhs))`, but more effecient.
459    ///
460    /// # Panics
461    ///
462    /// This function will panic if `rhs` is 0.
463    ///
464    /// # Examples
465    ///
466    /// Basic usage:
467    ///
468    /// ```
469    /// # use ethnum::I256;
470    /// assert_eq!(I256::new(22).wrapping_div_rem(I256::new(5)), (I256::new(4), I256::new(2)));
471    /// assert_eq!(I256::new(-22).wrapping_div_rem(I256::new(5)), (I256::new(-4), I256::new(-2)));
472    /// assert_eq!(I256::new(22).wrapping_div_rem(I256::new(-5)), (I256::new(-4), I256::new(2)));
473    /// assert_eq!(I256::new(-22).wrapping_div_rem(I256::new(-5)), (I256::new(4), I256::new(-2)));
474    ///
475    /// assert_eq!(I256::MIN.wrapping_div_rem(I256::MINUS_ONE), (I256::MIN, I256::ZERO));
476    /// ```
477    #[inline]
478    #[must_use = "this returns the result of the operation, \
479                  without modifying the original"]
480    #[track_caller]
481    pub fn wrapping_div_rem(self, rhs: Self) -> (Self, Self) {
482        if rhs == 0 {
483            if rhs.cmp(&I256::ZERO) != core::cmp::Ordering::Equal {
484                // The optimizer understands inequalities better
485                unsafe { core::hint::unreachable_unchecked() }
486            }
487            panic!("attempt to divide by zero");
488        }
489        if rhs.cmp(&I256::ZERO) == core::cmp::Ordering::Equal {
490            // The optimizer understands inequalities better
491            unsafe { core::hint::unreachable_unchecked() }
492        }
493
494        let mut res: MaybeUninit<Self> = MaybeUninit::uninit();
495        let mut rem: MaybeUninit<Self> = MaybeUninit::uninit();
496        crate::intrinsics::idivmod4(&mut res, &self, &rhs, Some(&mut rem));
497        unsafe { ((res.assume_init()), (rem.assume_init())) }
498    }
499
500    /// Performs euclidean division and returns the quotient and the remainder as a tuple.
501    ///
502    /// This computes the integers `q` and `r` such that self = q * rhs + r, with `q = self.wrapping_div_euclid` and `r = self.wrapping_rem_euclid(rhs)`.
503    ///
504    /// # Panics
505    ///
506    /// This function will panic if `rhs` is 0.
507    ///
508    /// # Examples
509    ///
510    /// Basic usage:
511    ///
512    /// ```
513    /// # use ethnum::I256;
514    /// assert_eq!(I256::new(22).wrapping_div_rem_euclid(I256::new(5)), (I256::new(4), I256::new(2)));
515    /// assert_eq!(I256::new(-22).wrapping_div_rem_euclid(I256::new(5)), (I256::new(-5), I256::new(3)));
516    /// assert_eq!(I256::new(22).wrapping_div_rem_euclid(I256::new(-5)), (I256::new(-4), I256::new(2)));
517    /// assert_eq!(I256::new(-22).wrapping_div_rem_euclid(I256::new(-5)), (I256::new(5), I256::new(3)));
518    ///
519    /// assert_eq!(I256::MIN.wrapping_div_rem(I256::MINUS_ONE), (I256::MIN, I256::ZERO));
520    /// # assert_eq!(I256::new(20).wrapping_div_rem_euclid(I256::new(5)), (I256::new(4), I256::new(0)));
521    /// # assert_eq!(I256::new(-20).wrapping_div_rem_euclid(I256::new(5)), (I256::new(-4), I256::new(0)));
522    /// # assert_eq!(I256::new(20).wrapping_div_rem_euclid(I256::new(-5)), (I256::new(-4), I256::new(0)));
523    /// # assert_eq!(I256::new(-20).wrapping_div_rem_euclid(I256::new(-5)), (I256::new(4), I256::new(0)));
524    /// ```
525    #[inline]
526    #[must_use = "this returns the result of the operation, \
527                  without modifying the original"]
528    #[track_caller]
529    pub fn wrapping_div_rem_euclid(self, rhs: Self) -> (Self, Self) {
530        let dividend_sign = self.is_negative();
531        let quotient_sign = dividend_sign ^ rhs.is_negative();
532        let abs_dividend = self.unsigned_abs();
533        let abs_divisor = rhs.unsigned_abs();
534
535        let (q, r) = abs_dividend.div_rem(abs_divisor);
536        let mut quotient = q.as_i256();
537        let mut remainder = r.as_i256();
538
539        let adjust_remainder = dividend_sign && remainder != 0;
540        if adjust_remainder {
541            remainder = abs_divisor.as_i256() - remainder;
542            // cannot overflow
543        }
544        if remainder.is_negative() || remainder.as_u256() >= abs_divisor {
545            debug_assert!(false);
546            unsafe { core::hint::unreachable_unchecked() }
547        }
548
549        if adjust_remainder {
550            if quotient_sign {
551                quotient = !quotient;
552                // quotient = -quotient - 1
553            } else {
554                quotient += 1;
555                // cannot overflow
556            }
557        } else if quotient_sign {
558            quotient = quotient.wrapping_neg();
559        }
560
561        (quotient, remainder)
562    }
563
564    /// Calculates the quotient and the remainder when `self` is divided by `rhs`.
565    ///
566    /// Returns a tuple of the quotient and the remainder along with a boolean indicating whether
567    /// an arithmetic overflow would occur. If an overflow would occur then
568    /// `self` is returned.
569    ///
570    /// # Panics
571    ///
572    /// This function will panic if `rhs` is 0.
573    ///
574    /// # Examples
575    ///
576    /// Basic usage:
577    ///
578    /// ```
579    /// # use ethnum::I256;
580    /// assert_eq!(I256::new(5).overflowing_div_rem(I256::new(2)), (I256::new(2), I256::new(1), false));
581    /// assert_eq!(I256::MIN.overflowing_div_rem(I256::new(-1)), (I256::MIN, I256::new(0), true));
582    /// ```
583    #[inline]
584    #[must_use = "this returns the result of the operation, \
585                  without modifying the original"]
586    #[track_caller]
587    pub fn overflowing_div_rem(self, rhs: Self) -> (Self, Self, bool) {
588        if self == Self::MIN && rhs == -1 {
589            (self, Self::ZERO, true)
590        } else {
591            let (q, r) = self.wrapping_div_rem(rhs);
592            (q, r, false)
593        }
594    }
595
596    /// Calculates the quotient and remainder of Euclidean division `self.div_rem_euclid(rhs)`.
597    ///
598    /// Returns a tuple of the quotient and the remainder along with a boolean indicating whether
599    /// an arithmetic overflow would occur. If an overflow would occur then
600    /// `self` is returned.
601    ///
602    /// # Panics
603    ///
604    /// This function will panic if `rhs` is 0.
605    ///
606    /// # Examples
607    ///
608    /// Basic usage:
609    ///
610    /// ```
611    /// # use ethnum::I256;
612    /// assert_eq!(I256::new(5).overflowing_div_rem_euclid(I256::new(2)), (I256::new(2), I256::new(1), false));
613    /// assert_eq!(I256::MIN.overflowing_div_rem_euclid(I256::new(-1)), (I256::MIN, I256::new(0), true));
614    /// ```
615    #[inline]
616    #[must_use = "this returns the result of the operation, \
617                  without modifying the original"]
618    #[track_caller]
619    pub fn overflowing_div_rem_euclid(self, rhs: Self) -> (Self, Self, bool) {
620        if self == Self::MIN && rhs == -1 {
621            (self, Self::ZERO, true)
622        } else {
623            let (q, r) = self.wrapping_div_rem_euclid(rhs);
624            (q, r, false)
625        }
626    }
627}
628
629#[cfg(test)]
630mod tests {
631    use crate::I256;
632
633    #[test]
634    #[allow(clippy::float_cmp)]
635    fn converts_to_f64() {
636        assert_eq!((-I256::from_words(1, 0)).as_f64(), -(2.0f64.powi(128)))
637    }
638}