Thanks to visit codestin.com
Credit goes to docs.rs

arrow2/compute/arithmetics/basic/
rem.rs

1use std::ops::Rem;
2
3use num_traits::{CheckedRem, NumCast};
4
5use crate::datatypes::PrimitiveType;
6use crate::{
7    array::{Array, PrimitiveArray},
8    compute::{
9        arithmetics::{ArrayCheckedRem, ArrayRem},
10        arity::{binary, binary_checked, unary, unary_checked},
11    },
12};
13use strength_reduce::{
14    StrengthReducedU16, StrengthReducedU32, StrengthReducedU64, StrengthReducedU8,
15};
16
17use super::NativeArithmetics;
18
19/// Remainder of two primitive arrays with the same type.
20/// Panics if the divisor is zero of one pair of values overflows.
21///
22/// # Examples
23/// ```
24/// use arrow2::compute::arithmetics::basic::rem;
25/// use arrow2::array::Int32Array;
26///
27/// let a = Int32Array::from(&[Some(10), Some(7)]);
28/// let b = Int32Array::from(&[Some(5), Some(6)]);
29/// let result = rem(&a, &b);
30/// let expected = Int32Array::from(&[Some(0), Some(1)]);
31/// assert_eq!(result, expected)
32/// ```
33pub fn rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
34where
35    T: NativeArithmetics + Rem<Output = T>,
36{
37    binary(lhs, rhs, lhs.data_type().clone(), |a, b| a % b)
38}
39
40/// Checked remainder of two primitive arrays. If the result from the remainder
41/// overflows, the result for the operation will change the validity array
42/// making this operation None
43///
44/// # Examples
45/// ```
46/// use arrow2::compute::arithmetics::basic::checked_rem;
47/// use arrow2::array::Int8Array;
48///
49/// let a = Int8Array::from(&[Some(-100i8), Some(10i8)]);
50/// let b = Int8Array::from(&[Some(100i8), Some(0i8)]);
51/// let result = checked_rem(&a, &b);
52/// let expected = Int8Array::from(&[Some(-0i8), None]);
53/// assert_eq!(result, expected);
54/// ```
55pub fn checked_rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
56where
57    T: NativeArithmetics + CheckedRem<Output = T>,
58{
59    let op = move |a: T, b: T| a.checked_rem(&b);
60
61    binary_checked(lhs, rhs, lhs.data_type().clone(), op)
62}
63
64impl<T> ArrayRem<PrimitiveArray<T>> for PrimitiveArray<T>
65where
66    T: NativeArithmetics + Rem<Output = T>,
67{
68    fn rem(&self, rhs: &PrimitiveArray<T>) -> Self {
69        rem(self, rhs)
70    }
71}
72
73impl<T> ArrayCheckedRem<PrimitiveArray<T>> for PrimitiveArray<T>
74where
75    T: NativeArithmetics + CheckedRem<Output = T>,
76{
77    fn checked_rem(&self, rhs: &PrimitiveArray<T>) -> Self {
78        checked_rem(self, rhs)
79    }
80}
81
82/// Remainder a primitive array of type T by a scalar T.
83/// Panics if the divisor is zero.
84///
85/// # Examples
86/// ```
87/// use arrow2::compute::arithmetics::basic::rem_scalar;
88/// use arrow2::array::Int32Array;
89///
90/// let a = Int32Array::from(&[None, Some(6), None, Some(7)]);
91/// let result = rem_scalar(&a, &2i32);
92/// let expected = Int32Array::from(&[None, Some(0), None, Some(1)]);
93/// assert_eq!(result, expected)
94/// ```
95pub fn rem_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
96where
97    T: NativeArithmetics + Rem<Output = T> + NumCast,
98{
99    let rhs = *rhs;
100
101    match T::PRIMITIVE {
102        PrimitiveType::UInt64 => {
103            let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u64>>().unwrap();
104            let rhs = rhs.to_u64().unwrap();
105
106            let reduced_rem = StrengthReducedU64::new(rhs);
107
108            // small hack to avoid a transmute of `PrimitiveArray<u64>` to `PrimitiveArray<T>`
109            let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
110            (&r as &dyn Array)
111                .as_any()
112                .downcast_ref::<PrimitiveArray<T>>()
113                .unwrap()
114                .clone()
115        }
116        PrimitiveType::UInt32 => {
117            let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u32>>().unwrap();
118            let rhs = rhs.to_u32().unwrap();
119
120            let reduced_rem = StrengthReducedU32::new(rhs);
121
122            let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
123            // small hack to avoid an unsafe transmute of `PrimitiveArray<u64>` to `PrimitiveArray<T>`
124            (&r as &dyn Array)
125                .as_any()
126                .downcast_ref::<PrimitiveArray<T>>()
127                .unwrap()
128                .clone()
129        }
130        PrimitiveType::UInt16 => {
131            let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u16>>().unwrap();
132            let rhs = rhs.to_u16().unwrap();
133
134            let reduced_rem = StrengthReducedU16::new(rhs);
135
136            let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
137            // small hack to avoid an unsafe transmute of `PrimitiveArray<u16>` to `PrimitiveArray<T>`
138            (&r as &dyn Array)
139                .as_any()
140                .downcast_ref::<PrimitiveArray<T>>()
141                .unwrap()
142                .clone()
143        }
144        PrimitiveType::UInt8 => {
145            let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u8>>().unwrap();
146            let rhs = rhs.to_u8().unwrap();
147
148            let reduced_rem = StrengthReducedU8::new(rhs);
149
150            let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
151            // small hack to avoid an unsafe transmute of `PrimitiveArray<u8>` to `PrimitiveArray<T>`
152            (&r as &dyn Array)
153                .as_any()
154                .downcast_ref::<PrimitiveArray<T>>()
155                .unwrap()
156                .clone()
157        }
158        _ => unary(lhs, |a| a % rhs, lhs.data_type().clone()),
159    }
160}
161
162/// Checked remainder of a primitive array of type T by a scalar T. If the
163/// divisor is zero then the validity array is changed to None.
164///
165/// # Examples
166/// ```
167/// use arrow2::compute::arithmetics::basic::checked_rem_scalar;
168/// use arrow2::array::Int8Array;
169///
170/// let a = Int8Array::from(&[Some(-100i8)]);
171/// let result = checked_rem_scalar(&a, &100i8);
172/// let expected = Int8Array::from(&[Some(0i8)]);
173/// assert_eq!(result, expected);
174/// ```
175pub fn checked_rem_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
176where
177    T: NativeArithmetics + CheckedRem<Output = T>,
178{
179    let rhs = *rhs;
180    let op = move |a: T| a.checked_rem(&rhs);
181
182    unary_checked(lhs, op, lhs.data_type().clone())
183}
184
185impl<T> ArrayRem<T> for PrimitiveArray<T>
186where
187    T: NativeArithmetics + Rem<Output = T> + NumCast,
188{
189    fn rem(&self, rhs: &T) -> Self {
190        rem_scalar(self, rhs)
191    }
192}
193
194impl<T> ArrayCheckedRem<T> for PrimitiveArray<T>
195where
196    T: NativeArithmetics + CheckedRem<Output = T>,
197{
198    fn checked_rem(&self, rhs: &T) -> Self {
199        checked_rem_scalar(self, rhs)
200    }
201}