From 88ce81d3b901b5f8aacc36573c7bce835cf85dfa Mon Sep 17 00:00:00 2001 From: liyafan82 Date: Wed, 12 Aug 2020 16:25:55 +0800 Subject: [PATCH] ARROW-9388: [C++] Division kernels --- cpp/src/arrow/compute/api_scalar.cc | 1 + cpp/src/arrow/compute/api_scalar.h | 14 ++++ .../arrow/compute/kernels/codegen_internal.h | 3 +- .../compute/kernels/scalar_arithmetic.cc | 59 +++++++++++++ .../kernels/scalar_arithmetic_benchmark.cc | 2 + .../compute/kernels/scalar_arithmetic_test.cc | 82 +++++++++++++++++++ cpp/src/arrow/util/int_util_internal.h | 1 + docs/source/cpp/compute.rst | 4 + 8 files changed, 165 insertions(+), 1 deletion(-) diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index 9a911030999..353151eade2 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -51,6 +51,7 @@ namespace compute { SCALAR_ARITHMETIC_BINARY(Add, "add", "add_checked") SCALAR_ARITHMETIC_BINARY(Subtract, "subtract", "subtract_checked") SCALAR_ARITHMETIC_BINARY(Multiply, "multiply", "multiply_checked") +SCALAR_ARITHMETIC_BINARY(Divide, "divide", "divide_checked") // ---------------------------------------------------------------------- // Set-related operations diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index 80e3ebb98b3..fc9dc35490e 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -129,6 +129,20 @@ Result Multiply(const Datum& left, const Datum& right, ArithmeticOptions options = ArithmeticOptions(), ExecContext* ctx = NULLPTR); +/// \brief Divide two values. Array values must be the same length. If either +/// argument is null the result will be null. For integer types, if there is +/// a zero divisor, an error will be raised. +/// +/// \param[in] left the dividend +/// \param[in] right the divisor +/// \param[in] options arithmetic options (enable/disable overflow checking), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise quotient +ARROW_EXPORT +Result Divide(const Datum& left, const Datum& right, + ArithmeticOptions options = ArithmeticOptions(), + 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/codegen_internal.h b/cpp/src/arrow/compute/kernels/codegen_internal.h index a4e11fe3894..1f940249857 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal.h +++ b/cpp/src/arrow/compute/kernels/codegen_internal.h @@ -728,7 +728,6 @@ struct ScalarBinary { } } else { if (batch[1].kind() == Datum::ARRAY) { - // e.g. if we were doing scalar < array, we flip and do array >= scalar return ScalarArray(ctx, *batch[0].scalar(), *batch[1].array(), out); } else { return ScalarScalar(ctx, *batch[0].scalar(), *batch[1].scalar(), out); @@ -842,6 +841,8 @@ struct ScalarBinaryNotNull { template using ScalarBinaryEqualTypes = ScalarBinary; +// A kernel exec generator for non-null binary kernels where both input types are the +// same template using ScalarBinaryNotNullEqualTypes = ScalarBinaryNotNull; diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index afb5348597e..e56203bdfc3 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -22,6 +22,7 @@ namespace arrow { using internal::AddWithOverflow; +using internal::DivideWithOverflow; using internal::MultiplyWithOverflow; using internal::SubtractWithOverflow; @@ -186,6 +187,56 @@ struct MultiplyChecked { } }; +struct Divide { + template + static enable_if_floating_point Call(KernelContext* ctx, Arg0 left, Arg1 right) { + if (ARROW_PREDICT_FALSE(right == 0)) { + ctx->SetStatus(Status::Invalid("divide by zero")); + return 0; + } + return left / right; + } + + template + static enable_if_integer Call(KernelContext* ctx, Arg0 left, Arg1 right) { + T result; + if (ARROW_PREDICT_FALSE(DivideWithOverflow(left, right, &result))) { + if (right == 0) { + ctx->SetStatus(Status::Invalid("divide by zero")); + } else { + result = 0; + } + } + return result; + } +}; + +struct DivideChecked { + template + static enable_if_integer Call(KernelContext* ctx, Arg0 left, Arg1 right) { + static_assert(std::is_same::value && std::is_same::value, ""); + T result; + if (ARROW_PREDICT_FALSE(DivideWithOverflow(left, right, &result))) { + if (right == 0) { + ctx->SetStatus(Status::Invalid("divide by zero")); + } else { + ctx->SetStatus(Status::Invalid("overflow")); + } + } + return result; + } + + template + static enable_if_floating_point Call(KernelContext* ctx, Arg0 left, Arg1 right) { + static_assert(std::is_same::value && std::is_same::value, ""); + if (ARROW_PREDICT_FALSE(right == 0)) { + ctx->SetStatus(Status::Invalid("divide by zero")); + return 0; + } + return left / right; + } +}; + // Generate a kernel given an arithmetic functor template