Skip to main content

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