This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new 8945462ed0 Fix : `signum` function bug when `0.0` input (#11580)
8945462ed0 is described below
commit 8945462ed0baf20eb4fb8e298407d08072030e33
Author: Namgung Chan <[email protected]>
AuthorDate: Wed Jul 24 22:11:00 2024 +0900
Fix : `signum` function bug when `0.0` input (#11580)
* add signum unit test
* fix: signum function implementation - input zero output zero
* fix: run cargo fmt
* fix: not specified return type is float64
* fix: sqllogictest
---
datafusion/functions/src/math/mod.rs | 3 +-
datafusion/functions/src/math/monotonicity.rs | 5 -
datafusion/functions/src/math/signum.rs | 215 ++++++++++++++++++++++++++
datafusion/sqllogictest/test_files/scalar.slt | 2 +-
4 files changed, 218 insertions(+), 7 deletions(-)
diff --git a/datafusion/functions/src/math/mod.rs
b/datafusion/functions/src/math/mod.rs
index 9ee173bb61..3b32a158b8 100644
--- a/datafusion/functions/src/math/mod.rs
+++ b/datafusion/functions/src/math/mod.rs
@@ -35,6 +35,7 @@ pub mod pi;
pub mod power;
pub mod random;
pub mod round;
+pub mod signum;
pub mod trunc;
// Create UDFs
@@ -81,7 +82,7 @@ make_math_unary_udf!(
);
make_udf_function!(random::RandomFunc, RANDOM, random);
make_udf_function!(round::RoundFunc, ROUND, round);
-make_math_unary_udf!(SignumFunc, SIGNUM, signum, signum, super::signum_order);
+make_udf_function!(signum::SignumFunc, SIGNUM, signum);
make_math_unary_udf!(SinFunc, SIN, sin, sin, super::sin_order);
make_math_unary_udf!(SinhFunc, SINH, sinh, sinh, super::sinh_order);
make_math_unary_udf!(SqrtFunc, SQRT, sqrt, sqrt, super::sqrt_order);
diff --git a/datafusion/functions/src/math/monotonicity.rs
b/datafusion/functions/src/math/monotonicity.rs
index 56c5a45788..33c061ee11 100644
--- a/datafusion/functions/src/math/monotonicity.rs
+++ b/datafusion/functions/src/math/monotonicity.rs
@@ -197,11 +197,6 @@ pub fn radians_order(input: &[ExprProperties]) ->
Result<SortProperties> {
Ok(input[0].sort_properties)
}
-/// Non-decreasing for all real numbers x.
-pub fn signum_order(input: &[ExprProperties]) -> Result<SortProperties> {
- Ok(input[0].sort_properties)
-}
-
/// Non-decreasing on \[0, π\] and then non-increasing on \[π, 2π\].
/// This pattern repeats periodically with a period of 2π.
// TODO: Implement ordering rule of the SIN function.
diff --git a/datafusion/functions/src/math/signum.rs
b/datafusion/functions/src/math/signum.rs
new file mode 100644
index 0000000000..d2a806a46e
--- /dev/null
+++ b/datafusion/functions/src/math/signum.rs
@@ -0,0 +1,215 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::any::Any;
+use std::sync::Arc;
+
+use arrow::array::{ArrayRef, Float32Array, Float64Array};
+use arrow::datatypes::DataType;
+use arrow::datatypes::DataType::{Float32, Float64};
+
+use datafusion_common::{exec_err, DataFusionError, Result};
+use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
+use datafusion_expr::ColumnarValue;
+use datafusion_expr::{ScalarUDFImpl, Signature, Volatility};
+
+use crate::utils::make_scalar_function;
+
+#[derive(Debug)]
+pub struct SignumFunc {
+ signature: Signature,
+}
+
+impl Default for SignumFunc {
+ fn default() -> Self {
+ SignumFunc::new()
+ }
+}
+
+impl SignumFunc {
+ pub fn new() -> Self {
+ use DataType::*;
+ Self {
+ signature: Signature::uniform(
+ 1,
+ vec![Float64, Float32],
+ Volatility::Immutable,
+ ),
+ }
+ }
+}
+
+impl ScalarUDFImpl for SignumFunc {
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
+ fn name(&self) -> &str {
+ "signum"
+ }
+
+ fn signature(&self) -> &Signature {
+ &self.signature
+ }
+
+ fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
+ match &arg_types[0] {
+ Float32 => Ok(Float32),
+ _ => Ok(Float64),
+ }
+ }
+
+ fn output_ordering(&self, input: &[ExprProperties]) ->
Result<SortProperties> {
+ // Non-decreasing for all real numbers x.
+ Ok(input[0].sort_properties)
+ }
+
+ fn invoke(&self, args: &[ColumnarValue]) -> Result<ColumnarValue> {
+ make_scalar_function(signum, vec![])(args)
+ }
+}
+
+/// signum SQL function
+pub fn signum(args: &[ArrayRef]) -> Result<ArrayRef> {
+ match args[0].data_type() {
+ Float64 => Ok(Arc::new(make_function_scalar_inputs_return_type!(
+ &args[0],
+ "signum",
+ Float64Array,
+ Float64Array,
+ {
+ |x: f64| {
+ if x == 0_f64 {
+ 0_f64
+ } else {
+ x.signum()
+ }
+ }
+ }
+ )) as ArrayRef),
+
+ Float32 => Ok(Arc::new(make_function_scalar_inputs_return_type!(
+ &args[0],
+ "signum",
+ Float32Array,
+ Float32Array,
+ {
+ |x: f32| {
+ if x == 0_f32 {
+ 0_f32
+ } else {
+ x.signum()
+ }
+ }
+ }
+ )) as ArrayRef),
+
+ other => exec_err!("Unsupported data type {other:?} for function
signum"),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::sync::Arc;
+
+ use arrow::array::{Float32Array, Float64Array};
+
+ use datafusion_common::cast::{as_float32_array, as_float64_array};
+ use datafusion_expr::{ColumnarValue, ScalarUDFImpl};
+
+ use crate::math::signum::SignumFunc;
+
+ #[test]
+ fn test_signum_f32() {
+ let args = [ColumnarValue::Array(Arc::new(Float32Array::from(vec![
+ -1.0,
+ -0.0,
+ 0.0,
+ 1.0,
+ -0.01,
+ 0.01,
+ f32::NAN,
+ f32::INFINITY,
+ f32::NEG_INFINITY,
+ ])))];
+
+ let result = SignumFunc::new()
+ .invoke(&args)
+ .expect("failed to initialize function signum");
+
+ match result {
+ ColumnarValue::Array(arr) => {
+ let floats = as_float32_array(&arr)
+ .expect("failed to convert result to a Float32Array");
+
+ assert_eq!(floats.len(), 9);
+ assert_eq!(floats.value(0), -1.0);
+ assert_eq!(floats.value(1), 0.0);
+ assert_eq!(floats.value(2), 0.0);
+ assert_eq!(floats.value(3), 1.0);
+ assert_eq!(floats.value(4), -1.0);
+ assert_eq!(floats.value(5), 1.0);
+ assert!(floats.value(6).is_nan());
+ assert_eq!(floats.value(7), 1.0);
+ assert_eq!(floats.value(8), -1.0);
+ }
+ ColumnarValue::Scalar(_) => {
+ panic!("Expected an array value")
+ }
+ }
+ }
+
+ #[test]
+ fn test_signum_f64() {
+ let args = [ColumnarValue::Array(Arc::new(Float64Array::from(vec![
+ -1.0,
+ -0.0,
+ 0.0,
+ 1.0,
+ -0.01,
+ 0.01,
+ f64::NAN,
+ f64::INFINITY,
+ f64::NEG_INFINITY,
+ ])))];
+
+ let result = SignumFunc::new()
+ .invoke(&args)
+ .expect("failed to initialize function signum");
+
+ match result {
+ ColumnarValue::Array(arr) => {
+ let floats = as_float64_array(&arr)
+ .expect("failed to convert result to a Float32Array");
+
+ assert_eq!(floats.len(), 9);
+ assert_eq!(floats.value(0), -1.0);
+ assert_eq!(floats.value(1), 0.0);
+ assert_eq!(floats.value(2), 0.0);
+ assert_eq!(floats.value(3), 1.0);
+ assert_eq!(floats.value(4), -1.0);
+ assert_eq!(floats.value(5), 1.0);
+ assert!(floats.value(6).is_nan());
+ assert_eq!(floats.value(7), 1.0);
+ assert_eq!(floats.value(8), -1.0);
+ }
+ ColumnarValue::Scalar(_) => {
+ panic!("Expected an array value")
+ }
+ }
+ }
+}
diff --git a/datafusion/sqllogictest/test_files/scalar.slt
b/datafusion/sqllogictest/test_files/scalar.slt
index ff9afa94f4..188a2c5863 100644
--- a/datafusion/sqllogictest/test_files/scalar.slt
+++ b/datafusion/sqllogictest/test_files/scalar.slt
@@ -794,7 +794,7 @@ select round(column1, column2) from values (3.14, 2),
(3.14, 3), (3.14, 21474836
query RRR rowsort
select signum(-2), signum(0), signum(2);
----
--1 1 1
+-1 0 1
# signum scalar nulls
query R rowsort
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]