Skip to main content

arrow_buffer/bigint/
mod.rs

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
18use crate::arith::derive_arith;
19use crate::bigint::div::div_rem;
20use num_bigint::BigInt;
21use num_traits::{
22    Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr,
23    CheckedSub, ConstOne, ConstZero, FromPrimitive, MulAdd, MulAddAssign, Num, One, SaturatingAdd,
24    SaturatingMul, SaturatingSub, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingNeg,
25    WrappingShl, WrappingShr, WrappingSub, Zero, cast::AsPrimitive,
26};
27use std::cmp::Ordering;
28use std::num::ParseIntError;
29use std::ops::{BitAnd, BitOr, BitXor, Neg, Not, Shl, Shr};
30use std::str::FromStr;
31
32mod div;
33
34/// An opaque error similar to [`std::num::ParseIntError`]
35#[derive(Debug)]
36pub struct ParseI256Error {}
37
38impl From<ParseIntError> for ParseI256Error {
39    fn from(_: ParseIntError) -> Self {
40        Self {}
41    }
42}
43
44impl std::fmt::Display for ParseI256Error {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(f, "Failed to parse as i256")
47    }
48}
49impl std::error::Error for ParseI256Error {}
50
51/// Error returned by i256::DivRem
52enum DivRemError {
53    /// Division by zero
54    DivideByZero,
55    /// Division overflow
56    DivideOverflow,
57}
58
59/// A signed 256-bit integer
60#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
61#[repr(C)]
62pub struct i256 {
63    low: u128,
64    high: i128,
65}
66
67impl std::fmt::Debug for i256 {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(f, "{self}")
70    }
71}
72
73impl std::fmt::Display for i256 {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        write!(f, "{}", BigInt::from_signed_bytes_le(&self.to_le_bytes()))
76    }
77}
78
79impl FromStr for i256 {
80    type Err = ParseI256Error;
81
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        // i128 can store up to 38 decimal digits
84        if s.len() <= 38 {
85            return Ok(Self::from_i128(i128::from_str(s)?));
86        }
87
88        let (negative, s) = match s.as_bytes()[0] {
89            b'-' => (true, &s[1..]),
90            b'+' => (false, &s[1..]),
91            _ => (false, s),
92        };
93
94        // Trim leading 0s
95        let s = s.trim_start_matches('0');
96        if s.is_empty() {
97            return Ok(i256::ZERO);
98        }
99
100        if !s.as_bytes()[0].is_ascii_digit() {
101            // Ensures no duplicate sign
102            return Err(ParseI256Error {});
103        }
104
105        parse_impl(s, negative)
106    }
107}
108
109impl From<i8> for i256 {
110    fn from(value: i8) -> Self {
111        Self::from_i128(value.into())
112    }
113}
114
115impl From<i16> for i256 {
116    fn from(value: i16) -> Self {
117        Self::from_i128(value.into())
118    }
119}
120
121impl From<i32> for i256 {
122    fn from(value: i32) -> Self {
123        Self::from_i128(value.into())
124    }
125}
126
127impl From<i64> for i256 {
128    fn from(value: i64) -> Self {
129        Self::from_i128(value.into())
130    }
131}
132
133impl From<i128> for i256 {
134    fn from(value: i128) -> Self {
135        Self::from_i128(value)
136    }
137}
138
139/// Parse `s` with any sign and leading 0s removed
140fn parse_impl(s: &str, negative: bool) -> Result<i256, ParseI256Error> {
141    if s.len() <= 38 {
142        let low = i128::from_str(s)?;
143        return Ok(match negative {
144            true => i256::from_parts(low.neg() as _, -1),
145            false => i256::from_parts(low as _, 0),
146        });
147    }
148
149    let split = s.len() - 38;
150    if !s.as_bytes()[split].is_ascii_digit() {
151        // Ensures not splitting codepoint and no sign
152        return Err(ParseI256Error {});
153    }
154    let (hs, ls) = s.split_at(split);
155
156    let mut low = i128::from_str(ls)?;
157    let high = parse_impl(hs, negative)?;
158
159    if negative {
160        low = -low;
161    }
162
163    let low = i256::from_i128(low);
164
165    high.checked_mul(i256::from_i128(10_i128.pow(38)))
166        .and_then(|high| high.checked_add(low))
167        .ok_or(ParseI256Error {})
168}
169
170impl PartialOrd for i256 {
171    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
172        Some(self.cmp(other))
173    }
174}
175
176impl Ord for i256 {
177    fn cmp(&self, other: &Self) -> Ordering {
178        // This is 25x faster than using a variable length encoding such
179        // as BigInt as it avoids allocation and branching
180        self.high.cmp(&other.high).then(self.low.cmp(&other.low))
181    }
182}
183
184impl i256 {
185    /// The additive identity for this integer type, i.e. `0`.
186    pub const ZERO: Self = i256 { low: 0, high: 0 };
187
188    /// The multiplicative identity for this integer type, i.e. `1`.
189    pub const ONE: Self = i256 { low: 1, high: 0 };
190
191    /// The multiplicative inverse for this integer type, i.e. `-1`.
192    pub const MINUS_ONE: Self = i256 {
193        low: u128::MAX,
194        high: -1,
195    };
196
197    /// The maximum value that can be represented by this integer type
198    pub const MAX: Self = i256 {
199        low: u128::MAX,
200        high: i128::MAX,
201    };
202
203    /// The minimum value that can be represented by this integer type
204    pub const MIN: Self = i256 {
205        low: u128::MIN,
206        high: i128::MIN,
207    };
208
209    /// Create an integer value from its representation as a byte array in little-endian.
210    #[inline]
211    pub const fn from_le_bytes(b: [u8; 32]) -> Self {
212        let (low, high) = split_array(b);
213        Self {
214            high: i128::from_le_bytes(high),
215            low: u128::from_le_bytes(low),
216        }
217    }
218
219    /// Create an integer value from its representation as a byte array in big-endian.
220    #[inline]
221    pub const fn from_be_bytes(b: [u8; 32]) -> Self {
222        let (high, low) = split_array(b);
223        Self {
224            high: i128::from_be_bytes(high),
225            low: u128::from_be_bytes(low),
226        }
227    }
228
229    /// Create an `i256` value from a 128-bit value.
230    pub const fn from_i128(v: i128) -> Self {
231        Self::from_parts(v as u128, v >> 127)
232    }
233
234    /// Create an integer value from its representation as string.
235    #[inline]
236    pub fn from_string(value_str: &str) -> Option<Self> {
237        value_str.parse().ok()
238    }
239
240    /// Create an optional i256 from the provided `f64`. Returning `None`
241    /// if overflow occurred
242    pub fn from_f64(v: f64) -> Option<Self> {
243        let (integer, overflow) = i256::from_bigint_with_overflow(BigInt::from_f64(v)?);
244        if overflow { None } else { Some(integer) }
245    }
246
247    /// Create an i256 from the provided low u128 and high i128
248    #[inline]
249    pub const fn from_parts(low: u128, high: i128) -> Self {
250        Self { low, high }
251    }
252
253    /// Returns this `i256` as a low u128 and high i128
254    pub const fn to_parts(self) -> (u128, i128) {
255        (self.low, self.high)
256    }
257
258    /// Converts this `i256` into an `i128` returning `None` if this would result
259    /// in truncation/overflow
260    pub const fn to_i128(self) -> Option<i128> {
261        let as_i128 = self.low as i128;
262
263        let high_negative = self.high < 0;
264        let low_negative = as_i128 < 0;
265        let high_valid = self.high == -1 || self.high == 0;
266
267        if (high_negative == low_negative) && high_valid {
268            Some(self.low as i128)
269        } else {
270            None
271        }
272    }
273
274    /// Wraps this `i256` into an `i128`
275    pub const fn as_i128(self) -> i128 {
276        self.low as i128
277    }
278
279    /// Return the memory representation of this integer as a byte array in little-endian byte order.
280    #[inline]
281    pub const fn to_le_bytes(self) -> [u8; 32] {
282        let low = self.low.to_le_bytes();
283        let high = self.high.to_le_bytes();
284        let mut t = [0; 32];
285        let mut i = 0;
286        while i != 16 {
287            t[i] = low[i];
288            t[i + 16] = high[i];
289            i += 1;
290        }
291        t
292    }
293
294    /// Return the memory representation of this integer as a byte array in big-endian byte order.
295    #[inline]
296    pub const fn to_be_bytes(self) -> [u8; 32] {
297        let low = self.low.to_be_bytes();
298        let high = self.high.to_be_bytes();
299        let mut t = [0; 32];
300        let mut i = 0;
301        while i != 16 {
302            t[i] = high[i];
303            t[i + 16] = low[i];
304            i += 1;
305        }
306        t
307    }
308
309    /// Create an i256 from the provided [`BigInt`] returning a bool indicating
310    /// if overflow occurred
311    fn from_bigint_with_overflow(v: BigInt) -> (Self, bool) {
312        let v_bytes = v.to_signed_bytes_le();
313        match v_bytes.len().cmp(&32) {
314            Ordering::Less => {
315                let mut bytes = if num_traits::Signed::is_negative(&v) {
316                    [255_u8; 32]
317                } else {
318                    [0; 32]
319                };
320                bytes[0..v_bytes.len()].copy_from_slice(&v_bytes[..v_bytes.len()]);
321                (Self::from_le_bytes(bytes), false)
322            }
323            Ordering::Equal => (Self::from_le_bytes(v_bytes.try_into().unwrap()), false),
324            Ordering::Greater => (Self::from_le_bytes(v_bytes[..32].try_into().unwrap()), true),
325        }
326    }
327
328    /// Computes the absolute value of this i256
329    #[inline]
330    pub const fn wrapping_abs(self) -> Self {
331        // -1 if negative, otherwise 0
332        let sa = self.high >> 127;
333        let sa = Self::from_parts(sa as u128, sa);
334
335        // Inverted if negative
336        Self::from_parts(self.low ^ sa.low, self.high ^ sa.high).wrapping_sub(sa)
337    }
338
339    /// Computes the absolute value of this i256 returning `None` if `Self == Self::MIN`
340    #[inline]
341    pub const fn checked_abs(self) -> Option<Self> {
342        if !self.is_eq(Self::MIN) {
343            Some(self.wrapping_abs())
344        } else {
345            None
346        }
347    }
348
349    /// Negates this i256
350    #[inline]
351    pub const fn wrapping_neg(self) -> Self {
352        Self::from_parts(!self.low, !self.high).wrapping_add(i256::ONE)
353    }
354
355    /// Negates this i256 returning `None` if `Self == Self::MIN`
356    #[inline]
357    pub const fn checked_neg(self) -> Option<Self> {
358        if !self.is_eq(Self::MIN) {
359            Some(self.wrapping_neg())
360        } else {
361            None
362        }
363    }
364
365    /// Performs wrapping addition
366    #[inline]
367    pub const fn wrapping_add(self, other: Self) -> Self {
368        let (low, carry) = self.low.overflowing_add(other.low);
369        let high = self.high.wrapping_add(other.high).wrapping_add(carry as _);
370        Self { low, high }
371    }
372
373    /// Performs checked addition
374    #[inline]
375    pub const fn checked_add(self, other: Self) -> Option<Self> {
376        let (r, overflow) = self.overflowing_add(other);
377
378        if overflow { None } else { Some(r) }
379    }
380
381    /// Performs wrapping subtraction
382    #[inline]
383    pub const fn wrapping_sub(self, other: Self) -> Self {
384        let (low, carry) = self.low.overflowing_sub(other.low);
385        let high = self.high.wrapping_sub(other.high).wrapping_sub(carry as _);
386        Self { low, high }
387    }
388
389    /// Performs checked subtraction
390    #[inline]
391    pub const fn checked_sub(self, other: Self) -> Option<Self> {
392        let (r, overflow) = self.overflowing_sub(other);
393
394        if overflow { None } else { Some(r) }
395    }
396
397    /// Performs wrapping multiplication
398    #[inline]
399    pub const fn wrapping_mul(self, other: Self) -> Self {
400        let (low, high) = mulx(self.low, other.low);
401
402        // Compute the high multiples, only impacting the high 128-bits
403        let hl = self.high.wrapping_mul(other.low as i128);
404        let lh = (self.low as i128).wrapping_mul(other.high);
405
406        Self {
407            low,
408            high: (high as i128).wrapping_add(hl).wrapping_add(lh),
409        }
410    }
411
412    /// Const helper to check equality of two `i256` instances
413    const fn is_eq(&self, other: Self) -> bool {
414        (self.high == other.high) && (self.low == other.low)
415    }
416
417    /// Performs checked multiplication
418    #[inline]
419    pub const fn checked_mul(self, other: Self) -> Option<Self> {
420        if self.is_eq(Self::ZERO) || other.is_eq(Self::ZERO) {
421            return Some(i256::ZERO);
422        }
423
424        // Shift sign bit down to construct mask of all set bits if negative
425        let l_sa = self.high >> 127;
426        let r_sa = other.high >> 127;
427        let out_sa = (l_sa ^ r_sa) as u128;
428
429        // Compute absolute values
430        let l_abs = self.wrapping_abs();
431        let r_abs = other.wrapping_abs();
432
433        // Overflow if both high parts are non-zero
434        if l_abs.high != 0 && r_abs.high != 0 {
435            return None;
436        }
437
438        // Perform checked multiplication on absolute values
439        let (low, high) = mulx(l_abs.low, r_abs.low);
440
441        // Compute the high multiples, only impacting the high 128-bits
442        let Some(hl) = (l_abs.high as u128).checked_mul(r_abs.low) else {
443            return None;
444        };
445        let Some(lh) = l_abs.low.checked_mul(r_abs.high as u128) else {
446            return None;
447        };
448
449        let Some(high) = high.checked_add(hl) else {
450            return None;
451        };
452        let Some(high) = high.checked_add(lh) else {
453            return None;
454        };
455
456        // Reverse absolute value, if necessary
457        let (low, c) = (low ^ out_sa).overflowing_sub(out_sa);
458        let high = (high ^ out_sa).wrapping_sub(out_sa).wrapping_sub(c as u128) as i128;
459
460        // Check for overflow in final conversion
461        if high.is_negative() == (self.is_negative() ^ other.is_negative()) {
462            Some(Self { low, high })
463        } else {
464            None
465        }
466    }
467
468    /// Division operation, returns (quotient, remainder).
469    /// This basically implements [Long division]: `<https://en.wikipedia.org/wiki/Division_algorithm>`
470    #[inline]
471    fn div_rem(self, other: Self) -> Result<(Self, Self), DivRemError> {
472        if other == Self::ZERO {
473            return Err(DivRemError::DivideByZero);
474        }
475        if other == Self::MINUS_ONE && self == Self::MIN {
476            return Err(DivRemError::DivideOverflow);
477        }
478
479        let a = self.wrapping_abs();
480        let b = other.wrapping_abs();
481
482        let (div, rem) = div_rem(&a.as_digits(), &b.as_digits());
483        let div = Self::from_digits(div);
484        let rem = Self::from_digits(rem);
485
486        Ok((
487            if self.is_negative() == other.is_negative() {
488                div
489            } else {
490                div.wrapping_neg()
491            },
492            if self.is_negative() {
493                rem.wrapping_neg()
494            } else {
495                rem
496            },
497        ))
498    }
499
500    /// Interpret this [`i256`] as 4 `u64` digits, least significant first
501    fn as_digits(self) -> [u64; 4] {
502        [
503            self.low as u64,
504            (self.low >> 64) as u64,
505            self.high as u64,
506            (self.high as u128 >> 64) as u64,
507        ]
508    }
509
510    /// Interpret 4 `u64` digits, least significant first, as a [`i256`]
511    fn from_digits(digits: [u64; 4]) -> Self {
512        Self::from_parts(
513            digits[0] as u128 | ((digits[1] as u128) << 64),
514            digits[2] as i128 | ((digits[3] as i128) << 64),
515        )
516    }
517
518    /// Performs wrapping division
519    ///
520    /// # Panics
521    ///
522    /// Panics if `other` is zero
523    #[inline]
524    pub fn wrapping_div(self, other: Self) -> Self {
525        match self.div_rem(other) {
526            Ok((v, _)) => v,
527            Err(DivRemError::DivideByZero) => panic!("attempt to divide by zero"),
528            Err(_) => Self::MIN,
529        }
530    }
531
532    /// Performs checked division
533    #[inline]
534    pub fn checked_div(self, other: Self) -> Option<Self> {
535        self.div_rem(other).map(|(v, _)| v).ok()
536    }
537
538    /// Performs wrapping remainder
539    ///
540    /// # Panics
541    ///
542    /// Panics if `other` is zero
543    #[inline]
544    pub fn wrapping_rem(self, other: Self) -> Self {
545        match self.div_rem(other) {
546            Ok((_, v)) => v,
547            Err(DivRemError::DivideByZero) => panic!("attempt to divide by zero"),
548            Err(_) => Self::ZERO,
549        }
550    }
551
552    /// Performs checked remainder
553    #[inline]
554    pub fn checked_rem(self, other: Self) -> Option<Self> {
555        self.div_rem(other).map(|(_, v)| v).ok()
556    }
557
558    /// Performs checked exponentiation
559    #[inline]
560    pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
561        if exp == 0 {
562            return Some(i256::from_i128(1));
563        }
564
565        let mut base = self;
566        let mut acc: Self = i256::from_i128(1);
567
568        while exp > 1 {
569            if (exp & 1) == 1 {
570                let Some(next) = acc.checked_mul(base) else {
571                    return None;
572                };
573                acc = next;
574            }
575            exp /= 2;
576            let Some(next) = base.checked_mul(base) else {
577                return None;
578            };
579            base = next;
580        }
581        // since exp!=0, finally the exp must be 1.
582        // Deal with the final bit of the exponent separately, since
583        // squaring the base afterwards is not necessary and may cause a
584        // needless overflow.
585        acc.checked_mul(base)
586    }
587
588    /// Performs wrapping exponentiation
589    #[inline]
590    pub const fn wrapping_pow(self, mut exp: u32) -> Self {
591        if exp == 0 {
592            return i256::from_i128(1);
593        }
594
595        let mut base = self;
596        let mut acc: Self = i256::from_i128(1);
597
598        while exp > 1 {
599            if (exp & 1) == 1 {
600                acc = acc.wrapping_mul(base);
601            }
602            exp /= 2;
603            base = base.wrapping_mul(base);
604        }
605
606        // since exp!=0, finally the exp must be 1.
607        // Deal with the final bit of the exponent separately, since
608        // squaring the base afterwards is not necessary and may cause a
609        // needless overflow.
610        acc.wrapping_mul(base)
611    }
612
613    /// Returns a number [`i256`] representing sign of this [`i256`].
614    ///
615    /// 0 if the number is zero
616    /// 1 if the number is positive
617    /// -1 if the number is negative
618    pub const fn signum(self) -> Self {
619        if self.is_positive() {
620            i256::ONE
621        } else if self.is_negative() {
622            i256::MINUS_ONE
623        } else {
624            i256::ZERO
625        }
626    }
627
628    /// Returns `true` if this [`i256`] is negative
629    #[inline]
630    pub const fn is_negative(self) -> bool {
631        self.high.is_negative()
632    }
633
634    /// Returns `true` if this [`i256`] is positive
635    pub const fn is_positive(self) -> bool {
636        self.high.is_positive() || self.high == 0 && self.low != 0
637    }
638
639    /// Returns the number of leading zeros in the binary representation of this [`i256`].
640    pub const fn leading_zeros(&self) -> u32 {
641        match self.high {
642            0 => u128::BITS + self.low.leading_zeros(),
643            _ => self.high.leading_zeros(),
644        }
645    }
646
647    /// Returns the number of trailing zeros in the binary representation of this [`i256`].
648    pub const fn trailing_zeros(&self) -> u32 {
649        match self.low {
650            0 => u128::BITS + self.high.trailing_zeros(),
651            _ => self.low.trailing_zeros(),
652        }
653    }
654
655    fn redundant_leading_sign_bits_i256(n: i256) -> u8 {
656        let mask = n >> 255; // all ones or all zeros
657        ((n ^ mask).leading_zeros() - 1) as u8 // we only need one sign bit
658    }
659
660    fn i256_to_f64(input: i256) -> f64 {
661        let k = i256::redundant_leading_sign_bits_i256(input);
662        let n = input << k; // left-justify (no redundant sign bits)
663        let n = (n.high >> 64) as i64; // throw away the lower 192 bits
664        (n as f64) * f64::powi(2.0, 192 - (k as i32)) // convert to f64 and scale it, as we left-shift k bit previous, so we need to scale it by 2^(192-k)
665    }
666
667    /// Computes the `base` logarithm of the number `self`
668    /// Returns `None` if `self` is less than or equal to zero, or if `base` is less than 2.
669    #[inline]
670    pub fn checked_ilog(self, base: i256) -> Option<u32> {
671        if base == Self::from(10) {
672            // Faster implementation for base 10
673            return self.checked_ilog10();
674        }
675
676        if self <= Self::ZERO {
677            return None;
678        }
679        if base <= Self::ONE {
680            return None;
681        }
682        if self < base {
683            return Some(0);
684        }
685
686        let mut val = 1;
687        let mut base_exp = base;
688
689        let boundary = self.checked_div(base)?;
690        while base_exp <= boundary {
691            val += 1;
692            base_exp = base_exp.checked_mul(base)?;
693        }
694        Some(val)
695    }
696
697    /// Computes the `base` logarithm of the number `self`
698    ///
699    /// # Panics
700    ///
701    /// Panics if `self` is less than or equal to zero, or if `base` is less than 2.
702    #[inline]
703    pub fn ilog(self, base: i256) -> u32 {
704        self.checked_ilog(base)
705            .unwrap_or_else(|| panic!("ilog overflow with {self} and base {base}"))
706    }
707
708    /// Computes the decimal logarithm of the number `self`
709    /// Returns `None` if `self` is less than or equal to zero.
710    #[inline]
711    pub fn checked_ilog10(self) -> Option<u32> {
712        if self <= Self::ZERO {
713            return None;
714        }
715        if self < Self::from(10) {
716            return Some(0);
717        }
718
719        /// `10^32`
720        const POW10_32: i256 = i256::from_i128(100_000_000_000_000_000_000_000_000_000_000);
721
722        /// `10^64`
723        const POW10_64: i256 = i256::from_parts(
724            146_510_663_073_550_942_663_504_491_129_887_260_672,
725            29_387_358_770_557_187_699_218_413,
726        );
727
728        // Layered approach to calculate logarithm using i128 log operations only
729        // Consult int_log10.rs stdlib implementiation for u128
730        if self >= POW10_64 {
731            let value = self.checked_div(POW10_64)?;
732            // self is between 10^64 and 10^77 (~i256::MAX).
733            // `value` is 14 digits max (10^77 / 10^64 = 10^13),
734            // so it fits to `low` u128
735            debug_assert!(value.high == 0);
736            Some(64 + value.low.checked_ilog10()?)
737        } else if self >= POW10_32 {
738            let value = self.checked_div(POW10_32)?;
739            // self is between 10^32 and 10^64.
740            // `value` is 33 digits max (10^64/10^32=10^32)
741            // so it fits to `low` 128-bit value
742            debug_assert!(value.high == 0);
743            Some(32 + value.low.checked_ilog10()?)
744        } else {
745            // self fits within u128 (high == 0 and self > 0).
746            self.low.checked_ilog10()
747        }
748    }
749
750    /// Computes the decimal logarithm of the number `self`
751    ///
752    /// # Panics
753    ///
754    /// Panics if `self` is less than or equal to zero.
755    #[inline]
756    pub fn ilog10(self) -> u32 {
757        self.checked_ilog10()
758            .unwrap_or_else(|| panic!("ilog10 overflow with {self}"))
759    }
760
761    /// Computes the binary logarithm of the number `self`
762    /// Returns `None` if `self` is less than or equal to zero.
763    #[inline]
764    pub fn checked_ilog2(self) -> Option<u32> {
765        self.checked_ilog(i256::from(2))
766    }
767
768    /// Computes the base 2 logarithm of the number, rounded down.
769    ///
770    /// # Panics
771    ///
772    /// Panics if `self` is less than or equal to zero
773    #[inline]
774    pub fn ilog2(self) -> u32 {
775        self.checked_ilog2()
776            .unwrap_or_else(|| panic!("ilog2 overflow with {self}"))
777    }
778
779    /// Calculates `self + rhs`.
780    ///
781    /// Returns the wrapping sum and a boolean indicating whether arithmetic overflow occurred.
782    /// The returned sum wraps around the bounds of [`i256`] when overflow occurs.
783    #[inline]
784    pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
785        // Add the low limbs and capture the carry into the high limb.
786        let (low, carry) = self.low.overflowing_add(rhs.low);
787
788        // Treat the high limbs as raw two's-complement bit patterns.
789        let high = (self.high as u128)
790            .wrapping_add(rhs.high as u128)
791            .wrapping_add(carry as u128) as i128;
792
793        let result = Self { low, high };
794
795        // Signed overflow occurs when:
796        // - both operands have the same sign, and
797        // - the result has the opposite sign.
798        let overflow = (self.high < 0) == (rhs.high < 0) && (high < 0) != (self.high < 0);
799
800        (result, overflow)
801    }
802
803    /// Calculates `self - rhs`.
804    ///
805    /// Returns the wrapping difference and a boolean indicating whether arithmetic overflow
806    /// occurred. The returned difference wraps around the bounds of [`i256`] when overflow occurs.
807    #[inline]
808    pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
809        // Subtract the low limbs and determine whether we borrowed.
810        let (low, borrow) = self.low.overflowing_sub(rhs.low);
811
812        // Subtract the high limbs as raw bit patterns, including the borrow.
813        let high = (self.high as u128)
814            .wrapping_sub(rhs.high as u128)
815            .wrapping_sub(borrow as u128) as i128;
816
817        let result = Self { low, high };
818
819        // Signed overflow occurs when:
820        // - operands have opposite signs, and
821        // - the result's sign differs from the left operand's sign.
822        let overflow = (self.high < 0) != (rhs.high < 0) && (high < 0) != (self.high < 0);
823
824        (result, overflow)
825    }
826}
827
828/// Temporary workaround due to lack of stable const array slicing
829/// See <https://github.com/rust-lang/rust/issues/90091>
830const fn split_array<const N: usize, const M: usize>(vals: [u8; N]) -> ([u8; M], [u8; M]) {
831    let mut a = [0; M];
832    let mut b = [0; M];
833    let mut i = 0;
834    while i != M {
835        a[i] = vals[i];
836        b[i] = vals[i + M];
837        i += 1;
838    }
839    (a, b)
840}
841
842/// Performs an unsigned multiplication of `a * b` returning a tuple of
843/// `(low, high)` where `low` contains the lower 128-bits of the result
844/// and `high` the higher 128-bits
845///
846/// This mirrors the x86 mulx instruction but for 128-bit types
847#[inline]
848const fn mulx(a: u128, b: u128) -> (u128, u128) {
849    const fn split(a: u128) -> (u128, u128) {
850        (a & (u64::MAX as u128), a >> 64)
851    }
852
853    const MASK: u128 = u64::MAX as _;
854
855    let (a_low, a_high) = split(a);
856    let (b_low, b_high) = split(b);
857
858    // Carry stores the upper 64-bits of low and lower 64-bits of high
859    let (mut low, mut carry) = split(a_low * b_low);
860    carry += a_high * b_low;
861
862    // Update low and high with corresponding parts of carry
863    low += carry << 64;
864    let mut high = carry >> 64;
865
866    // Update carry with overflow from low
867    carry = low >> 64;
868    low &= MASK;
869
870    // Perform multiply including overflow from low
871    carry += b_high * a_low;
872
873    // Update low and high with values from carry
874    low += carry << 64;
875    high += carry >> 64;
876
877    // Perform 4th multiplication
878    high += a_high * b_high;
879
880    (low, high)
881}
882
883derive_arith!(
884    i256,
885    Add,
886    AddAssign,
887    add,
888    add_assign,
889    wrapping_add,
890    checked_add
891);
892derive_arith!(
893    i256,
894    Sub,
895    SubAssign,
896    sub,
897    sub_assign,
898    wrapping_sub,
899    checked_sub
900);
901derive_arith!(
902    i256,
903    Mul,
904    MulAssign,
905    mul,
906    mul_assign,
907    wrapping_mul,
908    checked_mul
909);
910derive_arith!(
911    i256,
912    Div,
913    DivAssign,
914    div,
915    div_assign,
916    wrapping_div,
917    checked_div
918);
919derive_arith!(
920    i256,
921    Rem,
922    RemAssign,
923    rem,
924    rem_assign,
925    wrapping_rem,
926    checked_rem
927);
928
929impl Neg for i256 {
930    type Output = i256;
931
932    #[cfg(debug_assertions)]
933    fn neg(self) -> Self::Output {
934        self.checked_neg().expect("i256 overflow")
935    }
936
937    #[cfg(not(debug_assertions))]
938    fn neg(self) -> Self::Output {
939        self.wrapping_neg()
940    }
941}
942
943impl BitAnd for i256 {
944    type Output = i256;
945
946    #[inline]
947    fn bitand(self, rhs: Self) -> Self::Output {
948        Self {
949            low: self.low & rhs.low,
950            high: self.high & rhs.high,
951        }
952    }
953}
954
955impl BitOr for i256 {
956    type Output = i256;
957
958    #[inline]
959    fn bitor(self, rhs: Self) -> Self::Output {
960        Self {
961            low: self.low | rhs.low,
962            high: self.high | rhs.high,
963        }
964    }
965}
966
967impl BitXor for i256 {
968    type Output = i256;
969
970    #[inline]
971    fn bitxor(self, rhs: Self) -> Self::Output {
972        Self {
973            low: self.low ^ rhs.low,
974            high: self.high ^ rhs.high,
975        }
976    }
977}
978
979impl Shl<u8> for i256 {
980    type Output = i256;
981
982    #[inline]
983    fn shl(self, rhs: u8) -> Self::Output {
984        if rhs == 0 {
985            self
986        } else if rhs < 128 {
987            Self {
988                high: (self.high << rhs) | (self.low >> (128 - rhs)) as i128,
989                low: self.low << rhs,
990            }
991        } else {
992            Self {
993                high: (self.low << (rhs - 128)) as i128,
994                low: 0,
995            }
996        }
997    }
998}
999
1000impl Shr<u8> for i256 {
1001    type Output = i256;
1002
1003    #[inline]
1004    fn shr(self, rhs: u8) -> Self::Output {
1005        if rhs == 0 {
1006            self
1007        } else if rhs < 128 {
1008            Self {
1009                high: self.high >> rhs,
1010                low: (self.low >> rhs) | ((self.high as u128) << (128 - rhs)),
1011            }
1012        } else {
1013            Self {
1014                high: self.high >> 127,
1015                low: (self.high >> (rhs - 128)) as u128,
1016            }
1017        }
1018    }
1019}
1020
1021impl WrappingShl for i256 {
1022    #[inline]
1023    fn wrapping_shl(&self, rhs: u32) -> i256 {
1024        // Limit shift to 256 (max valid shift for i256)
1025        (*self).shl(rhs as u8)
1026    }
1027}
1028
1029impl WrappingShr for i256 {
1030    #[inline]
1031    fn wrapping_shr(&self, rhs: u32) -> i256 {
1032        // Limit shift to 256 (max valid shift for i256)
1033        (*self).shr(rhs as u8)
1034    }
1035}
1036
1037// Define Shl<T> and Shr<T> for specified integer types using
1038// an existing Shl<u8> and Shr<u8> implementation
1039macro_rules! define_standard_shift {
1040    // Handle multiple types
1041    ($trait_name:ident, $method:ident, [$($t:ty),+]) => {
1042        $(define_standard_shift!($trait_name, $method, $t);)+
1043    };
1044    // Handle single type
1045    ($trait_name:ident, $method:ident, $t:ty) => {
1046        impl $trait_name<$t> for i256 {
1047            type Output = i256;
1048
1049            #[inline]
1050            fn $method(self, rhs: $t) -> Self::Output {
1051                let rhs = u8::try_from(rhs).expect("rhs overflow for shift");
1052                // Other possible overflows are handled by Shl<u8> implementation
1053                self.$method(rhs)
1054            }
1055        }
1056    };
1057}
1058
1059define_standard_shift!(
1060    Shl,
1061    shl,
1062    [u16, u32, u64, u128, usize, i16, i32, i64, i128, isize]
1063);
1064define_standard_shift!(
1065    Shr,
1066    shr,
1067    [u16, u32, u64, u128, usize, i16, i32, i64, i128, isize]
1068);
1069
1070macro_rules! define_as_primitive {
1071    ($native_ty:ty) => {
1072        impl AsPrimitive<i256> for $native_ty {
1073            fn as_(self) -> i256 {
1074                i256::from_i128(self as i128)
1075            }
1076        }
1077    };
1078}
1079
1080define_as_primitive!(i8);
1081define_as_primitive!(i16);
1082define_as_primitive!(i32);
1083define_as_primitive!(i64);
1084define_as_primitive!(u8);
1085define_as_primitive!(u16);
1086define_as_primitive!(u32);
1087define_as_primitive!(u64);
1088
1089impl ToPrimitive for i256 {
1090    fn to_i64(&self) -> Option<i64> {
1091        i64::try_from(i256::to_i128(*self)?).ok()
1092    }
1093
1094    fn to_f64(&self) -> Option<f64> {
1095        match *self {
1096            Self::MIN => Some(-2_f64.powi(255)),
1097            Self::ZERO => Some(0f64),
1098            Self::ONE => Some(1f64),
1099            n => Some(Self::i256_to_f64(n)),
1100        }
1101    }
1102
1103    fn to_u64(&self) -> Option<u64> {
1104        u64::try_from(i256::to_i128(*self)?).ok()
1105    }
1106}
1107
1108// num_traits checked implementations
1109
1110impl CheckedNeg for i256 {
1111    fn checked_neg(&self) -> Option<Self> {
1112        (*self).checked_neg()
1113    }
1114}
1115
1116impl CheckedAdd for i256 {
1117    fn checked_add(&self, v: &i256) -> Option<Self> {
1118        (*self).checked_add(*v)
1119    }
1120}
1121
1122impl CheckedSub for i256 {
1123    fn checked_sub(&self, v: &i256) -> Option<Self> {
1124        (*self).checked_sub(*v)
1125    }
1126}
1127
1128impl CheckedDiv for i256 {
1129    fn checked_div(&self, v: &i256) -> Option<Self> {
1130        (*self).checked_div(*v)
1131    }
1132}
1133
1134impl CheckedMul for i256 {
1135    fn checked_mul(&self, v: &i256) -> Option<Self> {
1136        (*self).checked_mul(*v)
1137    }
1138}
1139
1140impl CheckedRem for i256 {
1141    fn checked_rem(&self, v: &i256) -> Option<Self> {
1142        (*self).checked_rem(*v)
1143    }
1144}
1145
1146impl CheckedShl for i256 {
1147    fn checked_shl(&self, rhs: u32) -> Option<Self> {
1148        let rhs = u8::try_from(rhs).ok()?;
1149        Some(self.shl(rhs))
1150    }
1151}
1152
1153impl CheckedShr for i256 {
1154    fn checked_shr(&self, rhs: u32) -> Option<Self> {
1155        let rhs = u8::try_from(rhs).ok()?;
1156        Some(self.shr(rhs))
1157    }
1158}
1159
1160// num_traits wrapping implementations
1161
1162impl WrappingAdd for i256 {
1163    fn wrapping_add(&self, v: &Self) -> Self {
1164        (*self).wrapping_add(*v)
1165    }
1166}
1167
1168impl WrappingSub for i256 {
1169    fn wrapping_sub(&self, v: &Self) -> Self {
1170        (*self).wrapping_sub(*v)
1171    }
1172}
1173
1174impl WrappingMul for i256 {
1175    fn wrapping_mul(&self, v: &Self) -> Self {
1176        (*self).wrapping_mul(*v)
1177    }
1178}
1179
1180impl WrappingNeg for i256 {
1181    fn wrapping_neg(&self) -> Self {
1182        (*self).wrapping_neg()
1183    }
1184}
1185
1186// num_traits saturating implementations
1187
1188impl SaturatingAdd for i256 {
1189    fn saturating_add(&self, v: &Self) -> Self {
1190        self.checked_add(v).unwrap_or_else(|| {
1191            if v.is_negative() {
1192                i256::MIN
1193            } else {
1194                i256::MAX
1195            }
1196        })
1197    }
1198}
1199
1200impl SaturatingSub for i256 {
1201    fn saturating_sub(&self, v: &Self) -> Self {
1202        self.checked_sub(v).unwrap_or_else(|| {
1203            if v.is_negative() {
1204                i256::MAX
1205            } else {
1206                i256::MIN
1207            }
1208        })
1209    }
1210}
1211
1212impl SaturatingMul for i256 {
1213    fn saturating_mul(&self, v: &Self) -> Self {
1214        self.checked_mul(v).unwrap_or_else(|| {
1215            if v.is_negative() == self.is_negative() {
1216                i256::MAX
1217            } else {
1218                i256::MIN
1219            }
1220        })
1221    }
1222}
1223
1224impl MulAdd for i256 {
1225    type Output = i256;
1226
1227    fn mul_add(self, a: Self, b: Self) -> Self::Output {
1228        (self * a) + b
1229    }
1230}
1231
1232impl MulAddAssign for i256 {
1233    fn mul_add_assign(&mut self, a: Self, b: Self) {
1234        *self = self.mul_add(a, b)
1235    }
1236}
1237
1238impl Zero for i256 {
1239    fn zero() -> Self {
1240        i256::ZERO
1241    }
1242
1243    fn is_zero(&self) -> bool {
1244        *self == i256::ZERO
1245    }
1246}
1247
1248impl ConstZero for i256 {
1249    const ZERO: Self = i256::ZERO;
1250}
1251
1252impl One for i256 {
1253    fn one() -> Self {
1254        i256::ONE
1255    }
1256
1257    fn is_one(&self) -> bool {
1258        *self == i256::ONE
1259    }
1260}
1261
1262impl ConstOne for i256 {
1263    const ONE: Self = i256::ONE;
1264}
1265
1266impl Num for i256 {
1267    type FromStrRadixErr = ParseI256Error;
1268
1269    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
1270        if radix == 10 {
1271            str.parse()
1272        } else {
1273            // Parsing from non-10 baseseeÃŽ is not supported
1274            Err(ParseI256Error {})
1275        }
1276    }
1277}
1278
1279impl Signed for i256 {
1280    fn abs(&self) -> Self {
1281        self.wrapping_abs()
1282    }
1283
1284    fn abs_sub(&self, other: &Self) -> Self {
1285        if self > other {
1286            self.wrapping_sub(other)
1287        } else {
1288            i256::ZERO
1289        }
1290    }
1291
1292    fn signum(&self) -> Self {
1293        (*self).signum()
1294    }
1295
1296    fn is_positive(&self) -> bool {
1297        (*self).is_positive()
1298    }
1299
1300    fn is_negative(&self) -> bool {
1301        (*self).is_negative()
1302    }
1303}
1304
1305impl Bounded for i256 {
1306    fn min_value() -> Self {
1307        i256::MIN
1308    }
1309
1310    fn max_value() -> Self {
1311        i256::MAX
1312    }
1313}
1314
1315impl Not for i256 {
1316    type Output = i256;
1317
1318    #[inline]
1319    fn not(self) -> Self::Output {
1320        Self::from_parts(!self.low, !self.high)
1321    }
1322}
1323
1324#[cfg(test)]
1325mod tests {
1326    use super::*;
1327    use num_traits::Signed;
1328    use rand::{RngExt, rng};
1329
1330    #[test]
1331    fn test_signed_cmp() {
1332        let a = i256::from_parts(i128::MAX as u128, 12);
1333        let b = i256::from_parts(i128::MIN as u128, 12);
1334        assert!(a < b);
1335
1336        let a = i256::from_parts(i128::MAX as u128, 12);
1337        let b = i256::from_parts(i128::MIN as u128, -12);
1338        assert!(a > b);
1339    }
1340
1341    #[test]
1342    fn test_to_i128() {
1343        let vals = [
1344            BigInt::from_i128(-1).unwrap(),
1345            BigInt::from_i128(i128::MAX).unwrap(),
1346            BigInt::from_i128(i128::MIN).unwrap(),
1347            BigInt::from_u128(u128::MIN).unwrap(),
1348            BigInt::from_u128(u128::MAX).unwrap(),
1349        ];
1350
1351        for v in vals {
1352            let (t, overflow) = i256::from_bigint_with_overflow(v.clone());
1353            assert!(!overflow);
1354            assert_eq!(t.to_i128(), v.to_i128(), "{v} vs {t}");
1355        }
1356    }
1357
1358    /// Tests operations against the two provided [`i256`]
1359    fn test_ops(il: i256, ir: i256) {
1360        let bl = BigInt::from_signed_bytes_le(&il.to_le_bytes());
1361        let br = BigInt::from_signed_bytes_le(&ir.to_le_bytes());
1362
1363        // Comparison
1364        assert_eq!(il.cmp(&ir), bl.cmp(&br), "{bl} cmp {br}");
1365
1366        // Conversions
1367        assert_eq!(i256::from_le_bytes(il.to_le_bytes()), il);
1368        assert_eq!(i256::from_be_bytes(il.to_be_bytes()), il);
1369        assert_eq!(i256::from_le_bytes(ir.to_le_bytes()), ir);
1370        assert_eq!(i256::from_be_bytes(ir.to_be_bytes()), ir);
1371
1372        // To i128
1373        assert_eq!(il.to_i128(), bl.to_i128(), "{bl}");
1374        assert_eq!(ir.to_i128(), br.to_i128(), "{br}");
1375
1376        // Absolute value
1377        let (abs, overflow) = i256::from_bigint_with_overflow(bl.abs());
1378        assert_eq!(il.wrapping_abs(), abs);
1379        assert_eq!(il.checked_abs().is_none(), overflow);
1380
1381        let (abs, overflow) = i256::from_bigint_with_overflow(br.abs());
1382        assert_eq!(ir.wrapping_abs(), abs);
1383        assert_eq!(ir.checked_abs().is_none(), overflow);
1384
1385        // Negation
1386        let (neg, overflow) = i256::from_bigint_with_overflow(bl.clone().neg());
1387        assert_eq!(il.wrapping_neg(), neg);
1388        assert_eq!(il.checked_neg().is_none(), overflow);
1389
1390        // Negation
1391        let (neg, overflow) = i256::from_bigint_with_overflow(br.clone().neg());
1392        assert_eq!(ir.wrapping_neg(), neg);
1393        assert_eq!(ir.checked_neg().is_none(), overflow);
1394
1395        // Addition
1396        let actual = il.wrapping_add(ir);
1397        let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() + br.clone());
1398        assert_eq!(actual, expected);
1399        assert_eq!(il.overflowing_add(ir), (expected, overflow));
1400
1401        let checked = il.checked_add(ir);
1402        match overflow {
1403            true => assert!(checked.is_none()),
1404            false => assert_eq!(checked, Some(actual)),
1405        }
1406
1407        // Subtraction
1408        let actual = il.wrapping_sub(ir);
1409        let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() - br.clone());
1410        assert_eq!(actual.to_string(), expected.to_string());
1411        assert_eq!(il.overflowing_sub(ir), (expected, overflow));
1412
1413        let checked = il.checked_sub(ir);
1414        match overflow {
1415            true => assert!(checked.is_none()),
1416            false => assert_eq!(checked, Some(actual), "{bl} - {br} = {expected}"),
1417        }
1418
1419        // Multiplication
1420        let actual = il.wrapping_mul(ir);
1421        let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone() * br.clone());
1422        assert_eq!(actual.to_string(), expected.to_string());
1423
1424        let checked = il.checked_mul(ir);
1425        match overflow {
1426            true => assert!(
1427                checked.is_none(),
1428                "{il} * {ir} = {actual} vs {bl} * {br} = {expected}"
1429            ),
1430            false => assert_eq!(
1431                checked,
1432                Some(actual),
1433                "{il} * {ir} = {actual} vs {bl} * {br} = {expected}"
1434            ),
1435        }
1436
1437        // Division
1438        if ir != i256::ZERO {
1439            let actual = il.wrapping_div(ir);
1440            let expected = bl.clone() / br.clone();
1441            let checked = il.checked_div(ir);
1442
1443            if ir == i256::MINUS_ONE && il == i256::MIN {
1444                // BigInt produces an integer over i256::MAX
1445                assert_eq!(actual, i256::MIN);
1446                assert!(checked.is_none());
1447            } else {
1448                assert_eq!(actual.to_string(), expected.to_string());
1449                assert_eq!(checked.unwrap().to_string(), expected.to_string());
1450            }
1451        } else {
1452            // `wrapping_div` panics on division by zero
1453            assert!(il.checked_div(ir).is_none());
1454        }
1455
1456        // Remainder
1457        if ir != i256::ZERO {
1458            let actual = il.wrapping_rem(ir);
1459            let expected = bl.clone() % br.clone();
1460            let checked = il.checked_rem(ir);
1461
1462            assert_eq!(actual.to_string(), expected.to_string(), "{il} % {ir}");
1463
1464            if ir == i256::MINUS_ONE && il == i256::MIN {
1465                assert!(checked.is_none());
1466            } else {
1467                assert_eq!(checked.unwrap().to_string(), expected.to_string());
1468            }
1469        } else {
1470            // `wrapping_rem` panics on division by zero
1471            assert!(il.checked_rem(ir).is_none());
1472        }
1473
1474        // Exponentiation
1475        for exp in [0, 1, 2, 3, 8, 100] {
1476            let actual = il.wrapping_pow(exp);
1477            let (expected, overflow) = i256::from_bigint_with_overflow(bl.clone().pow(exp));
1478            assert_eq!(actual.to_string(), expected.to_string());
1479
1480            let checked = il.checked_pow(exp);
1481            match overflow {
1482                true => assert!(
1483                    checked.is_none(),
1484                    "{il} ^ {exp} = {actual} vs {bl} * {exp} = {expected}"
1485                ),
1486                false => assert_eq!(
1487                    checked,
1488                    Some(actual),
1489                    "{il} ^ {exp} = {actual} vs {bl} ^ {exp} = {expected}"
1490                ),
1491            }
1492        }
1493
1494        // Bit operations
1495        let actual = il & ir;
1496        let (expected, _) = i256::from_bigint_with_overflow(bl.clone() & br.clone());
1497        assert_eq!(actual.to_string(), expected.to_string());
1498
1499        let actual = il | ir;
1500        let (expected, _) = i256::from_bigint_with_overflow(bl.clone() | br.clone());
1501        assert_eq!(actual.to_string(), expected.to_string());
1502
1503        let actual = il ^ ir;
1504        let (expected, _) = i256::from_bigint_with_overflow(bl.clone() ^ br);
1505        assert_eq!(actual.to_string(), expected.to_string());
1506
1507        for shift in [0_u8, 1, 4, 126, 128, 129, 254, 255] {
1508            let actual = il << shift;
1509            let (expected, _) = i256::from_bigint_with_overflow(bl.clone() << shift);
1510            assert_eq!(actual.to_string(), expected.to_string());
1511
1512            let wrapping_actual = <i256 as WrappingShl>::wrapping_shl(&il, shift as u32);
1513            assert_eq!(wrapping_actual.to_string(), expected.to_string());
1514
1515            let actual = il >> shift;
1516            let (expected, _) = i256::from_bigint_with_overflow(bl.clone() >> shift);
1517            assert_eq!(actual.to_string(), expected.to_string());
1518
1519            let wrapping_actual = <i256 as WrappingShr>::wrapping_shr(&il, shift as u32);
1520            assert_eq!(wrapping_actual.to_string(), expected.to_string());
1521
1522            // Check wrapping of the shift argument
1523            let wrapping_actual = <i256 as WrappingShr>::wrapping_shr(&il, 512 + shift as u32);
1524            assert_eq!(wrapping_actual.to_string(), expected.to_string());
1525        }
1526    }
1527
1528    #[test]
1529    fn test_overflowing_add() {
1530        const POSITIVE_OVERFLOW: (i256, bool) = i256::MAX.overflowing_add(i256::ONE);
1531        const NEGATIVE_OVERFLOW: (i256, bool) = i256::MIN.overflowing_add(i256::MINUS_ONE);
1532
1533        assert_eq!(POSITIVE_OVERFLOW, (i256::MIN, true));
1534        assert_eq!(NEGATIVE_OVERFLOW, (i256::MAX, true));
1535        assert_eq!(
1536            i256::from_parts(u128::MAX, 0).overflowing_add(i256::ONE),
1537            (i256::from_parts(0, 1), false)
1538        );
1539        assert_eq!(
1540            i256::ONE.overflowing_add(i256::from_i128(2)),
1541            (i256::from_i128(3), false)
1542        );
1543    }
1544
1545    #[test]
1546    fn test_overflowing_sub() {
1547        const NEGATIVE_OVERFLOW: (i256, bool) = i256::MIN.overflowing_sub(i256::ONE);
1548        const POSITIVE_OVERFLOW: (i256, bool) = i256::MAX.overflowing_sub(i256::MINUS_ONE);
1549
1550        assert_eq!(NEGATIVE_OVERFLOW, (i256::MAX, true));
1551        assert_eq!(POSITIVE_OVERFLOW, (i256::MIN, true));
1552        assert_eq!(
1553            i256::from_parts(0, 1).overflowing_sub(i256::ONE),
1554            (i256::from_parts(u128::MAX, 0), false)
1555        );
1556        assert_eq!(
1557            i256::from_i128(3).overflowing_sub(i256::from_i128(2)),
1558            (i256::ONE, false)
1559        );
1560    }
1561
1562    #[test]
1563    #[cfg_attr(miri, ignore)] // Takes too long
1564    fn test_i256() {
1565        let candidates = [
1566            i256::ZERO,
1567            i256::ONE,
1568            i256::MINUS_ONE,
1569            ConstZero::ZERO,
1570            ConstOne::ONE,
1571            i256::from_i128(2),
1572            i256::from_i128(-2),
1573            i256::from_parts(u128::MAX, 1),
1574            i256::from_parts(u128::MAX, -1),
1575            i256::from_parts(0, 1),
1576            i256::from_parts(0, -1),
1577            i256::from_parts(1, -1),
1578            i256::from_parts(1, 1),
1579            i256::from_parts(0, i128::MAX),
1580            i256::from_parts(0, i128::MIN),
1581            i256::from_parts(1, i128::MAX),
1582            i256::from_parts(1, i128::MIN),
1583            i256::from_parts(u128::MAX, i128::MIN),
1584            i256::from_parts(100, 32),
1585            i256::MIN,
1586            i256::MAX,
1587            i256::MIN >> 1,
1588            i256::MAX >> 1,
1589            i256::ONE << 127,
1590            i256::ONE << 128,
1591            i256::ONE << 129,
1592            i256::MINUS_ONE << 127,
1593            i256::MINUS_ONE << 128,
1594            i256::MINUS_ONE << 129,
1595        ];
1596
1597        for il in candidates {
1598            for ir in candidates {
1599                test_ops(il, ir)
1600            }
1601        }
1602    }
1603
1604    #[test]
1605    fn test_signed_ops() {
1606        // signum
1607        assert_eq!(i256::from_i128(1).signum(), i256::ONE);
1608        assert_eq!(i256::from_i128(0).signum(), i256::ZERO);
1609        assert_eq!(i256::from_i128(-0).signum(), i256::ZERO);
1610        assert_eq!(i256::from_i128(-1).signum(), i256::MINUS_ONE);
1611
1612        // is_positive
1613        assert!(i256::from_i128(1).is_positive());
1614        assert!(!i256::from_i128(0).is_positive());
1615        assert!(!i256::from_i128(-0).is_positive());
1616        assert!(!i256::from_i128(-1).is_positive());
1617
1618        // is_negative
1619        assert!(!i256::from_i128(1).is_negative());
1620        assert!(!i256::from_i128(0).is_negative());
1621        assert!(!i256::from_i128(-0).is_negative());
1622        assert!(i256::from_i128(-1).is_negative());
1623    }
1624
1625    #[test]
1626    #[cfg_attr(miri, ignore)] // Takes too long
1627    fn test_i256_fuzz() {
1628        let mut rng = rng();
1629
1630        for _ in 0..1000 {
1631            let mut l = [0_u8; 32];
1632            let len = rng.random_range(0..32);
1633            l.iter_mut().take(len).for_each(|x| *x = rng.random());
1634
1635            let mut r = [0_u8; 32];
1636            let len = rng.random_range(0..32);
1637            r.iter_mut().take(len).for_each(|x| *x = rng.random());
1638
1639            test_ops(i256::from_le_bytes(l), i256::from_le_bytes(r))
1640        }
1641    }
1642
1643    #[test]
1644    fn test_i256_to_primitive() {
1645        let a = i256::MAX;
1646        assert!(a.to_i64().is_none());
1647        assert!(a.to_u64().is_none());
1648
1649        let a = i256::from_i128(i128::MAX);
1650        assert!(a.to_i64().is_none());
1651        assert!(a.to_u64().is_none());
1652
1653        let a = i256::from_i128(i64::MAX as i128);
1654        assert_eq!(a.to_i64().unwrap(), i64::MAX);
1655        assert_eq!(a.to_u64().unwrap(), i64::MAX as u64);
1656
1657        let a = i256::from_i128(i64::MAX as i128 + 1);
1658        assert!(a.to_i64().is_none());
1659        assert_eq!(a.to_u64().unwrap(), i64::MAX as u64 + 1);
1660
1661        let a = i256::MIN;
1662        assert!(a.to_i64().is_none());
1663        assert!(a.to_u64().is_none());
1664
1665        let a = i256::from_i128(i128::MIN);
1666        assert!(a.to_i64().is_none());
1667        assert!(a.to_u64().is_none());
1668
1669        let a = i256::from_i128(i64::MIN as i128);
1670        assert_eq!(a.to_i64().unwrap(), i64::MIN);
1671        assert!(a.to_u64().is_none());
1672
1673        let a = i256::from_i128(i64::MIN as i128 - 1);
1674        assert!(a.to_i64().is_none());
1675        assert!(a.to_u64().is_none());
1676
1677        // values whose two 64-bit halves agree in sign but exceed i64/u64
1678        // https://github.com/apache/arrow-rs/issues/10855
1679        let a = i256::from_i128((1i128 << 64) + 5);
1680        assert!(a.to_i64().is_none());
1681        assert!(a.to_u64().is_none());
1682        assert!(a.to_i32().is_none());
1683        assert!(a.to_i8().is_none());
1684
1685        let a = i256::from_i128(-((1i128 << 64) + 5));
1686        assert!(a.to_i64().is_none());
1687        assert!(a.to_u64().is_none());
1688        assert!(a.to_i32().is_none());
1689        assert!(a.to_i8().is_none());
1690
1691        let a = i256::from_i128(u64::MAX as i128);
1692        assert!(a.to_i64().is_none());
1693        assert_eq!(a.to_u64().unwrap(), u64::MAX);
1694
1695        let a = i256::from_parts(5, 1);
1696        assert!(a.to_i64().is_none());
1697        assert!(a.to_u64().is_none());
1698
1699        let a = i256::from_parts(u64::MAX as u128 + 5, 0);
1700        assert!(a.to_i64().is_none());
1701        assert!(a.to_u64().is_none());
1702    }
1703
1704    #[test]
1705    fn test_i256_as_i128() {
1706        let a = i256::from_i128(i128::MAX).wrapping_add(i256::from_i128(1));
1707        let i128 = a.as_i128();
1708        assert_eq!(i128, i128::MIN);
1709
1710        let a = i256::from_i128(i128::MAX).wrapping_add(i256::from_i128(2));
1711        let i128 = a.as_i128();
1712        assert_eq!(i128, i128::MIN + 1);
1713
1714        let a = i256::from_i128(i128::MIN).wrapping_sub(i256::from_i128(1));
1715        let i128 = a.as_i128();
1716        assert_eq!(i128, i128::MAX);
1717
1718        let a = i256::from_i128(i128::MIN).wrapping_sub(i256::from_i128(2));
1719        let i128 = a.as_i128();
1720        assert_eq!(i128, i128::MAX - 1);
1721    }
1722
1723    #[test]
1724    fn test_string_roundtrip() {
1725        let roundtrip_cases = [
1726            i256::ZERO,
1727            i256::ONE,
1728            i256::MINUS_ONE,
1729            i256::from_i128(123456789),
1730            i256::from_i128(-123456789),
1731            i256::from_i128(i128::MIN),
1732            i256::from_i128(i128::MAX),
1733            i256::MIN,
1734            i256::MAX,
1735        ];
1736        for case in roundtrip_cases {
1737            let formatted = case.to_string();
1738            let back: i256 = formatted.parse().unwrap();
1739            assert_eq!(case, back);
1740        }
1741    }
1742
1743    #[test]
1744    fn test_from_string() {
1745        let cases = [
1746            (
1747                "000000000000000000000000000000000000000011",
1748                Some(i256::from_i128(11)),
1749            ),
1750            (
1751                "-000000000000000000000000000000000000000011",
1752                Some(i256::from_i128(-11)),
1753            ),
1754            (
1755                "-0000000000000000000000000000000000000000123456789",
1756                Some(i256::from_i128(-123456789)),
1757            ),
1758            ("-", None),
1759            ("+", None),
1760            ("--1", None),
1761            ("-+1", None),
1762            ("000000000000000000000000000000000000000", Some(i256::ZERO)),
1763            ("0000000000000000000000000000000000000000-11", None),
1764            ("11-1111111111111111111111111111111111111", None),
1765            (
1766                "115792089237316195423570985008687907853269984665640564039457584007913129639936",
1767                None,
1768            ),
1769        ];
1770        for (case, expected) in cases {
1771            assert_eq!(i256::from_string(case), expected)
1772        }
1773    }
1774
1775    #[expect(clippy::op_ref)]
1776    fn test_reference_op(il: i256, ir: i256) {
1777        let r1 = il + ir;
1778        let r2 = &il + ir;
1779        let r3 = il + &ir;
1780        let r4 = &il + &ir;
1781        assert_eq!(r1, r2);
1782        assert_eq!(r1, r3);
1783        assert_eq!(r1, r4);
1784
1785        let r1 = il - ir;
1786        let r2 = &il - ir;
1787        let r3 = il - &ir;
1788        let r4 = &il - &ir;
1789        assert_eq!(r1, r2);
1790        assert_eq!(r1, r3);
1791        assert_eq!(r1, r4);
1792
1793        let r1 = il * ir;
1794        let r2 = &il * ir;
1795        let r3 = il * &ir;
1796        let r4 = &il * &ir;
1797        assert_eq!(r1, r2);
1798        assert_eq!(r1, r3);
1799        assert_eq!(r1, r4);
1800
1801        let r1 = il / ir;
1802        let r2 = &il / ir;
1803        let r3 = il / &ir;
1804        let r4 = &il / &ir;
1805        assert_eq!(r1, r2);
1806        assert_eq!(r1, r3);
1807        assert_eq!(r1, r4);
1808    }
1809
1810    #[test]
1811    fn test_i256_reference_op() {
1812        let candidates = [
1813            i256::ONE,
1814            i256::MINUS_ONE,
1815            i256::from_i128(2),
1816            i256::from_i128(-2),
1817            i256::from_i128(3),
1818            i256::from_i128(-3),
1819        ];
1820
1821        for il in candidates {
1822            for ir in candidates {
1823                test_reference_op(il, ir)
1824            }
1825        }
1826    }
1827
1828    #[test]
1829    fn test_decimal256_to_f64_typical_values() {
1830        let v = i256::from_i128(42_i128);
1831        assert_eq!(v.to_f64().unwrap(), 42.0);
1832
1833        let v = i256::from_i128(-123456789012345678i128);
1834        assert_eq!(v.to_f64().unwrap(), -123_456_789_012_345_680.0);
1835
1836        let v = i256::from_string("0").unwrap();
1837        assert_eq!(v.to_f64().unwrap(), 0.0);
1838
1839        let v = i256::from_string("1").unwrap();
1840        assert_eq!(v.to_f64().unwrap(), 1.0);
1841
1842        let mut rng = rng();
1843        for _ in 0..10 {
1844            let f64_value =
1845                (rng.random_range(i128::MIN..i128::MAX) as f64) * rng.random_range(0.0..1.0);
1846            let big = i256::from_f64(f64_value).unwrap();
1847            assert_eq!(big.to_f64().unwrap(), f64_value);
1848        }
1849    }
1850
1851    #[test]
1852    fn test_decimal256_to_f64_large_positive_value() {
1853        let max_f = f64::MAX;
1854        let big = i256::from_f64(max_f * 2.0).unwrap_or(i256::MAX);
1855        let out = big.to_f64().unwrap();
1856        assert!(out.is_finite() && out.is_sign_positive());
1857    }
1858
1859    #[test]
1860    fn test_decimal256_to_f64_large_negative_value() {
1861        let max_f = f64::MAX;
1862        let big_neg = i256::from_f64(-(max_f * 2.0)).unwrap_or(i256::MIN);
1863        let out = big_neg.to_f64().unwrap();
1864        assert!(out.is_finite() && out.is_sign_negative());
1865    }
1866
1867    #[test]
1868    fn test_num_traits() {
1869        let value = i256::from_i128(-5);
1870        assert_eq!(
1871            <i256 as CheckedNeg>::checked_neg(&value),
1872            Some(i256::from(5))
1873        );
1874
1875        assert_eq!(
1876            <i256 as CheckedAdd>::checked_add(&value, &value),
1877            Some(i256::from(-10))
1878        );
1879
1880        assert_eq!(
1881            <i256 as CheckedSub>::checked_sub(&value, &value),
1882            Some(i256::from(0))
1883        );
1884
1885        assert_eq!(
1886            <i256 as CheckedMul>::checked_mul(&value, &value),
1887            Some(i256::from(25))
1888        );
1889
1890        assert_eq!(
1891            <i256 as CheckedDiv>::checked_div(&value, &value),
1892            Some(i256::from(1))
1893        );
1894
1895        assert_eq!(
1896            <i256 as CheckedRem>::checked_rem(&value, &value),
1897            Some(i256::from(0))
1898        );
1899
1900        assert_eq!(
1901            <i256 as WrappingAdd>::wrapping_add(&value, &value),
1902            i256::from(-10)
1903        );
1904
1905        assert_eq!(
1906            <i256 as WrappingSub>::wrapping_sub(&value, &value),
1907            i256::from(0)
1908        );
1909
1910        assert_eq!(
1911            <i256 as WrappingMul>::wrapping_mul(&value, &value),
1912            i256::from(25)
1913        );
1914
1915        assert_eq!(<i256 as WrappingNeg>::wrapping_neg(&value), i256::from(5));
1916
1917        // A single check for wrapping behavior, rely on trait implementation for others
1918        let result = <i256 as WrappingAdd>::wrapping_add(&i256::MAX, &i256::ONE);
1919        assert_eq!(result, i256::MIN);
1920
1921        // Saturating operations
1922        assert_eq!(i256::MAX.saturating_add(&i256::ONE), i256::MAX);
1923        assert_eq!(i256::MIN.saturating_sub(&i256::ONE), i256::MIN);
1924        assert_eq!(i256::MIN.saturating_add(&i256::MINUS_ONE), i256::MIN);
1925        assert_eq!(i256::MAX.saturating_sub(&i256::MINUS_ONE), i256::MAX);
1926        assert_eq!(i256::MAX.saturating_mul(&i256::MAX), i256::MAX);
1927        assert_eq!(i256::MAX.saturating_mul(&i256::MIN), i256::MIN);
1928        assert_eq!(i256::MIN.saturating_mul(&i256::MAX), i256::MIN);
1929        assert_eq!(i256::MIN.saturating_mul(&i256::MIN), i256::MAX);
1930        assert_eq!(i256::MIN.saturating_mul(&i256::ONE), i256::MIN);
1931        assert_eq!(i256::MIN.saturating_mul(&i256::MINUS_ONE), i256::MAX);
1932        assert_eq!(
1933            i256::from(20).saturating_add(&i256::from(5)),
1934            i256::from(25)
1935        );
1936        assert_eq!(
1937            i256::from(20).saturating_sub(&i256::from(5)),
1938            i256::from(15)
1939        );
1940        assert_eq!(
1941            i256::from(20).saturating_mul(&i256::from(5)),
1942            i256::from(100)
1943        );
1944
1945        // Mul-add
1946        assert_eq!(
1947            i256::from(20).mul_add(i256::from(5), i256::from(10)),
1948            i256::from(110)
1949        );
1950
1951        let mut mul_add_value = i256::from(20);
1952        mul_add_value.mul_add_assign(i256::from(5), i256::from(10));
1953        assert_eq!(mul_add_value, i256::from(110));
1954
1955        let value = i256::from(-5);
1956        assert_eq!(<i256 as Signed>::abs(&value), i256::from(5));
1957
1958        assert_eq!(<i256 as One>::one(), i256::from(1));
1959        assert_eq!(<i256 as Zero>::zero(), i256::from(0));
1960
1961        assert_eq!(<i256 as Bounded>::min_value(), i256::MIN);
1962        assert_eq!(<i256 as Bounded>::max_value(), i256::MAX);
1963
1964        // Bitwise not
1965        assert_eq!(!i256::ZERO, i256::MINUS_ONE);
1966        assert_eq!(!i256::MINUS_ONE, i256::ZERO);
1967        assert_eq!(!i256::ONE, i256::from_parts(u128::MAX - 1, -1));
1968    }
1969
1970    #[should_panic(expected = "rhs overflow for shift")]
1971    #[test]
1972    fn test_shl_panic_on_arg_overflow() {
1973        let value = i256::from(123);
1974        let rhs = std::hint::black_box(500);
1975        let _ = value << rhs;
1976    }
1977
1978    #[test]
1979    fn test_numtraits_from_str_radix() {
1980        assert_eq!(
1981            i256::from_str_radix("123456789", 10).expect("parsed"),
1982            i256::from(123456789)
1983        );
1984        assert_eq!(
1985            i256::from_str_radix("0", 10).expect("parsed"),
1986            i256::from(0)
1987        );
1988        assert!(i256::from_str_radix("abc", 10).is_err());
1989        assert!(i256::from_str_radix("0", 16).is_err());
1990    }
1991
1992    #[test]
1993    fn test_leading_zeros() {
1994        // Without high part
1995        assert_eq!(i256::from(0).leading_zeros(), 256);
1996        assert_eq!(i256::from(1).leading_zeros(), 256 - 1);
1997        assert_eq!(i256::from(16).leading_zeros(), 256 - 5);
1998        assert_eq!(i256::from(17).leading_zeros(), 256 - 5);
1999
2000        // With high part
2001        assert_eq!(i256::from_parts(2, 16).leading_zeros(), 128 - 5);
2002        assert_eq!(i256::from_parts(2, i128::MAX).leading_zeros(), 1);
2003
2004        assert_eq!(i256::MAX.leading_zeros(), 1);
2005        assert_eq!(i256::from(-1).leading_zeros(), 0);
2006    }
2007
2008    #[test]
2009    fn test_trailing_zeros() {
2010        // Without high part
2011        assert_eq!(i256::from(0).trailing_zeros(), 256);
2012        assert_eq!(i256::from(2).trailing_zeros(), 1);
2013        assert_eq!(i256::from(16).trailing_zeros(), 4);
2014        assert_eq!(i256::from(17).trailing_zeros(), 0);
2015        // With high part
2016        assert_eq!(i256::from_parts(0, i128::MAX).trailing_zeros(), 128);
2017        assert_eq!(i256::from_parts(0, 16).trailing_zeros(), 128 + 4);
2018        assert_eq!(i256::from_parts(2, i128::MAX).trailing_zeros(), 1);
2019
2020        assert_eq!(i256::MAX.trailing_zeros(), 0);
2021        assert_eq!(i256::from(-1).trailing_zeros(), 0);
2022    }
2023
2024    #[test]
2025    fn test_ilog() {
2026        let value = i256::from(128);
2027
2028        // log2
2029        assert_eq!(value.ilog(i256::from(2)), 7);
2030        assert_eq!(value.ilog2(), 7);
2031
2032        // log10
2033        assert_eq!(value.ilog(i256::from(10)), 2);
2034        assert_eq!(value.ilog10(), 2);
2035
2036        // negative base
2037        assert_eq!(value.checked_ilog(i256::from(-2)), None);
2038        assert_eq!(value.checked_ilog(i256::from(-10)), None);
2039        assert_eq!(value.checked_ilog(i256::from(0)), None);
2040        assert_eq!(value.checked_ilog(i256::from(1)), None);
2041
2042        // negative self
2043        let neg_value = i256::from(-128);
2044        assert_eq!(neg_value.checked_ilog(i256::from(2)), None);
2045        assert_eq!(neg_value.checked_ilog(i256::from(10)), None);
2046        assert_eq!(neg_value.checked_ilog10(), None);
2047        assert_eq!(neg_value.checked_ilog2(), None);
2048
2049        // zero self
2050        assert_eq!(i256::ZERO.checked_ilog(i256::from(2)), None);
2051        assert_eq!(i256::ZERO.checked_ilog(i256::from(10)), None);
2052        assert_eq!(i256::ZERO.checked_ilog10(), None);
2053        assert_eq!(i256::ZERO.checked_ilog2(), None);
2054
2055        // self == base, matches std: `n.ilog(n) == 1`
2056        assert_eq!(i256::from(2).checked_ilog(i256::from(2)), Some(1));
2057        assert_eq!(i256::from(3).checked_ilog(i256::from(3)), Some(1));
2058        assert_eq!(i256::from(5).checked_ilog(i256::from(5)), Some(1));
2059        assert_eq!(i256::from(1000).checked_ilog(i256::from(1000)), Some(1));
2060        assert_eq!(i256::from(2).checked_ilog2(), Some(1));
2061        assert_eq!(i256::from(2).ilog2(), 1);
2062        // base 10 goes through the checked_ilog10 fast path
2063        assert_eq!(i256::from(10).checked_ilog(i256::from(10)), Some(1));
2064
2065        // self < base is 0
2066        assert_eq!(i256::from(3).checked_ilog(i256::from(5)), Some(0));
2067
2068        // cross-check small results (0 and 1) against u128::ilog
2069        for base in [2i64, 3, 5, 7, 1000] {
2070            for v in 1i64..64 {
2071                let want = (v as u128).ilog(base as u128);
2072                assert_eq!(
2073                    i256::from(v).checked_ilog(i256::from(base)),
2074                    Some(want),
2075                    "checked_ilog({v}, {base})"
2076                );
2077            }
2078        }
2079
2080        let value = i256::from_parts(100000000, 1234);
2081        assert_eq!(value.checked_ilog(i256::from(10)), Some(41));
2082        assert_eq!(value.checked_ilog10(), Some(41));
2083
2084        // Large i256 values
2085        let large = i256::from_parts(100000000, i128::MAX);
2086        // log2 of 2 powered to approximately 255 should be 254
2087        assert_eq!(large.checked_ilog(i256::from(2)), Some(254));
2088
2089        // log10(large)=76
2090        assert_eq!(large.checked_ilog(i256::from(10)), Some(76));
2091        assert_eq!(large.checked_ilog10(), Some(76));
2092
2093        // log5(large)
2094        assert_eq!(large.checked_ilog(i256::from(5)), Some(109));
2095
2096        // Maximum representable value is 2^254
2097        assert!(i256::from(2).checked_pow(255).is_none());
2098        let value = i256::from(2).checked_pow(254).expect("construct");
2099        assert_eq!(value.checked_ilog(i256::from(2)), Some(254));
2100
2101        // Logarithm of a maximum representable value is 254
2102        assert_eq!(i256::MAX.checked_ilog(i256::from(2)), Some(254));
2103    }
2104
2105    #[test]
2106    fn test_ilog10() {
2107        // Edge cases
2108        assert_eq!(i256::ZERO.checked_ilog10(), None);
2109        assert_eq!(i256::MINUS_ONE.checked_ilog10(), None);
2110        assert_eq!(i256::MAX.checked_ilog10(), Some(76));
2111        assert_eq!(i256::from(10).checked_ilog10(), Some(1));
2112
2113        // small values
2114        assert_eq!(i256::from(1).checked_ilog10(), Some(0));
2115        assert_eq!(i256::from(9).checked_ilog10(), Some(0));
2116
2117        // case with high == 0
2118        assert_eq!(i256::from(100).checked_ilog10(), Some(2));
2119        // case with high == 0 and full low
2120        assert_eq!(i256::from_parts(u128::MAX, 0).checked_ilog10(), Some(38));
2121
2122        // case with high > 0
2123        assert_eq!(i256::from_parts(0, 1).checked_ilog10(), Some(38));
2124
2125        // case with non-null high and low, slow branch
2126        let pow50 = i256::from(10).checked_pow(50).unwrap();
2127        assert_eq!(pow50.checked_ilog10(), Some(50));
2128
2129        // case with non-null high and low, fast branch
2130        let pow64 = i256::from(10).checked_pow(64).unwrap();
2131        assert_eq!(pow64.checked_ilog10(), Some(64));
2132    }
2133
2134    #[test]
2135    #[should_panic(expected = "ilog10 overflow")]
2136    fn test_ilog10_zero_panics() {
2137        let _ = i256::ZERO.ilog10();
2138    }
2139
2140    #[test]
2141    #[should_panic(expected = "ilog overflow")]
2142    fn test_ilog_zero_panics() {
2143        let _ = i256::ZERO.ilog(i256::from(5));
2144    }
2145
2146    #[test]
2147    #[should_panic(expected = "ilog2 overflow")]
2148    fn test_ilog2_zero_panics() {
2149        let _ = i256::ZERO.ilog2();
2150    }
2151}