## Coverage Report

#### Created: 2025-11-17 14:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-array/src/arithmetic.rs

    Line
    Count
    Source
    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
    18
    use arrow_buffer::{ArrowNativeType, IntervalDayTime, IntervalMonthDayNano, i256};
    19
    use arrow_schema::ArrowError;
    20
    use half::f16;
    21
    use num_complex::ComplexFloat;
    22
    use 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
    ///
    41
    pub 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
    137
        fn is_lt(self, rhs: Self) -> bool {
    118
    137
            self.compare(rhs).is_lt()
    119
    137
        }
    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
    140
    macro_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
    137
                fn compare(self, rhs: Self) -> Ordering {
    271
    137
                    self.cmp(&rhs)
    272
    137
                }
    273
    274
                #[inline]
    275
                fn is_eq(self, rhs: Self) -> bool {
    276
                    self == rhs
    277
                }
    278
            }
    279
        };
    280
    }
    281
    282
    native_type_op!(i8);
    283
    native_type_op!(i16);
    284
    native_type_op!(i32);
    285
    native_type_op!(i64);
    286
    native_type_op!(i128);
    287
    native_type_op!(u8);
    288
    native_type_op!(u16);
    289
    native_type_op!(u32);
    290
    native_type_op!(u64);
    291
    native_type_op!(i256, i256::ZERO, i256::ONE);
    292
    293
    native_type_op!(IntervalDayTime, IntervalDayTime::ZERO, IntervalDayTime::ONE);
    294
    native_type_op!(
    295
        IntervalMonthDayNano,
    296
        IntervalMonthDayNano::ZERO,
    297
        IntervalMonthDayNano::ONE
    298
    );
    299
    300
    macro_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.
    409
    native_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
    417
    native_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.85.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.85.0` but this item is stable since `1.87.0`
    430
            #[allow(unnecessary_transmutes)]
    431
            std::mem::transmute(i32::MAX)
    432
        }
    433
    );
    434
    native_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.85.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.85.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)]
    453
    mod tests {
    454
        use super::*;
    455
    456
        macro_rules! assert_approx_eq {
    457
            ( $x: expr, $y: expr ) => {{ assert_approx_eq!($x, $y, 1.0e-4) }};
    458
            ( $x: expr, $y: expr, $tol: expr ) => {{
    459
                let x_val = $x;
    460
                let y_val = $y;
    461
                let diff = f64::from((x_val - y_val).abs());
    462
                assert!(
    463
                    diff <= $tol,
    464
                    "{} != {} (with tolerance = {})",
    465
                    x_val,
    466
                    y_val,
    467
                    $tol
    468
                );
    469
            }};
    470
        }
    471
    472
        #[test]
    473
        fn test_native_type_is_zero() {
    474
            assert!(0_i8.is_zero());
    475
            assert!(0_i16.is_zero());
    476
            assert!(0_i32.is_zero());
    477
            assert!(0_i64.is_zero());
    478
            assert!(0_i128.is_zero());
    479
            assert!(i256::ZERO.is_zero());
    480
            assert!(0_u8.is_zero());
    481
            assert!(0_u16.is_zero());
    482
            assert!(0_u32.is_zero());
    483
            assert!(0_u64.is_zero());
    484
            assert!(f16::ZERO.is_zero());
    485
            assert!(0.0_f32.is_zero());
    486
            assert!(0.0_f64.is_zero());
    487
        }
    488
    489
        #[test]
    490
        fn test_native_type_comparison() {
    491
            // is_eq
    492
            assert!(8_i8.is_eq(8_i8));
    493
            assert!(8_i16.is_eq(8_i16));
    494
            assert!(8_i32.is_eq(8_i32));
    495
            assert!(8_i64.is_eq(8_i64));
    496
            assert!(8_i128.is_eq(8_i128));
    497
            assert!(i256::from_parts(8, 0).is_eq(i256::from_parts(8, 0)));
    498
            assert!(8_u8.is_eq(8_u8));
    499
            assert!(8_u16.is_eq(8_u16));
    500
            assert!(8_u32.is_eq(8_u32));
    501
            assert!(8_u64.is_eq(8_u64));
    502
            assert!(f16::from_f32(8.0).is_eq(f16::from_f32(8.0)));
    503
            assert!(8.0_f32.is_eq(8.0_f32));
    504
            assert!(8.0_f64.is_eq(8.0_f64));
    505
    506
            // is_ne
    507
            assert!(8_i8.is_ne(1_i8));
    508
            assert!(8_i16.is_ne(1_i16));
    509
            assert!(8_i32.is_ne(1_i32));
    510
            assert!(8_i64.is_ne(1_i64));
    511
            assert!(8_i128.is_ne(1_i128));
    512
            assert!(i256::from_parts(8, 0).is_ne(i256::from_parts(1, 0)));
    513
            assert!(8_u8.is_ne(1_u8));
    514
            assert!(8_u16.is_ne(1_u16));
    515
            assert!(8_u32.is_ne(1_u32));
    516
            assert!(8_u64.is_ne(1_u64));
    517
            assert!(f16::from_f32(8.0).is_ne(f16::from_f32(1.0)));
    518
            assert!(8.0_f32.is_ne(1.0_f32));
    519
            assert!(8.0_f64.is_ne(1.0_f64));
    520
    521
            // is_lt
    522
            assert!(8_i8.is_lt(10_i8));
    523
            assert!(8_i16.is_lt(10_i16));
    524
            assert!(8_i32.is_lt(10_i32));
    525
            assert!(8_i64.is_lt(10_i64));
    526
            assert!(8_i128.is_lt(10_i128));
    527
            assert!(i256::from_parts(8, 0).is_lt(i256::from_parts(10, 0)));
    528
            assert!(8_u8.is_lt(10_u8));
    529
            assert!(8_u16.is_lt(10_u16));
    530
            assert!(8_u32.is_lt(10_u32));
    531
            assert!(8_u64.is_lt(10_u64));
    532
            assert!(f16::from_f32(8.0).is_lt(f16::from_f32(10.0)));
    533
            assert!(8.0_f32.is_lt(10.0_f32));
    534
            assert!(8.0_f64.is_lt(10.0_f64));
    535
    536
            // is_gt
    537
            assert!(8_i8.is_gt(1_i8));
    538
            assert!(8_i16.is_gt(1_i16));
    539
            assert!(8_i32.is_gt(1_i32));
    540
            assert!(8_i64.is_gt(1_i64));
    541
            assert!(8_i128.is_gt(1_i128));
    542
            assert!(i256::from_parts(8, 0).is_gt(i256::from_parts(1, 0)));
    543
            assert!(8_u8.is_gt(1_u8));
    544
            assert!(8_u16.is_gt(1_u16));
    545
            assert!(8_u32.is_gt(1_u32));
    546
            assert!(8_u64.is_gt(1_u64));
    547
            assert!(f16::from_f32(8.0).is_gt(f16::from_f32(1.0)));
    548
            assert!(8.0_f32.is_gt(1.0_f32));
    549
            assert!(8.0_f64.is_gt(1.0_f64));
    550
        }
    551
    552
        #[test]
    553
        fn test_native_type_add() {
    554
            // add_wrapping
    555
            assert_eq!(8_i8.add_wrapping(2_i8), 10_i8);
    556
            assert_eq!(8_i16.add_wrapping(2_i16), 10_i16);
    557
            assert_eq!(8_i32.add_wrapping(2_i32), 10_i32);
    558
            assert_eq!(8_i64.add_wrapping(2_i64), 10_i64);
    559
            assert_eq!(8_i128.add_wrapping(2_i128), 10_i128);
    560
            assert_eq!(
    561
                i256::from_parts(8, 0).add_wrapping(i256::from_parts(2, 0)),
    562
                i256::from_parts(10, 0)
    563
            );
    564
            assert_eq!(8_u8.add_wrapping(2_u8), 10_u8);
    565
            assert_eq!(8_u16.add_wrapping(2_u16), 10_u16);
    566
            assert_eq!(8_u32.add_wrapping(2_u32), 10_u32);
    567
            assert_eq!(8_u64.add_wrapping(2_u64), 10_u64);
    568
            assert_eq!(
    569
                f16::from_f32(8.0).add_wrapping(f16::from_f32(2.0)),
    570
                f16::from_f32(10.0)
    571
            );
    572
            assert_eq!(8.0_f32.add_wrapping(2.0_f32), 10_f32);
    573
            assert_eq!(8.0_f64.add_wrapping(2.0_f64), 10_f64);
    574
    575
            // add_checked
    576
            assert_eq!(8_i8.add_checked(2_i8).unwrap(), 10_i8);
    577
            assert_eq!(8_i16.add_checked(2_i16).unwrap(), 10_i16);
    578
            assert_eq!(8_i32.add_checked(2_i32).unwrap(), 10_i32);
    579
            assert_eq!(8_i64.add_checked(2_i64).unwrap(), 10_i64);
    580
            assert_eq!(8_i128.add_checked(2_i128).unwrap(), 10_i128);
    581
            assert_eq!(
    582
                i256::from_parts(8, 0)
    583
                    .add_checked(i256::from_parts(2, 0))
    584
                    .unwrap(),
    585
                i256::from_parts(10, 0)
    586
            );
    587
            assert_eq!(8_u8.add_checked(2_u8).unwrap(), 10_u8);
    588
            assert_eq!(8_u16.add_checked(2_u16).unwrap(), 10_u16);
    589
            assert_eq!(8_u32.add_checked(2_u32).unwrap(), 10_u32);
    590
            assert_eq!(8_u64.add_checked(2_u64).unwrap(), 10_u64);
    591
            assert_eq!(
    592
                f16::from_f32(8.0).add_checked(f16::from_f32(2.0)).unwrap(),
    593
                f16::from_f32(10.0)
    594
            );
    595
            assert_eq!(8.0_f32.add_checked(2.0_f32).unwrap(), 10_f32);
    596
            assert_eq!(8.0_f64.add_checked(2.0_f64).unwrap(), 10_f64);
    597
        }
    598
    599
        #[test]
    600
        fn test_native_type_sub() {
    601
            // sub_wrapping
    602
            assert_eq!(8_i8.sub_wrapping(2_i8), 6_i8);
    603
            assert_eq!(8_i16.sub_wrapping(2_i16), 6_i16);
    604
            assert_eq!(8_i32.sub_wrapping(2_i32), 6_i32);
    605
            assert_eq!(8_i64.sub_wrapping(2_i64), 6_i64);
    606
            assert_eq!(8_i128.sub_wrapping(2_i128), 6_i128);
    607
            assert_eq!(
    608
                i256::from_parts(8, 0).sub_wrapping(i256::from_parts(2, 0)),
    609
                i256::from_parts(6, 0)
    610
            );
    611
            assert_eq!(8_u8.sub_wrapping(2_u8), 6_u8);
    612
            assert_eq!(8_u16.sub_wrapping(2_u16), 6_u16);
    613
            assert_eq!(8_u32.sub_wrapping(2_u32), 6_u32);
    614
            assert_eq!(8_u64.sub_wrapping(2_u64), 6_u64);
    615
            assert_eq!(
    616
                f16::from_f32(8.0).sub_wrapping(f16::from_f32(2.0)),
    617
                f16::from_f32(6.0)
    618
            );
    619
            assert_eq!(8.0_f32.sub_wrapping(2.0_f32), 6_f32);
    620
            assert_eq!(8.0_f64.sub_wrapping(2.0_f64), 6_f64);
    621
    622
            // sub_checked
    623
            assert_eq!(8_i8.sub_checked(2_i8).unwrap(), 6_i8);
    624
            assert_eq!(8_i16.sub_checked(2_i16).unwrap(), 6_i16);
    625
            assert_eq!(8_i32.sub_checked(2_i32).unwrap(), 6_i32);
    626
            assert_eq!(8_i64.sub_checked(2_i64).unwrap(), 6_i64);
    627
            assert_eq!(8_i128.sub_checked(2_i128).unwrap(), 6_i128);
    628
            assert_eq!(
    629
                i256::from_parts(8, 0)
    630
                    .sub_checked(i256::from_parts(2, 0))
    631
                    .unwrap(),
    632
                i256::from_parts(6, 0)
    633
            );
    634
            assert_eq!(8_u8.sub_checked(2_u8).unwrap(), 6_u8);
    635
            assert_eq!(8_u16.sub_checked(2_u16).unwrap(), 6_u16);
    636
            assert_eq!(8_u32.sub_checked(2_u32).unwrap(), 6_u32);
    637
            assert_eq!(8_u64.sub_checked(2_u64).unwrap(), 6_u64);
    638
            assert_eq!(
    639
                f16::from_f32(8.0).sub_checked(f16::from_f32(2.0)).unwrap(),
    640
                f16::from_f32(6.0)
    641
            );
    642
            assert_eq!(8.0_f32.sub_checked(2.0_f32).unwrap(), 6_f32);
    643
            assert_eq!(8.0_f64.sub_checked(2.0_f64).unwrap(), 6_f64);
    644
        }
    645
    646
        #[test]
    647
        fn test_native_type_mul() {
    648
            // mul_wrapping
    649
            assert_eq!(8_i8.mul_wrapping(2_i8), 16_i8);
    650
            assert_eq!(8_i16.mul_wrapping(2_i16), 16_i16);
    651
            assert_eq!(8_i32.mul_wrapping(2_i32), 16_i32);
    652
            assert_eq!(8_i64.mul_wrapping(2_i64), 16_i64);
    653
            assert_eq!(8_i128.mul_wrapping(2_i128), 16_i128);
    654
            assert_eq!(
    655
                i256::from_parts(8, 0).mul_wrapping(i256::from_parts(2, 0)),
    656
                i256::from_parts(16, 0)
    657
            );
    658
            assert_eq!(8_u8.mul_wrapping(2_u8), 16_u8);
    659
            assert_eq!(8_u16.mul_wrapping(2_u16), 16_u16);
    660
            assert_eq!(8_u32.mul_wrapping(2_u32), 16_u32);
    661
            assert_eq!(8_u64.mul_wrapping(2_u64), 16_u64);
    662
            assert_eq!(
    663
                f16::from_f32(8.0).mul_wrapping(f16::from_f32(2.0)),
    664
                f16::from_f32(16.0)
    665
            );
    666
            assert_eq!(8.0_f32.mul_wrapping(2.0_f32), 16_f32);
    667
            assert_eq!(8.0_f64.mul_wrapping(2.0_f64), 16_f64);
    668
    669
            // mul_checked
    670
            assert_eq!(8_i8.mul_checked(2_i8).unwrap(), 16_i8);
    671
            assert_eq!(8_i16.mul_checked(2_i16).unwrap(), 16_i16);
    672
            assert_eq!(8_i32.mul_checked(2_i32).unwrap(), 16_i32);
    673
            assert_eq!(8_i64.mul_checked(2_i64).unwrap(), 16_i64);
    674
            assert_eq!(8_i128.mul_checked(2_i128).unwrap(), 16_i128);
    675
            assert_eq!(
    676
                i256::from_parts(8, 0)
    677
                    .mul_checked(i256::from_parts(2, 0))
    678
                    .unwrap(),
    679
                i256::from_parts(16, 0)
    680
            );
    681
            assert_eq!(8_u8.mul_checked(2_u8).unwrap(), 16_u8);
    682
            assert_eq!(8_u16.mul_checked(2_u16).unwrap(), 16_u16);
    683
            assert_eq!(8_u32.mul_checked(2_u32).unwrap(), 16_u32);
    684
            assert_eq!(8_u64.mul_checked(2_u64).unwrap(), 16_u64);
    685
            assert_eq!(
    686
                f16::from_f32(8.0).mul_checked(f16::from_f32(2.0)).unwrap(),
    687
                f16::from_f32(16.0)
    688
            );
    689
            assert_eq!(8.0_f32.mul_checked(2.0_f32).unwrap(), 16_f32);
    690
            assert_eq!(8.0_f64.mul_checked(2.0_f64).unwrap(), 16_f64);
    691
        }
    692
    693
        #[test]
    694
        fn test_native_type_div() {
    695
            // div_wrapping
    696
            assert_eq!(8_i8.div_wrapping(2_i8), 4_i8);
    697
            assert_eq!(8_i16.div_wrapping(2_i16), 4_i16);
    698
            assert_eq!(8_i32.div_wrapping(2_i32), 4_i32);
    699
            assert_eq!(8_i64.div_wrapping(2_i64), 4_i64);
    700
            assert_eq!(8_i128.div_wrapping(2_i128), 4_i128);
    701
            assert_eq!(
    702
                i256::from_parts(8, 0).div_wrapping(i256::from_parts(2, 0)),
    703
                i256::from_parts(4, 0)
    704
            );
    705
            assert_eq!(8_u8.div_wrapping(2_u8), 4_u8);
    706
            assert_eq!(8_u16.div_wrapping(2_u16), 4_u16);
    707
            assert_eq!(8_u32.div_wrapping(2_u32), 4_u32);
    708
            assert_eq!(8_u64.div_wrapping(2_u64), 4_u64);
    709
            assert_eq!(
    710
                f16::from_f32(8.0).div_wrapping(f16::from_f32(2.0)),
    711
                f16::from_f32(4.0)
    712
            );
    713
            assert_eq!(8.0_f32.div_wrapping(2.0_f32), 4_f32);
    714
            assert_eq!(8.0_f64.div_wrapping(2.0_f64), 4_f64);
    715
    716
            // div_checked
    717
            assert_eq!(8_i8.div_checked(2_i8).unwrap(), 4_i8);
    718
            assert_eq!(8_i16.div_checked(2_i16).unwrap(), 4_i16);
    719
            assert_eq!(8_i32.div_checked(2_i32).unwrap(), 4_i32);
    720
            assert_eq!(8_i64.div_checked(2_i64).unwrap(), 4_i64);
    721
            assert_eq!(8_i128.div_checked(2_i128).unwrap(), 4_i128);
    722
            assert_eq!(
    723
                i256::from_parts(8, 0)
    724
                    .div_checked(i256::from_parts(2, 0))
    725
                    .unwrap(),
    726
                i256::from_parts(4, 0)
    727
            );
    728
            assert_eq!(8_u8.div_checked(2_u8).unwrap(), 4_u8);
    729
            assert_eq!(8_u16.div_checked(2_u16).unwrap(), 4_u16);
    730
            assert_eq!(8_u32.div_checked(2_u32).unwrap(), 4_u32);
    731
            assert_eq!(8_u64.div_checked(2_u64).unwrap(), 4_u64);
    732
            assert_eq!(
    733
                f16::from_f32(8.0).div_checked(f16::from_f32(2.0)).unwrap(),
    734
                f16::from_f32(4.0)
    735
            );
    736
            assert_eq!(8.0_f32.div_checked(2.0_f32).unwrap(), 4_f32);
    737
            assert_eq!(8.0_f64.div_checked(2.0_f64).unwrap(), 4_f64);
    738
        }
    739
    740
        #[test]
    741
        fn test_native_type_mod() {
    742
            // mod_wrapping
    743
            assert_eq!(9_i8.mod_wrapping(2_i8), 1_i8);
    744
            assert_eq!(9_i16.mod_wrapping(2_i16), 1_i16);
    745
            assert_eq!(9_i32.mod_wrapping(2_i32), 1_i32);
    746
            assert_eq!(9_i64.mod_wrapping(2_i64), 1_i64);
    747
            assert_eq!(9_i128.mod_wrapping(2_i128), 1_i128);
    748
            assert_eq!(
    749
                i256::from_parts(9, 0).mod_wrapping(i256::from_parts(2, 0)),
    750
                i256::from_parts(1, 0)
    751
            );
    752
            assert_eq!(9_u8.mod_wrapping(2_u8), 1_u8);
    753
            assert_eq!(9_u16.mod_wrapping(2_u16), 1_u16);
    754
            assert_eq!(9_u32.mod_wrapping(2_u32), 1_u32);
    755
            assert_eq!(9_u64.mod_wrapping(2_u64), 1_u64);
    756
            assert_eq!(
    757
                f16::from_f32(9.0).mod_wrapping(f16::from_f32(2.0)),
    758
                f16::from_f32(1.0)
    759
            );
    760
            assert_eq!(9.0_f32.mod_wrapping(2.0_f32), 1_f32);
    761
            assert_eq!(9.0_f64.mod_wrapping(2.0_f64), 1_f64);
    762
    763
            // mod_checked
    764
            assert_eq!(9_i8.mod_checked(2_i8).unwrap(), 1_i8);
    765
            assert_eq!(9_i16.mod_checked(2_i16).unwrap(), 1_i16);
    766
            assert_eq!(9_i32.mod_checked(2_i32).unwrap(), 1_i32);
    767
            assert_eq!(9_i64.mod_checked(2_i64).unwrap(), 1_i64);
    768
            assert_eq!(9_i128.mod_checked(2_i128).unwrap(), 1_i128);
    769
            assert_eq!(
    770
                i256::from_parts(9, 0)
    771
                    .mod_checked(i256::from_parts(2, 0))
    772
                    .unwrap(),
    773
                i256::from_parts(1, 0)
    774
            );
    775
            assert_eq!(9_u8.mod_checked(2_u8).unwrap(), 1_u8);
    776
            assert_eq!(9_u16.mod_checked(2_u16).unwrap(), 1_u16);
    777
            assert_eq!(9_u32.mod_checked(2_u32).unwrap(), 1_u32);
    778
            assert_eq!(9_u64.mod_checked(2_u64).unwrap(), 1_u64);
    779
            assert_eq!(
    780
                f16::from_f32(9.0).mod_checked(f16::from_f32(2.0)).unwrap(),
    781
                f16::from_f32(1.0)
    782
            );
    783
            assert_eq!(9.0_f32.mod_checked(2.0_f32).unwrap(), 1_f32);
    784
            assert_eq!(9.0_f64.mod_checked(2.0_f64).unwrap(), 1_f64);
    785
        }
    786
    787
        #[test]
    788
        fn test_native_type_neg() {
    789
            // neg_wrapping
    790
            assert_eq!(8_i8.neg_wrapping(), -8_i8);
    791
            assert_eq!(8_i16.neg_wrapping(), -8_i16);
    792
            assert_eq!(8_i32.neg_wrapping(), -8_i32);
    793
            assert_eq!(8_i64.neg_wrapping(), -8_i64);
    794
            assert_eq!(8_i128.neg_wrapping(), -8_i128);
    795
            assert_eq!(i256::from_parts(8, 0).neg_wrapping(), i256::from_i128(-8));
    796
            assert_eq!(8_u8.neg_wrapping(), u8::MAX - 7_u8);
    797
            assert_eq!(8_u16.neg_wrapping(), u16::MAX - 7_u16);
    798
            assert_eq!(8_u32.neg_wrapping(), u32::MAX - 7_u32);
    799
            assert_eq!(8_u64.neg_wrapping(), u64::MAX - 7_u64);
    800
            assert_eq!(f16::from_f32(8.0).neg_wrapping(), f16::from_f32(-8.0));
    801
            assert_eq!(8.0_f32.neg_wrapping(), -8_f32);
    802
            assert_eq!(8.0_f64.neg_wrapping(), -8_f64);
    803
    804
            // neg_checked
    805
            assert_eq!(8_i8.neg_checked().unwrap(), -8_i8);
    806
            assert_eq!(8_i16.neg_checked().unwrap(), -8_i16);
    807
            assert_eq!(8_i32.neg_checked().unwrap(), -8_i32);
    808
            assert_eq!(8_i64.neg_checked().unwrap(), -8_i64);
    809
            assert_eq!(8_i128.neg_checked().unwrap(), -8_i128);
    810
            assert_eq!(
    811
                i256::from_parts(8, 0).neg_checked().unwrap(),
    812
                i256::from_i128(-8)
    813
            );
    814
            assert!(8_u8.neg_checked().is_err());
    815
            assert!(8_u16.neg_checked().is_err());
    816
            assert!(8_u32.neg_checked().is_err());
    817
            assert!(8_u64.neg_checked().is_err());
    818
            assert_eq!(
    819
                f16::from_f32(8.0).neg_checked().unwrap(),
    820
                f16::from_f32(-8.0)
    821
            );
    822
            assert_eq!(8.0_f32.neg_checked().unwrap(), -8_f32);
    823
            assert_eq!(8.0_f64.neg_checked().unwrap(), -8_f64);
    824
        }
    825
    826
        #[test]
    827
        fn test_native_type_pow() {
    828
            // pow_wrapping
    829
            assert_eq!(8_i8.pow_wrapping(2_u32), 64_i8);
    830
            assert_eq!(8_i16.pow_wrapping(2_u32), 64_i16);
    831
            assert_eq!(8_i32.pow_wrapping(2_u32), 64_i32);
    832
            assert_eq!(8_i64.pow_wrapping(2_u32), 64_i64);
    833
            assert_eq!(8_i128.pow_wrapping(2_u32), 64_i128);
    834
            assert_eq!(
    835
                i256::from_parts(8, 0).pow_wrapping(2_u32),
    836
                i256::from_parts(64, 0)
    837
            );
    838
            assert_eq!(8_u8.pow_wrapping(2_u32), 64_u8);
    839
            assert_eq!(8_u16.pow_wrapping(2_u32), 64_u16);
    840
            assert_eq!(8_u32.pow_wrapping(2_u32), 64_u32);
    841
            assert_eq!(8_u64.pow_wrapping(2_u32), 64_u64);
    842
            assert_approx_eq!(f16::from_f32(8.0).pow_wrapping(2_u32), f16::from_f32(64.0));
    843
            assert_approx_eq!(8.0_f32.pow_wrapping(2_u32), 64_f32);
    844
            assert_approx_eq!(8.0_f64.pow_wrapping(2_u32), 64_f64);
    845
    846
            // pow_checked
    847
            assert_eq!(8_i8.pow_checked(2_u32).unwrap(), 64_i8);
    848
            assert_eq!(8_i16.pow_checked(2_u32).unwrap(), 64_i16);
    849
            assert_eq!(8_i32.pow_checked(2_u32).unwrap(), 64_i32);
    850
            assert_eq!(8_i64.pow_checked(2_u32).unwrap(), 64_i64);
    851
            assert_eq!(8_i128.pow_checked(2_u32).unwrap(), 64_i128);
    852
            assert_eq!(
    853
                i256::from_parts(8, 0).pow_checked(2_u32).unwrap(),
    854
                i256::from_parts(64, 0)
    855
            );
    856
            assert_eq!(8_u8.pow_checked(2_u32).unwrap(), 64_u8);
    857
            assert_eq!(8_u16.pow_checked(2_u32).unwrap(), 64_u16);
    858
            assert_eq!(8_u32.pow_checked(2_u32).unwrap(), 64_u32);
    859
            assert_eq!(8_u64.pow_checked(2_u32).unwrap(), 64_u64);
    860
            assert_approx_eq!(
    861
                f16::from_f32(8.0).pow_checked(2_u32).unwrap(),
    862
                f16::from_f32(64.0)
    863
            );
    864
            assert_approx_eq!(8.0_f32.pow_checked(2_u32).unwrap(), 64_f32);
    865
            assert_approx_eq!(8.0_f64.pow_checked(2_u32).unwrap(), 64_f64);
    866
        }
    867
    868
        #[test]
    869
        fn test_float_total_order_min_max() {
    870
            assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f64::NEG_INFINITY));
    871
            assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f64::INFINITY));
    872
    873
            assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
    874
            assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
    875
            assert!(<f64 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f64::NAN));
    876
    877
            assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
    878
            assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
    879
            assert!(<f64 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f64::NAN));
    880
    881
            assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f32::NEG_INFINITY));
    882
            assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f32::INFINITY));
    883
    884
            assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
    885
            assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
    886
            assert!(<f32 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f32::NAN));
    887
    888
            assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
    889
            assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
    890
            assert!(<f32 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f32::NAN));
    891
    892
            assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(f16::NEG_INFINITY));
    893
            assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f16::INFINITY));
    894
    895
            assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_nan());
    896
            assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_sign_negative());
    897
            assert!(<f16 as ArrowNativeTypeOp>::MIN_TOTAL_ORDER.is_lt(-f16::NAN));
    898
    899
            assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_nan());
    900
            assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_sign_positive());
    901
            assert!(<f16 as ArrowNativeTypeOp>::MAX_TOTAL_ORDER.is_gt(f16::NAN));
    902
        }
    903
    }