diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index be6498a74c6..88832252e19 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -330,6 +330,7 @@ void RegisterScalarOptions(FunctionRegistry* registry) { SCALAR_ARITHMETIC_UNARY(AbsoluteValue, "abs", "abs_checked") SCALAR_ARITHMETIC_UNARY(Negate, "negate", "negate_checked") +SCALAR_EAGER_UNARY(Sign, "sign") SCALAR_ARITHMETIC_UNARY(Sin, "sin", "sin_checked") SCALAR_ARITHMETIC_UNARY(Cos, "cos", "cos_checked") SCALAR_ARITHMETIC_UNARY(Asin, "asin", "asin_checked") diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index f0aebc8e032..2be289a4720 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -513,6 +513,15 @@ Result MinElementWise( ElementWiseAggregateOptions options = ElementWiseAggregateOptions::Defaults(), ExecContext* ctx = NULLPTR); +/// \brief Get the sign of a value. Array values can be of arbitrary length. If argument +/// is null the result will be null. +/// +/// \param[in] arg the value to extract sign from +/// \param[in] ctx the function execution context, optional +/// \return the elementwise sign function +ARROW_EXPORT +Result Sign(const Datum& arg, ExecContext* ctx = NULLPTR); + /// \brief Compare a numeric array with a scalar. /// /// \param[in] left datum to compare, must be an Array diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index db73294e1fa..28904bdbfa0 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -20,8 +20,10 @@ #include #include +#include "arrow/compute/kernels/codegen_internal.h" #include "arrow/compute/kernels/common.h" #include "arrow/compute/kernels/util_internal.h" +#include "arrow/type.h" #include "arrow/type_traits.h" #include "arrow/util/decimal.h" #include "arrow/util/int_util_internal.h" @@ -462,6 +464,23 @@ struct PowerChecked { } }; +struct Sign { + template + static constexpr enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + return std::isnan(arg) ? arg : ((arg == 0) ? 0 : (std::signbit(arg) ? -1 : 1)); + } + + template + static constexpr enable_if_unsigned_integer Call(KernelContext*, Arg arg, Status*) { + return arg > 0; + } + + template + static constexpr enable_if_signed_integer Call(KernelContext*, Arg arg, Status*) { + return (arg > 0) ? 1 : ((arg == 0) ? 0 : -1); + } +}; + // Bitwise operations struct BitWiseNot { @@ -1033,6 +1052,37 @@ void AddDecimalBinaryKernels(const std::string& name, DCHECK_OK((*func)->AddKernel({in_type256, in_type256}, out_type, exec256)); } +// Generate a kernel given an arithmetic functor +template