diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index 2021c8a30c6..719fbed78d5 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -326,6 +326,10 @@ SCALAR_ARITHMETIC_UNARY(Asin, "asin", "asin_checked") SCALAR_ARITHMETIC_UNARY(Acos, "acos", "acos_checked") SCALAR_ARITHMETIC_UNARY(Tan, "tan", "tan_checked") SCALAR_EAGER_UNARY(Atan, "atan") +SCALAR_ARITHMETIC_UNARY(Ln, "ln", "ln_checked") +SCALAR_ARITHMETIC_UNARY(Log10, "log10", "log10_checked") +SCALAR_ARITHMETIC_UNARY(Log2, "log2", "log2_checked") +SCALAR_ARITHMETIC_UNARY(Log1p, "log1p", "log1p_checked") #define SCALAR_ARITHMETIC_BINARY(NAME, REGISTRY_NAME, REGISTRY_CHECKED_NAME) \ Result NAME(const Datum& left, const Datum& right, ArithmeticOptions options, \ diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index 89b4faca940..8417d77b9de 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -246,8 +246,9 @@ class ARROW_EXPORT ProjectOptions : public FunctionOptions { /// @} -/// \brief Get the absolute value of a value. Array values can be of arbitrary -/// length. If argument is null the result will be null. +/// \brief Get the absolute value of a value. +/// +/// If argument is null the result will be null. /// /// \param[in] arg the value transformed /// \param[in] options arithmetic options (overflow handling), optional @@ -311,8 +312,9 @@ Result Divide(const Datum& left, const Datum& right, ArithmeticOptions options = ArithmeticOptions(), ExecContext* ctx = NULLPTR); -/// \brief Negate a value. Array values can be of arbitrary length. If argument -/// is null the result will be null. +/// \brief Negate values. +/// +/// If argument is null the result will be null. /// /// \param[in] arg the value negated /// \param[in] options arithmetic options (overflow handling), optional @@ -424,6 +426,55 @@ Result Atan(const Datum& arg, ExecContext* ctx = NULLPTR); ARROW_EXPORT Result Atan2(const Datum& y, const Datum& x, ExecContext* ctx = NULLPTR); +/// \brief Get the natural log of a value. +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg The values to compute the logarithm for. +/// \param[in] options arithmetic options (overflow handling), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise natural log +ARROW_EXPORT +Result Ln(const Datum& arg, ArithmeticOptions options = ArithmeticOptions(), + ExecContext* ctx = NULLPTR); + +/// \brief Get the log base 10 of a value. +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg The values to compute the logarithm for. +/// \param[in] options arithmetic options (overflow handling), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise log base 10 +ARROW_EXPORT +Result Log10(const Datum& arg, ArithmeticOptions options = ArithmeticOptions(), + ExecContext* ctx = NULLPTR); + +/// \brief Get the log base 2 of a value. +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg The values to compute the logarithm for. +/// \param[in] options arithmetic options (overflow handling), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise log base 2 +ARROW_EXPORT +Result Log2(const Datum& arg, ArithmeticOptions options = ArithmeticOptions(), + ExecContext* ctx = NULLPTR); + +/// \brief Get the natural log of (1 + value). +/// +/// If argument is null the result will be null. +/// This function may be more accurate than Log(1 + value) for values close to zero. +/// +/// \param[in] arg The values to compute the logarithm for. +/// \param[in] options arithmetic options (overflow handling), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise natural log +ARROW_EXPORT +Result Log1p(const Datum& arg, ArithmeticOptions options = ArithmeticOptions(), + ExecContext* ctx = NULLPTR); + /// \brief Find the element-wise maximum of any number of arrays or scalars. /// Array values must be the same length. /// diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index da3a3095041..f0eabf1b40e 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -53,11 +53,11 @@ template using is_signed_integer = std::integral_constant::value && std::is_signed::value>; -template -using enable_if_signed_integer = enable_if_t::value, T>; +template +using enable_if_signed_integer = enable_if_t::value, R>; -template -using enable_if_unsigned_integer = enable_if_t::value, T>; +template +using enable_if_unsigned_integer = enable_if_t::value, R>; template using enable_if_integer = @@ -686,6 +686,118 @@ struct Atan2 { } }; +struct LogNatural { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + static_assert(std::is_same::value, ""); + if (arg == 0.0) { + return -std::numeric_limits::infinity(); + } else if (arg < 0.0) { + return std::numeric_limits::quiet_NaN(); + } + return std::log(arg); + } +}; + +struct LogNaturalChecked { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + if (arg == 0.0) { + *st = Status::Invalid("logarithm of zero"); + return arg; + } else if (arg < 0.0) { + *st = Status::Invalid("logarithm of negative number"); + return arg; + } + return std::log(arg); + } +}; + +struct Log10 { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + static_assert(std::is_same::value, ""); + if (arg == 0.0) { + return -std::numeric_limits::infinity(); + } else if (arg < 0.0) { + return std::numeric_limits::quiet_NaN(); + } + return std::log10(arg); + } +}; + +struct Log10Checked { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + if (arg == 0) { + *st = Status::Invalid("logarithm of zero"); + return arg; + } else if (arg < 0) { + *st = Status::Invalid("logarithm of negative number"); + return arg; + } + return std::log10(arg); + } +}; + +struct Log2 { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + static_assert(std::is_same::value, ""); + if (arg == 0.0) { + return -std::numeric_limits::infinity(); + } else if (arg < 0.0) { + return std::numeric_limits::quiet_NaN(); + } + return std::log2(arg); + } +}; + +struct Log2Checked { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + if (arg == 0.0) { + *st = Status::Invalid("logarithm of zero"); + return arg; + } else if (arg < 0.0) { + *st = Status::Invalid("logarithm of negative number"); + return arg; + } + return std::log2(arg); + } +}; + +struct Log1p { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + static_assert(std::is_same::value, ""); + if (arg == -1) { + return -std::numeric_limits::infinity(); + } else if (arg < -1) { + return std::numeric_limits::quiet_NaN(); + } + return std::log1p(arg); + } +}; + +struct Log1pChecked { + template + static enable_if_floating_point Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + if (arg == -1) { + *st = Status::Invalid("logarithm of zero"); + return arg; + } else if (arg < -1) { + *st = Status::Invalid("logarithm of negative number"); + return arg; + } + return std::log1p(arg); + } +}; + // Generate a kernel given an arithmetic functor template