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