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