arrow2/compute/arithmetics/basic/mul.rs
1//! Definition of basic mul operations with primitive arrays
2use std::ops::Mul;
3
4use num_traits::{ops::overflowing::OverflowingMul, CheckedMul, SaturatingMul, WrappingMul};
5
6use crate::{
7 array::PrimitiveArray,
8 bitmap::Bitmap,
9 compute::{
10 arithmetics::{
11 ArrayCheckedMul, ArrayMul, ArrayOverflowingMul, ArraySaturatingMul, ArrayWrappingMul,
12 },
13 arity::{
14 binary, binary_checked, binary_with_bitmap, unary, unary_checked, unary_with_bitmap,
15 },
16 },
17};
18
19use super::NativeArithmetics;
20
21/// Multiplies two primitive arrays with the same type.
22/// Panics if the multiplication of one pair of values overflows.
23///
24/// # Examples
25/// ```
26/// use arrow2::compute::arithmetics::basic::mul;
27/// use arrow2::array::Int32Array;
28///
29/// let a = Int32Array::from(&[None, Some(6), None, Some(6)]);
30/// let b = Int32Array::from(&[Some(5), None, None, Some(6)]);
31/// let result = mul(&a, &b);
32/// let expected = Int32Array::from(&[None, None, None, Some(36)]);
33/// assert_eq!(result, expected)
34/// ```
35pub fn mul<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
36where
37 T: NativeArithmetics + Mul<Output = T>,
38{
39 binary(lhs, rhs, lhs.data_type().clone(), |a, b| a * b)
40}
41
42/// Wrapping multiplication of two [`PrimitiveArray`]s.
43/// It wraps around at the boundary of the type if the result overflows.
44///
45/// # Examples
46/// ```
47/// use arrow2::compute::arithmetics::basic::wrapping_mul;
48/// use arrow2::array::PrimitiveArray;
49///
50/// let a = PrimitiveArray::from([Some(100i8), Some(0x10i8), Some(100i8)]);
51/// let b = PrimitiveArray::from([Some(0i8), Some(0x10i8), Some(0i8)]);
52/// let result = wrapping_mul(&a, &b);
53/// let expected = PrimitiveArray::from([Some(0), Some(0), Some(0)]);
54/// assert_eq!(result, expected);
55/// ```
56pub fn wrapping_mul<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
57where
58 T: NativeArithmetics + WrappingMul<Output = T>,
59{
60 let op = move |a: T, b: T| a.wrapping_mul(&b);
61
62 binary(lhs, rhs, lhs.data_type().clone(), op)
63}
64
65/// Checked multiplication of two primitive arrays. If the result from the
66/// multiplications overflows, the validity for that index is changed
67/// returned.
68///
69/// # Examples
70/// ```
71/// use arrow2::compute::arithmetics::basic::checked_mul;
72/// use arrow2::array::Int8Array;
73///
74/// let a = Int8Array::from(&[Some(100i8), Some(100i8), Some(100i8)]);
75/// let b = Int8Array::from(&[Some(1i8), Some(100i8), Some(1i8)]);
76/// let result = checked_mul(&a, &b);
77/// let expected = Int8Array::from(&[Some(100i8), None, Some(100i8)]);
78/// assert_eq!(result, expected);
79/// ```
80pub fn checked_mul<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
81where
82 T: NativeArithmetics + CheckedMul<Output = T>,
83{
84 let op = move |a: T, b: T| a.checked_mul(&b);
85
86 binary_checked(lhs, rhs, lhs.data_type().clone(), op)
87}
88
89/// Saturating multiplication of two primitive arrays. If the result from the
90/// multiplication overflows, the result for the
91/// operation will be the saturated value.
92///
93/// # Examples
94/// ```
95/// use arrow2::compute::arithmetics::basic::saturating_mul;
96/// use arrow2::array::Int8Array;
97///
98/// let a = Int8Array::from(&[Some(-100i8)]);
99/// let b = Int8Array::from(&[Some(100i8)]);
100/// let result = saturating_mul(&a, &b);
101/// let expected = Int8Array::from(&[Some(-128)]);
102/// assert_eq!(result, expected);
103/// ```
104pub fn saturating_mul<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
105where
106 T: NativeArithmetics + SaturatingMul<Output = T>,
107{
108 let op = move |a: T, b: T| a.saturating_mul(&b);
109
110 binary(lhs, rhs, lhs.data_type().clone(), op)
111}
112
113/// Overflowing multiplication of two primitive arrays. If the result from the
114/// mul overflows, the result for the operation will be an array with
115/// overflowed values and a validity array indicating the overflowing elements
116/// from the array.
117///
118/// # Examples
119/// ```
120/// use arrow2::compute::arithmetics::basic::overflowing_mul;
121/// use arrow2::array::Int8Array;
122///
123/// let a = Int8Array::from(&[Some(1i8), Some(-100i8)]);
124/// let b = Int8Array::from(&[Some(1i8), Some(100i8)]);
125/// let (result, overflow) = overflowing_mul(&a, &b);
126/// let expected = Int8Array::from(&[Some(1i8), Some(-16i8)]);
127/// assert_eq!(result, expected);
128/// ```
129pub fn overflowing_mul<T>(
130 lhs: &PrimitiveArray<T>,
131 rhs: &PrimitiveArray<T>,
132) -> (PrimitiveArray<T>, Bitmap)
133where
134 T: NativeArithmetics + OverflowingMul<Output = T>,
135{
136 let op = move |a: T, b: T| a.overflowing_mul(&b);
137
138 binary_with_bitmap(lhs, rhs, lhs.data_type().clone(), op)
139}
140
141// Implementation of ArrayMul trait for PrimitiveArrays
142impl<T> ArrayMul<PrimitiveArray<T>> for PrimitiveArray<T>
143where
144 T: NativeArithmetics + Mul<Output = T>,
145{
146 fn mul(&self, rhs: &PrimitiveArray<T>) -> Self {
147 mul(self, rhs)
148 }
149}
150
151impl<T> ArrayWrappingMul<PrimitiveArray<T>> for PrimitiveArray<T>
152where
153 T: NativeArithmetics + WrappingMul<Output = T>,
154{
155 fn wrapping_mul(&self, rhs: &PrimitiveArray<T>) -> Self {
156 wrapping_mul(self, rhs)
157 }
158}
159
160// Implementation of ArrayCheckedMul trait for PrimitiveArrays
161impl<T> ArrayCheckedMul<PrimitiveArray<T>> for PrimitiveArray<T>
162where
163 T: NativeArithmetics + CheckedMul<Output = T>,
164{
165 fn checked_mul(&self, rhs: &PrimitiveArray<T>) -> Self {
166 checked_mul(self, rhs)
167 }
168}
169
170// Implementation of ArraySaturatingMul trait for PrimitiveArrays
171impl<T> ArraySaturatingMul<PrimitiveArray<T>> for PrimitiveArray<T>
172where
173 T: NativeArithmetics + SaturatingMul<Output = T>,
174{
175 fn saturating_mul(&self, rhs: &PrimitiveArray<T>) -> Self {
176 saturating_mul(self, rhs)
177 }
178}
179
180// Implementation of ArraySaturatingMul trait for PrimitiveArrays
181impl<T> ArrayOverflowingMul<PrimitiveArray<T>> for PrimitiveArray<T>
182where
183 T: NativeArithmetics + OverflowingMul<Output = T>,
184{
185 fn overflowing_mul(&self, rhs: &PrimitiveArray<T>) -> (Self, Bitmap) {
186 overflowing_mul(self, rhs)
187 }
188}
189
190/// Multiply a scalar T to a primitive array of type T.
191/// Panics if the multiplication of the values overflows.
192///
193/// # Examples
194/// ```
195/// use arrow2::compute::arithmetics::basic::mul_scalar;
196/// use arrow2::array::Int32Array;
197///
198/// let a = Int32Array::from(&[None, Some(6), None, Some(6)]);
199/// let result = mul_scalar(&a, &2i32);
200/// let expected = Int32Array::from(&[None, Some(12), None, Some(12)]);
201/// assert_eq!(result, expected)
202/// ```
203pub fn mul_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
204where
205 T: NativeArithmetics + Mul<Output = T>,
206{
207 let rhs = *rhs;
208 unary(lhs, |a| a * rhs, lhs.data_type().clone())
209}
210
211/// Wrapping multiplication of a scalar T to a [`PrimitiveArray`] of type T.
212/// It do nothing if the result overflows.
213///
214/// # Examples
215/// ```
216/// use arrow2::compute::arithmetics::basic::wrapping_mul_scalar;
217/// use arrow2::array::Int8Array;
218///
219/// let a = Int8Array::from(&[None, Some(0x10)]);
220/// let result = wrapping_mul_scalar(&a, &0x10);
221/// let expected = Int8Array::from(&[None, Some(0)]);
222/// assert_eq!(result, expected);
223/// ```
224pub fn wrapping_mul_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
225where
226 T: NativeArithmetics + WrappingMul<Output = T>,
227{
228 unary(lhs, |a| a.wrapping_mul(rhs), lhs.data_type().clone())
229}
230
231/// Checked multiplication of a scalar T to a primitive array of type T. If the
232/// result from the multiplication overflows, then the validity for that index is
233/// changed to None
234///
235/// # Examples
236/// ```
237/// use arrow2::compute::arithmetics::basic::checked_mul_scalar;
238/// use arrow2::array::Int8Array;
239///
240/// let a = Int8Array::from(&[None, Some(100), None, Some(100)]);
241/// let result = checked_mul_scalar(&a, &100i8);
242/// let expected = Int8Array::from(&[None, None, None, None]);
243/// assert_eq!(result, expected);
244/// ```
245pub fn checked_mul_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
246where
247 T: NativeArithmetics + CheckedMul<Output = T>,
248{
249 let rhs = *rhs;
250 let op = move |a: T| a.checked_mul(&rhs);
251
252 unary_checked(lhs, op, lhs.data_type().clone())
253}
254
255/// Saturated multiplication of a scalar T to a primitive array of type T. If the
256/// result from the mul overflows for this type, then
257/// the result will be saturated
258///
259/// # Examples
260/// ```
261/// use arrow2::compute::arithmetics::basic::saturating_mul_scalar;
262/// use arrow2::array::Int8Array;
263///
264/// let a = Int8Array::from(&[Some(-100i8)]);
265/// let result = saturating_mul_scalar(&a, &100i8);
266/// let expected = Int8Array::from(&[Some(-128i8)]);
267/// assert_eq!(result, expected);
268/// ```
269pub fn saturating_mul_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
270where
271 T: NativeArithmetics + SaturatingMul<Output = T>,
272{
273 let rhs = *rhs;
274 let op = move |a: T| a.saturating_mul(&rhs);
275
276 unary(lhs, op, lhs.data_type().clone())
277}
278
279/// Overflowing multiplication of a scalar T to a primitive array of type T. If
280/// the result from the mul overflows for this type,
281/// then the result will be an array with overflowed values and a validity
282/// array indicating the overflowing elements from the array
283///
284/// # Examples
285/// ```
286/// use arrow2::compute::arithmetics::basic::overflowing_mul_scalar;
287/// use arrow2::array::Int8Array;
288///
289/// let a = Int8Array::from(&[Some(1i8), Some(100i8)]);
290/// let (result, overflow) = overflowing_mul_scalar(&a, &100i8);
291/// let expected = Int8Array::from(&[Some(100i8), Some(16i8)]);
292/// assert_eq!(result, expected);
293/// ```
294pub fn overflowing_mul_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> (PrimitiveArray<T>, Bitmap)
295where
296 T: NativeArithmetics + OverflowingMul<Output = T>,
297{
298 let rhs = *rhs;
299 let op = move |a: T| a.overflowing_mul(&rhs);
300
301 unary_with_bitmap(lhs, op, lhs.data_type().clone())
302}
303
304// Implementation of ArrayMul trait for PrimitiveArrays with a scalar
305impl<T> ArrayMul<T> for PrimitiveArray<T>
306where
307 T: NativeArithmetics + Mul<Output = T>,
308{
309 fn mul(&self, rhs: &T) -> Self {
310 mul_scalar(self, rhs)
311 }
312}
313
314// Implementation of ArrayCheckedMul trait for PrimitiveArrays with a scalar
315impl<T> ArrayCheckedMul<T> for PrimitiveArray<T>
316where
317 T: NativeArithmetics + CheckedMul<Output = T>,
318{
319 fn checked_mul(&self, rhs: &T) -> Self {
320 checked_mul_scalar(self, rhs)
321 }
322}
323
324// Implementation of ArraySaturatingMul trait for PrimitiveArrays with a scalar
325impl<T> ArraySaturatingMul<T> for PrimitiveArray<T>
326where
327 T: NativeArithmetics + SaturatingMul<Output = T>,
328{
329 fn saturating_mul(&self, rhs: &T) -> Self {
330 saturating_mul_scalar(self, rhs)
331 }
332}
333
334// Implementation of ArraySaturatingMul trait for PrimitiveArrays with a scalar
335impl<T> ArrayOverflowingMul<T> for PrimitiveArray<T>
336where
337 T: NativeArithmetics + OverflowingMul<Output = T>,
338{
339 fn overflowing_mul(&self, rhs: &T) -> (Self, Bitmap) {
340 overflowing_mul_scalar(self, rhs)
341 }
342}