Skip to main content

arrow_array/
arithmetic.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5use arrow_buffer::{ArrowNativeType, IntervalDayTime, IntervalMonthDayNano, i256};
6use arrow_schema::ArrowError;
7use half::f16;
8use num_complex::ComplexFloat;
9use std::cmp::Ordering;
10
11/// Trait for [`ArrowNativeType`] that adds checked and unchecked arithmetic operations,
12/// and totally ordered comparison operations
13///
14/// The APIs with `_wrapping` suffix do not perform overflow-checking. For integer
15/// types they will wrap around the boundary of the type. For floating point types they
16/// will overflow to INF or -INF preserving the expected sign value
17///
18/// Note `div_wrapping`, `mod_wrapping` and `div_rem_wrapping` will panic for integer types if
19/// `rhs` is zero, although this may be subject to change
20/// <https://github.com/apache/arrow-rs/issues/2647>
21///
22/// The APIs with `_checked` suffix perform overflow-checking. For integer types
23/// these will return `Err` instead of wrapping. For floating point types they will
24/// overflow to INF or -INF preserving the expected sign value
25///
26/// Comparison of integer types is as per normal integer comparison rules, floating
27/// point values are compared as per IEEE 754's totalOrder predicate see [`f32::total_cmp`]
28///
29pub trait ArrowNativeTypeOp: ArrowNativeType {
30    /// The additive identity
31    const ZERO: Self;
32
33    /// The multiplicative identity
34    const ONE: Self;
35
36    /// The minimum value and identity for the `max` aggregation.
37    /// Note that the aggregation uses the total order predicate for floating point values,
38    /// which means that this value is a negative NaN.
39    const MIN_TOTAL_ORDER: Self;
40
41    /// The maximum value and identity for the `min` aggregation.
42    /// Note that the aggregation uses the total order predicate for floating point values,
43    /// which means that this value is a positive NaN.
44    const MAX_TOTAL_ORDER: Self;
45
46    /// Checked addition operation
47    fn add_checked(self, rhs: Self) -> Result<Self, ArrowError>;
48
49    /// Wrapping addition operation
50    fn add_wrapping(self, rhs: Self) -> Self;
51
52    /// Checked subtraction operation
53    fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError>;
54
55    /// Wrapping subtraction operation
56    fn sub_wrapping(self, rhs: Self) -> Self;
57
58    /// Checked multiplication operation
59    fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError>;
60
61    /// Wrapping multiplication operation
62    fn mul_wrapping(self, rhs: Self) -> Self;
63
64    /// Checked division operation
65    fn div_checked(self, rhs: Self) -> Result<Self, ArrowError>;
66
67    /// Wrapping division operation
68    ///
69    /// # Panics
70    ///
71    /// Panics if `rhs` is zero for integer types
72    fn div_wrapping(self, rhs: Self) -> Self;
73
74    /// Checked remainder operation
75    fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError>;
76
77    /// Wrapping remainder operation
78    ///
79    /// # Panics
80    ///
81    /// Panics if `rhs` is zero for integer types
82    fn mod_wrapping(self, rhs: Self) -> Self;
83
84    /// Checked division and remainder operation, returning `(quotient, remainder)`
85    ///
86    /// Returns the same results as [`Self::div_checked`] and [`Self::mod_checked`]. `i256`
87    /// computes both with one division.
88    ///
89    /// # Example
90    /// ```
91    /// # use arrow_array::ArrowNativeTypeOp;
92    /// assert_eq!((-7_i32).div_rem_checked(2).unwrap(), (-3, -1));
93    /// assert!(7_i32.div_rem_checked(0).is_err());
94    /// assert!(i32::MIN.div_rem_checked(-1).is_err());
95    /// ```
96    #[inline]
97    fn div_rem_checked(self, rhs: Self) -> Result<(Self, Self), ArrowError> {
98        Ok((self.div_checked(rhs)?, self.mod_checked(rhs)?))
99    }
100
101    /// Wrapping division and remainder operation, returning `(quotient, remainder)`
102    ///
103    /// Returns the same results as [`Self::div_wrapping`] and [`Self::mod_wrapping`]. `i256`
104    /// computes both with one division.
105    ///
106    /// # Panics
107    ///
108    /// Panics if `rhs` is zero for integer types
109    ///
110    /// # Example
111    /// ```
112    /// # use arrow_array::ArrowNativeTypeOp;
113    /// assert_eq!((-7_i32).div_rem_wrapping(2), (-3, -1));
114    /// assert_eq!(i32::MIN.div_rem_wrapping(-1), (i32::MIN, 0));
115    /// ```
116    #[inline]
117    fn div_rem_wrapping(self, rhs: Self) -> (Self, Self) {
118        (self.div_wrapping(rhs), self.mod_wrapping(rhs))
119    }
120
121    /// Checked negation operation
122    fn neg_checked(self) -> Result<Self, ArrowError>;
123
124    /// Wrapping negation operation
125    fn neg_wrapping(self) -> Self;
126
127    /// Checked exponentiation operation
128    fn pow_checked(self, exp: u32) -> Result<Self, ArrowError>;
129
130    /// Wrapping exponentiation operation
131    fn pow_wrapping(self, exp: u32) -> Self;
132
133    /// Returns true if zero else false
134    fn is_zero(self) -> bool;
135
136    /// Compare operation
137    fn compare(self, rhs: Self) -> Ordering;
138
139    /// Equality operation
140    fn is_eq(self, rhs: Self) -> bool;
141
142    /// Not equal operation
143    #[inline]
144    fn is_ne(self, rhs: Self) -> bool {
145        !self.is_eq(rhs)
146    }
147
148    /// Less than operation
149    #[inline]
150    fn is_lt(self, rhs: Self) -> bool {
151        self.compare(rhs).is_lt()
152    }
153
154    /// Less than equals operation
155    #[inline]
156    fn is_le(self, rhs: Self) -> bool {
157        self.compare(rhs).is_le()
158    }
159
160    /// Greater than operation
161    #[inline]
162    fn is_gt(self, rhs: Self) -> bool {
163        self.compare(rhs).is_gt()
164    }
165
166    /// Greater than equals operation
167    #[inline]
168    fn is_ge(self, rhs: Self) -> bool {
169        self.compare(rhs).is_ge()
170    }
171}
172
173macro_rules! native_type_op {
174    ($t:tt) => {
175        native_type_op!($t, 0, 1);
176    };
177    ($t:tt, $zero:expr, $one: expr) => {
178        native_type_op!($t, $zero, $one, $t::MIN, $t::MAX);
179    };
180    ($t:tt, $zero:expr, $one: expr, $min: expr, $max: expr $(, $extra:item)*) => {
181        impl ArrowNativeTypeOp for $t {
182            $($extra)*
183
184            const ZERO: Self = $zero;
185            const ONE: Self = $one;
186            const MIN_TOTAL_ORDER: Self = $min;
187            const MAX_TOTAL_ORDER: Self = $max;
188
189            #[inline]
190            fn add_checked(self, rhs: Self) -> Result<Self, ArrowError> {
191                self.checked_add(rhs).ok_or_else(|| {
192                    ArrowError::ArithmeticOverflow(format!(
193                        "Overflow happened on: {:?} + {:?}",
194                        self, rhs
195                    ))
196                })
197            }
198
199            #[inline]
200            fn add_wrapping(self, rhs: Self) -> Self {
201                self.wrapping_add(rhs)
202            }
203
204            #[inline]
205            fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
206                self.checked_sub(rhs).ok_or_else(|| {
207                    ArrowError::ArithmeticOverflow(format!(
208                        "Overflow happened on: {:?} - {:?}",
209                        self, rhs
210                    ))
211                })
212            }
213
214            #[inline]
215            fn sub_wrapping(self, rhs: Self) -> Self {
216                self.wrapping_sub(rhs)
217            }
218
219            #[inline]
220            fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
221                self.checked_mul(rhs).ok_or_else(|| {
222                    ArrowError::ArithmeticOverflow(format!(
223                        "Overflow happened on: {:?} * {:?}",
224                        self, rhs
225                    ))
226                })
227            }
228
229            #[inline]
230            fn mul_wrapping(self, rhs: Self) -> Self {
231                self.wrapping_mul(rhs)
232            }
233
234            #[inline]
235            fn div_checked(self, rhs: Self) -> Result<Self, ArrowError> {
236                if rhs.is_zero() {
237                    Err(ArrowError::DivideByZero)
238                } else {
239                    self.checked_div(rhs).ok_or_else(|| {
240                        ArrowError::ArithmeticOverflow(format!(
241                            "Overflow happened on: {:?} / {:?}",
242                            self, rhs
243                        ))
244                    })
245                }
246            }
247
248            #[inline]
249            fn div_wrapping(self, rhs: Self) -> Self {
250                self.wrapping_div(rhs)
251            }
252
253            #[inline]
254            fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError> {
255                if rhs.is_zero() {
256                    Err(ArrowError::DivideByZero)
257                } else {
258                    self.checked_rem(rhs).ok_or_else(|| {
259                        ArrowError::ArithmeticOverflow(format!(
260                            "Overflow happened on: {:?} % {:?}",
261                            self, rhs
262                        ))
263                    })
264                }
265            }
266
267            #[inline]
268            fn mod_wrapping(self, rhs: Self) -> Self {
269                self.wrapping_rem(rhs)
270            }
271
272            #[inline]
273            fn neg_checked(self) -> Result<Self, ArrowError> {
274                self.checked_neg().ok_or_else(|| {
275                    ArrowError::ArithmeticOverflow(format!("Overflow happened on: - {:?}", self))
276                })
277            }
278
279            #[inline]
280            fn pow_checked(self, exp: u32) -> Result<Self, ArrowError> {
281                self.checked_pow(exp).ok_or_else(|| {
282                    ArrowError::ArithmeticOverflow(format!(
283                        "Overflow happened on: {:?} ^ {exp:?}",
284                        self
285                    ))
286                })
287            }
288
289            #[inline]
290            fn pow_wrapping(self, exp: u32) -> Self {
291                self.wrapping_pow(exp)
292            }
293
294            #[inline]
295            fn neg_wrapping(self) -> Self {
296                self.wrapping_neg()
297            }
298
299            #[inline]
300            fn is_zero(self) -> bool {
301                self == Self::ZERO
302            }
303
304            #[inline]
305            fn compare(self, rhs: Self) -> Ordering {
306                self.cmp(&rhs)
307            }
308
309            #[inline]
310            fn is_eq(self, rhs: Self) -> bool {
311                self == rhs
312            }
313        }
314    };
315}
316
317native_type_op!(i8);
318native_type_op!(i16);
319native_type_op!(i32);
320native_type_op!(i64);
321native_type_op!(i128);
322native_type_op!(u8);
323native_type_op!(u16);
324native_type_op!(u32);
325native_type_op!(u64);
326native_type_op!(
327    i256,
328    i256::ZERO,
329    i256::ONE,
330    i256::MIN,
331    i256::MAX,
332    #[inline]
333    fn div_rem_checked(self, rhs: Self) -> Result<(Self, Self), ArrowError> {
334        if rhs.is_zero() {
335            return Err(ArrowError::DivideByZero);
336        }
337        self.checked_div_rem(rhs).ok_or_else(|| {
338            ArrowError::ArithmeticOverflow(format!("Overflow happened on: {self:?} / {rhs:?}"))
339        })
340    },
341    #[inline]
342    fn div_rem_wrapping(self, rhs: Self) -> (Self, Self) {
343        self.wrapping_div_rem(rhs)
344    }
345);
346
347native_type_op!(IntervalDayTime, IntervalDayTime::ZERO, IntervalDayTime::ONE);
348native_type_op!(
349    IntervalMonthDayNano,
350    IntervalMonthDayNano::ZERO,
351    IntervalMonthDayNano::ONE
352);
353
354macro_rules! native_type_float_op {
355    ($t:tt, $zero:expr, $one:expr, $min:expr, $max:expr) => {
356        impl ArrowNativeTypeOp for $t {
357            const ZERO: Self = $zero;
358            const ONE: Self = $one;
359            const MIN_TOTAL_ORDER: Self = $min;
360            const MAX_TOTAL_ORDER: Self = $max;
361
362            #[inline]
363            fn add_checked(self, rhs: Self) -> Result<Self, ArrowError> {
364                Ok(self + rhs)
365            }
366
367            #[inline]
368            fn add_wrapping(self, rhs: Self) -> Self {
369                self + rhs
370            }
371
372            #[inline]
373            fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
374                Ok(self - rhs)
375            }
376
377            #[inline]
378            fn sub_wrapping(self, rhs: Self) -> Self {
379                self - rhs
380            }
381
382            #[inline]
383            fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
384                Ok(self * rhs)
385            }
386
387            #[inline]
388            fn mul_wrapping(self, rhs: Self) -> Self {
389                self * rhs
390            }
391
392            #[inline]
393            fn div_checked(self, rhs: Self) -> Result<Self, ArrowError> {
394                if rhs.is_zero() {
395                    Err(ArrowError::DivideByZero)
396                } else {
397                    Ok(self / rhs)
398                }
399            }
400
401            #[inline]
402            fn div_wrapping(self, rhs: Self) -> Self {
403                self / rhs
404            }
405
406            #[inline]
407            fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError> {
408                if rhs.is_zero() {
409                    Err(ArrowError::DivideByZero)
410                } else {
411                    Ok(self % rhs)
412                }
413            }
414
415            #[inline]
416            fn mod_wrapping(self, rhs: Self) -> Self {
417                self % rhs
418            }
419
420            #[inline]
421            fn neg_checked(self) -> Result<Self, ArrowError> {
422                Ok(-self)
423            }
424
425            #[inline]
426            fn neg_wrapping(self) -> Self {
427                -self
428            }
429
430            #[inline]
431            fn pow_checked(self, exp: u32) -> Result<Self, ArrowError> {
432                Ok(self.powi(exp as i32))
433            }
434
435            #[inline]
436            fn pow_wrapping(self, exp: u32) -> Self {
437                self.powi(exp as i32)
438            }
439
440            #[inline]
441            fn is_zero(self) -> bool {
442                self == $zero
443            }
444
445            #[inline]
446            fn compare(self, rhs: Self) -> Ordering {
447                <$t>::total_cmp(&self, &rhs)
448            }
449
450            #[inline]
451            fn is_eq(self, rhs: Self) -> bool {
452                // Equivalent to `self.total_cmp(&rhs).is_eq()`
453                // but LLVM isn't able to realise this is bitwise equality
454                // https://rust.godbolt.org/z/347nWGxoW
455                self.to_bits() == rhs.to_bits()
456            }
457        }
458    };
459}
460
461// the smallest/largest bit patterns for floating point numbers are NaN, but differ from the canonical NAN constants.
462// See test_float_total_order_min_max for details.
463native_type_float_op!(
464    f16,
465    f16::ZERO,
466    f16::ONE,
467    f16::from_bits(-1 as _),
468    f16::from_bits(i16::MAX as _)
469);
470native_type_float_op!(
471    f32,
472    0.,
473    1.,
474    f32::from_bits(-1_i32 as _),
475    f32::from_bits(i32::MAX as _)
476);
477native_type_float_op!(
478    f64,
479    0.,
480    1.,
481    f64::from_bits(-1_i64 as _),
482    f64::from_bits(i64::MAX as _)
483);
484
485#[cfg(test)]
486mod tests {
487    use super::*;
488
489    macro_rules! assert_approx_eq {
490        ( $x: expr, $y: expr ) => {{ assert_approx_eq!($x, $y, 1.0e-4) }};
491        ( $x: expr, $y: expr, $tol: expr ) => {{
492            let x_val = $x;
493            let y_val = $y;
494            let diff = f64::from((x_val - y_val).abs());
495            assert!(
496                diff <= $tol,
497                "{} != {} (with tolerance = {})",
498                x_val,
499                y_val,
500                $tol
501            );
502        }};
503    }
504
505    #[test]
506    fn test_native_type_is_zero() {
507        assert!(0_i8.is_zero());
508        assert!(0_i16.is_zero());
509        assert!(0_i32.is_zero());
510        assert!(0_i64.is_zero());
511        assert!(0_i128.is_zero());
512        assert!(i256::ZERO.is_zero());
513        assert!(0_u8.is_zero());
514        assert!(0_u16.is_zero());
515        assert!(0_u32.is_zero());
516        assert!(0_u64.is_zero());
517        assert!(f16::ZERO.is_zero());
518        assert!(0.0_f32.is_zero());
519        assert!(0.0_f64.is_zero());
520    }
521
522    #[test]
523    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
524    fn test_native_type_comparison() {
525        // is_eq
526        assert!(8_i8.is_eq(8_i8));
527        assert!(8_i16.is_eq(8_i16));
528        assert!(8_i32.is_eq(8_i32));
529        assert!(8_i64.is_eq(8_i64));
530        assert!(8_i128.is_eq(8_i128));
531        assert!(i256::from_parts(8, 0).is_eq(i256::from_parts(8, 0)));
532        assert!(8_u8.is_eq(8_u8));
533        assert!(8_u16.is_eq(8_u16));
534        assert!(8_u32.is_eq(8_u32));
535        assert!(8_u64.is_eq(8_u64));
536        assert!(f16::from_f32(8.0).is_eq(f16::from_f32(8.0)));
537        assert!(8.0_f32.is_eq(8.0_f32));
538        assert!(8.0_f64.is_eq(8.0_f64));
539
540        // is_ne
541        assert!(8_i8.is_ne(1_i8));
542        assert!(8_i16.is_ne(1_i16));
543        assert!(8_i32.is_ne(1_i32));
544        assert!(8_i64.is_ne(1_i64));
545        assert!(8_i128.is_ne(1_i128));
546        assert!(i256::from_parts(8, 0).is_ne(i256::from_parts(1, 0)));
547        assert!(8_u8.is_ne(1_u8));
548        assert!(8_u16.is_ne(1_u16));
549        assert!(8_u32.is_ne(1_u32));
550        assert!(8_u64.is_ne(1_u64));
551        assert!(f16::from_f32(8.0).is_ne(f16::from_f32(1.0)));
552        assert!(8.0_f32.is_ne(1.0_f32));
553        assert!(8.0_f64.is_ne(1.0_f64));
554
555        // is_lt
556        assert!(8_i8.is_lt(10_i8));
557        assert!(8_i16.is_lt(10_i16));
558        assert!(8_i32.is_lt(10_i32));
559        assert!(8_i64.is_lt(10_i64));
560        assert!(8_i128.is_lt(10_i128));
561        assert!(i256::from_parts(8, 0).is_lt(i256::from_parts(10, 0)));
562        assert!(8_u8.is_lt(10_u8));
563        assert!(8_u16.is_lt(10_u16));
564        assert!(8_u32.is_lt(10_u32));
565        assert!(8_u64.is_lt(10_u64));
566        assert!(f16::from_f32(8.0).is_lt(f16::from_f32(10.0)));
567        assert!(8.0_f32.is_lt(10.0_f32));
568        assert!(8.0_f64.is_lt(10.0_f64));
569
570        // is_gt
571        assert!(8_i8.is_gt(1_i8));
572        assert!(8_i16.is_gt(1_i16));
573        assert!(8_i32.is_gt(1_i32));
574        assert!(8_i64.is_gt(1_i64));
575        assert!(8_i128.is_gt(1_i128));
576        assert!(i256::from_parts(8, 0).is_gt(i256::from_parts(1, 0)));
577        assert!(8_u8.is_gt(1_u8));
578        assert!(8_u16.is_gt(1_u16));
579        assert!(8_u32.is_gt(1_u32));
580        assert!(8_u64.is_gt(1_u64));
581        assert!(f16::from_f32(8.0).is_gt(f16::from_f32(1.0)));
582        assert!(8.0_f32.is_gt(1.0_f32));
583        assert!(8.0_f64.is_gt(1.0_f64));
584    }
585
586    #[test]
587    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
588    fn test_native_type_add() {
589        // add_wrapping
590        assert_eq!(8_i8.add_wrapping(2_i8), 10_i8);
591        assert_eq!(8_i16.add_wrapping(2_i16), 10_i16);
592        assert_eq!(8_i32.add_wrapping(2_i32), 10_i32);
593        assert_eq!(8_i64.add_wrapping(2_i64), 10_i64);
594        assert_eq!(8_i128.add_wrapping(2_i128), 10_i128);
595        assert_eq!(
596            i256::from_parts(8, 0).add_wrapping(i256::from_parts(2, 0)),
597            i256::from_parts(10, 0)
598        );
599        assert_eq!(8_u8.add_wrapping(2_u8), 10_u8);
600        assert_eq!(8_u16.add_wrapping(2_u16), 10_u16);
601        assert_eq!(8_u32.add_wrapping(2_u32), 10_u32);
602        assert_eq!(8_u64.add_wrapping(2_u64), 10_u64);
603        assert_eq!(
604            f16::from_f32(8.0).add_wrapping(f16::from_f32(2.0)),
605            f16::from_f32(10.0)
606        );
607        assert_eq!(8.0_f32.add_wrapping(2.0_f32), 10_f32);
608        assert_eq!(8.0_f64.add_wrapping(2.0_f64), 10_f64);
609
610        // add_checked
611        assert_eq!(8_i8.add_checked(2_i8).unwrap(), 10_i8);
612        assert_eq!(8_i16.add_checked(2_i16).unwrap(), 10_i16);
613        assert_eq!(8_i32.add_checked(2_i32).unwrap(), 10_i32);
614        assert_eq!(8_i64.add_checked(2_i64).unwrap(), 10_i64);
615        assert_eq!(8_i128.add_checked(2_i128).unwrap(), 10_i128);
616        assert_eq!(
617            i256::from_parts(8, 0)
618                .add_checked(i256::from_parts(2, 0))
619                .unwrap(),
620            i256::from_parts(10, 0)
621        );
622        assert_eq!(8_u8.add_checked(2_u8).unwrap(), 10_u8);
623        assert_eq!(8_u16.add_checked(2_u16).unwrap(), 10_u16);
624        assert_eq!(8_u32.add_checked(2_u32).unwrap(), 10_u32);
625        assert_eq!(8_u64.add_checked(2_u64).unwrap(), 10_u64);
626        assert_eq!(
627            f16::from_f32(8.0).add_checked(f16::from_f32(2.0)).unwrap(),
628            f16::from_f32(10.0)
629        );
630        assert_eq!(8.0_f32.add_checked(2.0_f32).unwrap(), 10_f32);
631        assert_eq!(8.0_f64.add_checked(2.0_f64).unwrap(), 10_f64);
632    }
633
634    #[test]
635    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
636    fn test_native_type_sub() {
637        // sub_wrapping
638        assert_eq!(8_i8.sub_wrapping(2_i8), 6_i8);
639        assert_eq!(8_i16.sub_wrapping(2_i16), 6_i16);
640        assert_eq!(8_i32.sub_wrapping(2_i32), 6_i32);
641        assert_eq!(8_i64.sub_wrapping(2_i64), 6_i64);
642        assert_eq!(8_i128.sub_wrapping(2_i128), 6_i128);
643        assert_eq!(
644            i256::from_parts(8, 0).sub_wrapping(i256::from_parts(2, 0)),
645            i256::from_parts(6, 0)
646        );
647        assert_eq!(8_u8.sub_wrapping(2_u8), 6_u8);
648        assert_eq!(8_u16.sub_wrapping(2_u16), 6_u16);
649        assert_eq!(8_u32.sub_wrapping(2_u32), 6_u32);
650        assert_eq!(8_u64.sub_wrapping(2_u64), 6_u64);
651        assert_eq!(
652            f16::from_f32(8.0).sub_wrapping(f16::from_f32(2.0)),
653            f16::from_f32(6.0)
654        );
655        assert_eq!(8.0_f32.sub_wrapping(2.0_f32), 6_f32);
656        assert_eq!(8.0_f64.sub_wrapping(2.0_f64), 6_f64);
657
658        // sub_checked
659        assert_eq!(8_i8.sub_checked(2_i8).unwrap(), 6_i8);
660        assert_eq!(8_i16.sub_checked(2_i16).unwrap(), 6_i16);
661        assert_eq!(8_i32.sub_checked(2_i32).unwrap(), 6_i32);
662        assert_eq!(8_i64.sub_checked(2_i64).unwrap(), 6_i64);
663        assert_eq!(8_i128.sub_checked(2_i128).unwrap(), 6_i128);
664        assert_eq!(
665            i256::from_parts(8, 0)
666                .sub_checked(i256::from_parts(2, 0))
667                .unwrap(),
668            i256::from_parts(6, 0)
669        );
670        assert_eq!(8_u8.sub_checked(2_u8).unwrap(), 6_u8);
671        assert_eq!(8_u16.sub_checked(2_u16).unwrap(), 6_u16);
672        assert_eq!(8_u32.sub_checked(2_u32).unwrap(), 6_u32);
673        assert_eq!(8_u64.sub_checked(2_u64).unwrap(), 6_u64);
674        assert_eq!(
675            f16::from_f32(8.0).sub_checked(f16::from_f32(2.0)).unwrap(),
676            f16::from_f32(6.0)
677        );
678        assert_eq!(8.0_f32.sub_checked(2.0_f32).unwrap(), 6_f32);
679        assert_eq!(8.0_f64.sub_checked(2.0_f64).unwrap(), 6_f64);
680    }
681
682    #[test]
683    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
684    fn test_native_type_mul() {
685        // mul_wrapping
686        assert_eq!(8_i8.mul_wrapping(2_i8), 16_i8);
687        assert_eq!(8_i16.mul_wrapping(2_i16), 16_i16);
688        assert_eq!(8_i32.mul_wrapping(2_i32), 16_i32);
689        assert_eq!(8_i64.mul_wrapping(2_i64), 16_i64);
690        assert_eq!(8_i128.mul_wrapping(2_i128), 16_i128);
691        assert_eq!(
692            i256::from_parts(8, 0).mul_wrapping(i256::from_parts(2, 0)),
693            i256::from_parts(16, 0)
694        );
695        assert_eq!(8_u8.mul_wrapping(2_u8), 16_u8);
696        assert_eq!(8_u16.mul_wrapping(2_u16), 16_u16);
697        assert_eq!(8_u32.mul_wrapping(2_u32), 16_u32);
698        assert_eq!(8_u64.mul_wrapping(2_u64), 16_u64);
699        assert_eq!(
700            f16::from_f32(8.0).mul_wrapping(f16::from_f32(2.0)),
701            f16::from_f32(16.0)
702        );
703        assert_eq!(8.0_f32.mul_wrapping(2.0_f32), 16_f32);
704        assert_eq!(8.0_f64.mul_wrapping(2.0_f64), 16_f64);
705
706        // mul_checked
707        assert_eq!(8_i8.mul_checked(2_i8).unwrap(), 16_i8);
708        assert_eq!(8_i16.mul_checked(2_i16).unwrap(), 16_i16);
709        assert_eq!(8_i32.mul_checked(2_i32).unwrap(), 16_i32);
710        assert_eq!(8_i64.mul_checked(2_i64).unwrap(), 16_i64);
711        assert_eq!(8_i128.mul_checked(2_i128).unwrap(), 16_i128);
712        assert_eq!(
713            i256::from_parts(8, 0)
714                .mul_checked(i256::from_parts(2, 0))
715                .unwrap(),
716            i256::from_parts(16, 0)
717        );
718        assert_eq!(8_u8.mul_checked(2_u8).unwrap(), 16_u8);
719        assert_eq!(8_u16.mul_checked(2_u16).unwrap(), 16_u16);
720        assert_eq!(8_u32.mul_checked(2_u32).unwrap(), 16_u32);
721        assert_eq!(8_u64.mul_checked(2_u64).unwrap(), 16_u64);
722        assert_eq!(
723            f16::from_f32(8.0).mul_checked(f16::from_f32(2.0)).unwrap(),
724            f16::from_f32(16.0)
725        );
726        assert_eq!(8.0_f32.mul_checked(2.0_f32).unwrap(), 16_f32);
727        assert_eq!(8.0_f64.mul_checked(2.0_f64).unwrap(), 16_f64);
728    }
729
730    #[test]
731    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
732    fn test_native_type_div() {
733        // div_wrapping
734        assert_eq!(8_i8.div_wrapping(2_i8), 4_i8);
735        assert_eq!(8_i16.div_wrapping(2_i16), 4_i16);
736        assert_eq!(8_i32.div_wrapping(2_i32), 4_i32);
737        assert_eq!(8_i64.div_wrapping(2_i64), 4_i64);
738        assert_eq!(8_i128.div_wrapping(2_i128), 4_i128);
739        assert_eq!(
740            i256::from_parts(8, 0).div_wrapping(i256::from_parts(2, 0)),
741            i256::from_parts(4, 0)
742        );
743        assert_eq!(8_u8.div_wrapping(2_u8), 4_u8);
744        assert_eq!(8_u16.div_wrapping(2_u16), 4_u16);
745        assert_eq!(8_u32.div_wrapping(2_u32), 4_u32);
746        assert_eq!(8_u64.div_wrapping(2_u64), 4_u64);
747        assert_eq!(
748            f16::from_f32(8.0).div_wrapping(f16::from_f32(2.0)),
749            f16::from_f32(4.0)
750        );
751        assert_eq!(8.0_f32.div_wrapping(2.0_f32), 4_f32);
752        assert_eq!(8.0_f64.div_wrapping(2.0_f64), 4_f64);
753
754        // div_checked
755        assert_eq!(8_i8.div_checked(2_i8).unwrap(), 4_i8);
756        assert_eq!(8_i16.div_checked(2_i16).unwrap(), 4_i16);
757        assert_eq!(8_i32.div_checked(2_i32).unwrap(), 4_i32);
758        assert_eq!(8_i64.div_checked(2_i64).unwrap(), 4_i64);
759        assert_eq!(8_i128.div_checked(2_i128).unwrap(), 4_i128);
760        assert_eq!(
761            i256::from_parts(8, 0)
762                .div_checked(i256::from_parts(2, 0))
763                .unwrap(),
764            i256::from_parts(4, 0)
765        );
766        assert_eq!(8_u8.div_checked(2_u8).unwrap(), 4_u8);
767        assert_eq!(8_u16.div_checked(2_u16).unwrap(), 4_u16);
768        assert_eq!(8_u32.div_checked(2_u32).unwrap(), 4_u32);
769        assert_eq!(8_u64.div_checked(2_u64).unwrap(), 4_u64);
770        assert_eq!(
771            f16::from_f32(8.0).div_checked(f16::from_f32(2.0)).unwrap(),
772            f16::from_f32(4.0)
773        );
774        assert_eq!(8.0_f32.div_checked(2.0_f32).unwrap(), 4_f32);
775        assert_eq!(8.0_f64.div_checked(2.0_f64).unwrap(), 4_f64);
776    }
777
778    #[test]
779    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
780    fn test_native_type_mod() {
781        // mod_wrapping
782        assert_eq!(9_i8.mod_wrapping(2_i8), 1_i8);
783        assert_eq!(9_i16.mod_wrapping(2_i16), 1_i16);
784        assert_eq!(9_i32.mod_wrapping(2_i32), 1_i32);
785        assert_eq!(9_i64.mod_wrapping(2_i64), 1_i64);
786        assert_eq!(9_i128.mod_wrapping(2_i128), 1_i128);
787        assert_eq!(
788            i256::from_parts(9, 0).mod_wrapping(i256::from_parts(2, 0)),
789            i256::from_parts(1, 0)
790        );
791        assert_eq!(9_u8.mod_wrapping(2_u8), 1_u8);
792        assert_eq!(9_u16.mod_wrapping(2_u16), 1_u16);
793        assert_eq!(9_u32.mod_wrapping(2_u32), 1_u32);
794        assert_eq!(9_u64.mod_wrapping(2_u64), 1_u64);
795        assert_eq!(
796            f16::from_f32(9.0).mod_wrapping(f16::from_f32(2.0)),
797            f16::from_f32(1.0)
798        );
799        assert_eq!(9.0_f32.mod_wrapping(2.0_f32), 1_f32);
800        assert_eq!(9.0_f64.mod_wrapping(2.0_f64), 1_f64);
801
802        // mod_checked
803        assert_eq!(9_i8.mod_checked(2_i8).unwrap(), 1_i8);
804        assert_eq!(9_i16.mod_checked(2_i16).unwrap(), 1_i16);
805        assert_eq!(9_i32.mod_checked(2_i32).unwrap(), 1_i32);
806        assert_eq!(9_i64.mod_checked(2_i64).unwrap(), 1_i64);
807        assert_eq!(9_i128.mod_checked(2_i128).unwrap(), 1_i128);
808        assert_eq!(
809            i256::from_parts(9, 0)
810                .mod_checked(i256::from_parts(2, 0))
811                .unwrap(),
812            i256::from_parts(1, 0)
813        );
814        assert_eq!(9_u8.mod_checked(2_u8).unwrap(), 1_u8);
815        assert_eq!(9_u16.mod_checked(2_u16).unwrap(), 1_u16);
816        assert_eq!(9_u32.mod_checked(2_u32).unwrap(), 1_u32);
817        assert_eq!(9_u64.mod_checked(2_u64).unwrap(), 1_u64);
818        assert_eq!(
819            f16::from_f32(9.0).mod_checked(f16::from_f32(2.0)).unwrap(),
820            f16::from_f32(1.0)
821        );
822        assert_eq!(9.0_f32.mod_checked(2.0_f32).unwrap(), 1_f32);
823        assert_eq!(9.0_f64.mod_checked(2.0_f64).unwrap(), 1_f64);
824    }
825
826    #[test]
827    fn test_i256_div_rem() {
828        let values = [
829            i256::MIN,
830            i256::MIN + i256::ONE,
831            i256::from_i128(-7),
832            i256::MINUS_ONE,
833            i256::ZERO,
834            i256::ONE,
835            i256::from_i128(2),
836            i256::from_i128(7),
837            i256::from_i128(i128::MAX),
838            i256::MAX,
839        ];
840        for n in values {
841            for d in values {
842                let checked = n
843                    .div_checked(d)
844                    .and_then(|q| Ok((q, n.mod_checked(d)?)))
845                    .map_err(|e| e.to_string());
846                assert_eq!(
847                    n.div_rem_checked(d).map_err(|e| e.to_string()),
848                    checked,
849                    "{n} / {d}"
850                );
851                if !d.is_zero() {
852                    assert_eq!(
853                        n.div_rem_wrapping(d),
854                        (n.div_wrapping(d), n.mod_wrapping(d)),
855                        "{n} / {d}"
856                    );
857                }
858            }
859        }
860    }
861
862    #[test]
863    #[should_panic(expected = "attempt to divide by zero")]
864    fn test_i256_div_rem_wrapping_zero_panics() {
865        let _ = i256::ONE.div_rem_wrapping(i256::ZERO);
866    }
867
868    #[test]
869    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
870    fn test_native_type_neg() {
871        // neg_wrapping
872        assert_eq!(8_i8.neg_wrapping(), -8_i8);
873        assert_eq!(8_i16.neg_wrapping(), -8_i16);
874        assert_eq!(8_i32.neg_wrapping(), -8_i32);
875        assert_eq!(8_i64.neg_wrapping(), -8_i64);
876        assert_eq!(8_i128.neg_wrapping(), -8_i128);
877        assert_eq!(i256::from_parts(8, 0).neg_wrapping(), i256::from_i128(-8));
878        assert_eq!(8_u8.neg_wrapping(), u8::MAX - 7_u8);
879        assert_eq!(8_u16.neg_wrapping(), u16::MAX - 7_u16);
880        assert_eq!(8_u32.neg_wrapping(), u32::MAX - 7_u32);
881        assert_eq!(8_u64.neg_wrapping(), u64::MAX - 7_u64);
882        assert_eq!(f16::from_f32(8.0).neg_wrapping(), f16::from_f32(-8.0));
883        assert_eq!(8.0_f32.neg_wrapping(), -8_f32);
884        assert_eq!(8.0_f64.neg_wrapping(), -8_f64);
885
886        // neg_checked
887        assert_eq!(8_i8.neg_checked().unwrap(), -8_i8);
888        assert_eq!(8_i16.neg_checked().unwrap(), -8_i16);
889        assert_eq!(8_i32.neg_checked().unwrap(), -8_i32);
890        assert_eq!(8_i64.neg_checked().unwrap(), -8_i64);
891        assert_eq!(8_i128.neg_checked().unwrap(), -8_i128);
892        assert_eq!(
893            i256::from_parts(8, 0).neg_checked().unwrap(),
894            i256::from_i128(-8)
895        );
896        assert!(8_u8.neg_checked().is_err());
897        assert!(8_u16.neg_checked().is_err());
898        assert!(8_u32.neg_checked().is_err());
899        assert!(8_u64.neg_checked().is_err());
900        assert_eq!(
901            f16::from_f32(8.0).neg_checked().unwrap(),
902            f16::from_f32(-8.0)
903        );
904        assert_eq!(8.0_f32.neg_checked().unwrap(), -8_f32);
905        assert_eq!(8.0_f64.neg_checked().unwrap(), -8_f64);
906    }
907
908    #[test]
909    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
910    fn test_native_type_pow() {
911        // pow_wrapping
912        assert_eq!(8_i8.pow_wrapping(2_u32), 64_i8);
913        assert_eq!(8_i16.pow_wrapping(2_u32), 64_i16);
914        assert_eq!(8_i32.pow_wrapping(2_u32), 64_i32);
915        assert_eq!(8_i64.pow_wrapping(2_u32), 64_i64);
916        assert_eq!(8_i128.pow_wrapping(2_u32), 64_i128);
917        assert_eq!(
918            i256::from_parts(8, 0).pow_wrapping(2_u32),
919            i256::from_parts(64, 0)
920        );
921        assert_eq!(8_u8.pow_wrapping(2_u32), 64_u8);
922        assert_eq!(8_u16.pow_wrapping(2_u32), 64_u16);
923        assert_eq!(8_u32.pow_wrapping(2_u32), 64_u32);
924        assert_eq!(8_u64.pow_wrapping(2_u32), 64_u64);
925        assert_approx_eq!(f16::from_f32(8.0).pow_wrapping(2_u32), f16::from_f32(64.0));
926        assert_approx_eq!(8.0_f32.pow_wrapping(2_u32), 64_f32);
927        assert_approx_eq!(8.0_f64.pow_wrapping(2_u32), 64_f64);
928
929        // pow_checked
930        assert_eq!(8_i8.pow_checked(2_u32).unwrap(), 64_i8);
931        assert_eq!(8_i16.pow_checked(2_u32).unwrap(), 64_i16);
932        assert_eq!(8_i32.pow_checked(2_u32).unwrap(), 64_i32);
933        assert_eq!(8_i64.pow_checked(2_u32).unwrap(), 64_i64);
934        assert_eq!(8_i128.pow_checked(2_u32).unwrap(), 64_i128);
935        assert_eq!(
936            i256::from_parts(8, 0).pow_checked(2_u32).unwrap(),
937            i256::from_parts(64, 0)
938        );
939        assert_eq!(8_u8.pow_checked(2_u32).unwrap(), 64_u8);
940        assert_eq!(8_u16.pow_checked(2_u32).unwrap(), 64_u16);
941        assert_eq!(8_u32.pow_checked(2_u32).unwrap(), 64_u32);
942        assert_eq!(8_u64.pow_checked(2_u32).unwrap(), 64_u64);
943        assert_approx_eq!(
944            f16::from_f32(8.0).pow_checked(2_u32).unwrap(),
945            f16::from_f32(64.0)
946        );
947        assert_approx_eq!(8.0_f32.pow_checked(2_u32).unwrap(), 64_f32);
948        assert_approx_eq!(8.0_f64.pow_checked(2_u32).unwrap(), 64_f64);
949    }
950
951    #[test]
952    fn test_float_total_order_min_max() {
953        assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f64::NEG_INFINITY));
954        assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f64::INFINITY));
955
956        assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
957        assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
958        assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f64::NAN));
959
960        assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
961        assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
962        assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f64::NAN));
963
964        assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f32::NEG_INFINITY));
965        assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f32::INFINITY));
966
967        assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
968        assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
969        assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f32::NAN));
970
971        assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
972        assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
973        assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f32::NAN));
974
975        assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f16::NEG_INFINITY));
976        assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f16::INFINITY));
977
978        assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
979        assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
980        assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f16::NAN));
981
982        assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
983        assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
984        assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f16::NAN));
985    }
986}