Coverage Report

Created: 2025-08-26 07:03

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::{i256, ArrowNativeType, IntervalDayTime, IntervalMonthDayNano};
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
51
    fn is_lt(self, rhs: Self) -> bool {
118
51
        self.compare(rhs).is_lt()
119
51
    }
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
0
            fn add_checked(self, rhs: Self) -> Result<Self, ArrowError> {
156
0
                self.checked_add(rhs).ok_or_else(|| {
157
0
                    ArrowError::ArithmeticOverflow(format!(
158
0
                        "Overflow happened on: {:?} + {:?}",
159
0
                        self, rhs
160
0
                    ))
161
0
                })
162
0
            }
163
164
            #[inline]
165
0
            fn add_wrapping(self, rhs: Self) -> Self {
166
0
                self.wrapping_add(rhs)
167
0
            }
168
169
            #[inline]
170
0
            fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
171
0
                self.checked_sub(rhs).ok_or_else(|| {
172
0
                    ArrowError::ArithmeticOverflow(format!(
173
0
                        "Overflow happened on: {:?} - {:?}",
174
0
                        self, rhs
175
0
                    ))
176
0
                })
177
0
            }
178
179
            #[inline]
180
0
            fn sub_wrapping(self, rhs: Self) -> Self {
181
0
                self.wrapping_sub(rhs)
182
0
            }
183
184
            #[inline]
185
0
            fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
186
0
                self.checked_mul(rhs).ok_or_else(|| {
187
0
                    ArrowError::ArithmeticOverflow(format!(
188
0
                        "Overflow happened on: {:?} * {:?}",
189
0
                        self, rhs
190
0
                    ))
191
0
                })
192
0
            }
193
194
            #[inline]
195
0
            fn mul_wrapping(self, rhs: Self) -> Self {
196
0
                self.wrapping_mul(rhs)
197
0
            }
198
199
            #[inline]
200
0
            fn div_checked(self, rhs: Self) -> Result<Self, ArrowError> {
201
0
                if rhs.is_zero() {
202
0
                    Err(ArrowError::DivideByZero)
203
                } else {
204
0
                    self.checked_div(rhs).ok_or_else(|| {
205
0
                        ArrowError::ArithmeticOverflow(format!(
206
0
                            "Overflow happened on: {:?} / {:?}",
207
0
                            self, rhs
208
0
                        ))
209
0
                    })
210
                }
211
0
            }
212
213
            #[inline]
214
0
            fn div_wrapping(self, rhs: Self) -> Self {
215
0
                self.wrapping_div(rhs)
216
0
            }
217
218
            #[inline]
219
0
            fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError> {
220
0
                if rhs.is_zero() {
221
0
                    Err(ArrowError::DivideByZero)
222
                } else {
223
0
                    self.checked_rem(rhs).ok_or_else(|| {
224
0
                        ArrowError::ArithmeticOverflow(format!(
225
0
                            "Overflow happened on: {:?} % {:?}",
226
0
                            self, rhs
227
0
                        ))
228
0
                    })
229
                }
230
0
            }
231
232
            #[inline]
233
0
            fn mod_wrapping(self, rhs: Self) -> Self {
234
0
                self.wrapping_rem(rhs)
235
0
            }
236
237
            #[inline]
238
0
            fn neg_checked(self) -> Result<Self, ArrowError> {
239
0
                self.checked_neg().ok_or_else(|| {
240
0
                    ArrowError::ArithmeticOverflow(format!("Overflow happened on: - {:?}", self))
241
0
                })
242
0
            }
243
244
            #[inline]
245
0
            fn pow_checked(self, exp: u32) -> Result<Self, ArrowError> {
246
0
                self.checked_pow(exp).ok_or_else(|| {
247
0
                    ArrowError::ArithmeticOverflow(format!(
248
0
                        "Overflow happened on: {:?} ^ {exp:?}",
249
0
                        self
250
0
                    ))
251
0
                })
252
0
            }
253
254
            #[inline]
255
0
            fn pow_wrapping(self, exp: u32) -> Self {
256
0
                self.wrapping_pow(exp)
257
0
            }
258
259
            #[inline]
260
0
            fn neg_wrapping(self) -> Self {
261
0
                self.wrapping_neg()
262
0
            }
263
264
            #[inline]
265
0
            fn is_zero(self) -> bool {
266
0
                self == Self::ZERO
267
0
            }
268
269
            #[inline]
270
51
            fn compare(self, rhs: Self) -> Ordering {
271
51
                self.cmp(&rhs)
272
51
            }
273
274
            #[inline]
275
0
            fn is_eq(self, rhs: Self) -> bool {
276
0
                self == rhs
277
0
            }
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, i256::MIN, i256::MAX);
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
0
            fn add_wrapping(self, rhs: Self) -> Self {
315
0
                self + rhs
316
0
            }
317
318
            #[inline]
319
            fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
320
                Ok(self - rhs)
321
            }
322
323
            #[inline]
324
0
            fn sub_wrapping(self, rhs: Self) -> Self {
325
0
                self - rhs
326
0
            }
327
328
            #[inline]
329
            fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
330
                Ok(self * rhs)
331
            }
332
333
            #[inline]
334
0
            fn mul_wrapping(self, rhs: Self) -> Self {
335
0
                self * rhs
336
0
            }
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
0
            fn div_wrapping(self, rhs: Self) -> Self {
349
0
                self / rhs
350
0
            }
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
0
            fn mod_wrapping(self, rhs: Self) -> Self {
363
0
                self % rhs
364
0
            }
365
366
            #[inline]
367
            fn neg_checked(self) -> Result<Self, ArrowError> {
368
                Ok(-self)
369
            }
370
371
            #[inline]
372
0
            fn neg_wrapping(self) -> Self {
373
0
                -self
374
0
            }
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
0
            fn compare(self, rhs: Self) -> Ordering {
393
0
                <$t>::total_cmp(&self, &rhs)
394
0
            }
395
396
            #[inline]
397
0
            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
0
                self.to_bits() == rhs.to_bits()
402
0
            }
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.84.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.84.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.84.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.84.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 ) => {{
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
}