This is an automated email from the ASF dual-hosted git repository.

viirya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new b7f4cbf87 Add modulus_dyn and modulus_scalar_dyn (#3649)
b7f4cbf87 is described below

commit b7f4cbf876fb3adcbb68fa6aff7f045a9c17a6fb
Author: Liang-Chi Hsieh <[email protected]>
AuthorDate: Sun Feb 5 00:09:03 2023 -0800

    Add modulus_dyn and modulus_scalar_dyn (#3649)
---
 arrow-arith/src/arithmetic.rs | 106 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 105 insertions(+), 1 deletion(-)

diff --git a/arrow-arith/src/arithmetic.rs b/arrow-arith/src/arithmetic.rs
index 48f0412bf..0db32d575 100644
--- a/arrow-arith/src/arithmetic.rs
+++ b/arrow-arith/src/arithmetic.rs
@@ -1333,6 +1333,45 @@ where
     });
 }
 
+/// Perform `left % right` operation on two arrays. If either left or right 
value is null
+/// then the result is also null. If any right hand value is zero then the 
result of this
+/// operation will be `Err(ArrowError::DivideByZero)`.
+pub fn modulus_dyn(left: &dyn Array, right: &dyn Array) -> Result<ArrayRef, 
ArrowError> {
+    match left.data_type() {
+        DataType::Dictionary(_, _) => {
+            typed_dict_math_op!(
+                left,
+                right,
+                |a, b| {
+                    if b.is_zero() {
+                        Err(ArrowError::DivideByZero)
+                    } else {
+                        Ok(a.mod_wrapping(b))
+                    }
+                },
+                math_divide_checked_op_dict
+            )
+        }
+        _ => {
+            downcast_primitive_array!(
+                (left, right) => {
+                    math_checked_divide_op(left, right, |a, b| {
+                        if b.is_zero() {
+                            Err(ArrowError::DivideByZero)
+                        } else {
+                            Ok(a.mod_wrapping(b))
+                        }
+                    }).map(|a| Arc::new(a) as ArrayRef)
+                }
+                _ => Err(ArrowError::CastError(format!(
+                    "Unsupported data type {}, {}",
+                    left.data_type(), right.data_type()
+                )))
+            )
+        }
+    }
+}
+
 /// Perform `left / right` operation on two arrays. If either left or right 
value is null
 /// then the result is also null. If any right hand value is zero then the 
result of this
 /// operation will be `Err(ArrowError::DivideByZero)`.
@@ -1551,6 +1590,23 @@ where
     Ok(unary(array, |a| a.mod_wrapping(modulo)))
 }
 
+/// Modulus every value in an array by a scalar. If any value in the array is 
null then the
+/// result is also null. If the scalar is zero then the result of this 
operation will be
+/// `Err(ArrowError::DivideByZero)`.
+pub fn modulus_scalar_dyn<T>(
+    array: &dyn Array,
+    modulo: T::Native,
+) -> Result<ArrayRef, ArrowError>
+where
+    T: ArrowNumericType,
+    T::Native: ArrowNativeTypeOp,
+{
+    if modulo.is_zero() {
+        return Err(ArrowError::DivideByZero);
+    }
+    unary_dyn::<_, T>(array, |value| value.mod_wrapping(modulo))
+}
+
 /// Divide every value in an array by a scalar. If any value in the array is 
null then the
 /// result is also null. If the scalar is zero then the result of this 
operation will be
 /// `Err(ArrowError::DivideByZero)`.
@@ -2170,6 +2226,14 @@ mod tests {
         assert_eq!(0, c.value(2));
         assert_eq!(1, c.value(3));
         assert_eq!(0, c.value(4));
+
+        let c = modulus_dyn(&a, &b).unwrap();
+        let c = as_primitive_array::<Int32Type>(&c);
+        assert_eq!(0, c.value(0));
+        assert_eq!(3, c.value(1));
+        assert_eq!(0, c.value(2));
+        assert_eq!(1, c.value(3));
+        assert_eq!(0, c.value(4));
     }
 
     #[test]
@@ -2182,6 +2246,16 @@ mod tests {
         modulus(&a, &b).unwrap();
     }
 
+    #[test]
+    #[should_panic(
+        expected = "called `Result::unwrap()` on an `Err` value: DivideByZero"
+    )]
+    fn test_int_array_modulus_dyn_divide_by_zero() {
+        let a = Int32Array::from(vec![1]);
+        let b = Int32Array::from(vec![0]);
+        modulus_dyn(&a, &b).unwrap();
+    }
+
     #[test]
     fn test_int_array_modulus_overflow_wrapping() {
         let a = Int32Array::from(vec![i32::MIN]);
@@ -2258,6 +2332,11 @@ mod tests {
         let c = modulus_scalar(&a, b).unwrap();
         let expected = Int32Array::from(vec![0, 2, 0, 2, 1]);
         assert_eq!(c, expected);
+
+        let c = modulus_scalar_dyn::<Int32Type>(&a, b).unwrap();
+        let c = as_primitive_array::<Int32Type>(&c);
+        let expected = Int32Array::from(vec![0, 2, 0, 2, 1]);
+        assert_eq!(c, &expected);
     }
 
     #[test]
@@ -2268,6 +2347,11 @@ mod tests {
         let actual = modulus_scalar(a, 3).unwrap();
         let expected = Int32Array::from(vec![None, Some(0), Some(2), None]);
         assert_eq!(actual, expected);
+
+        let actual = modulus_scalar_dyn::<Int32Type>(a, 3).unwrap();
+        let actual = as_primitive_array::<Int32Type>(&actual);
+        let expected = Int32Array::from(vec![None, Some(0), Some(2), None]);
+        assert_eq!(actual, &expected);
     }
 
     #[test]
@@ -2283,7 +2367,11 @@ mod tests {
     fn test_int_array_modulus_scalar_overflow_wrapping() {
         let a = Int32Array::from(vec![i32::MIN]);
         let result = modulus_scalar(&a, -1).unwrap();
-        assert_eq!(0, result.value(0))
+        assert_eq!(0, result.value(0));
+
+        let result = modulus_scalar_dyn::<Int32Type>(&a, -1).unwrap();
+        let result = as_primitive_array::<Int32Type>(&result);
+        assert_eq!(0, result.value(0));
     }
 
     #[test]
@@ -2566,6 +2654,14 @@ mod tests {
         modulus(&a, &b).unwrap();
     }
 
+    #[test]
+    #[should_panic(expected = "DivideByZero")]
+    fn test_i32_array_modulus_dyn_by_zero() {
+        let a = Int32Array::from(vec![15]);
+        let b = Int32Array::from(vec![0]);
+        modulus_dyn(&a, &b).unwrap();
+    }
+
     #[test]
     #[should_panic(expected = "DivideByZero")]
     fn test_f32_array_modulus_by_zero() {
@@ -2574,6 +2670,14 @@ mod tests {
         modulus(&a, &b).unwrap();
     }
 
+    #[test]
+    #[should_panic(expected = "DivideByZero")]
+    fn test_f32_array_modulus_dyn_by_zero() {
+        let a = Float32Array::from(vec![1.5]);
+        let b = Float32Array::from(vec![0.0]);
+        modulus_dyn(&a, &b).unwrap();
+    }
+
     #[test]
     fn test_f64_array_divide() {
         let a = Float64Array::from(vec![15.0, 15.0, 8.0]);

Reply via email to