cyb70289 commented on a change in pull request #10364:
URL: https://github.com/apache/arrow/pull/10364#discussion_r645469007
##########
File path: cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
##########
@@ -516,6 +520,141 @@ std::shared_ptr<ScalarFunction>
MakeUnarySignedArithmeticFunctionNotNull(
return func;
}
+// Decimal arithmetics
+struct BinaryDecimal : public KernelState {
+ const std::shared_ptr<DecimalType> left_type, right_type;
+ std::shared_ptr<DataType> out_type;
+
+ explicit BinaryDecimal(const KernelInitArgs& args)
+ : left_type(checked_pointer_cast<DecimalType>(args.inputs[0].type)),
+ right_type(checked_pointer_cast<DecimalType>(args.inputs[1].type)) {
+ DCHECK_EQ(left_type->id(), right_type->id());
+ }
+
+ // create instance of derived class T
+ template <typename T>
+ static Result<std::unique_ptr<KernelState>> Make(const KernelInitArgs& args)
{
+ auto op = ::arrow::internal::make_unique<T>(args);
+ if (op->left_type->scale() < 0 || op->right_type->scale() < 0) {
+ return Status::Invalid("Decimals with negative scales not supported");
+ }
+ RETURN_NOT_OK(op->Init(op->left_type->precision(), op->left_type->scale(),
+ op->right_type->precision(),
op->right_type->scale()));
+ return std::move(op);
+ }
+
+ // return error and stop kernel execution if output precision is out of bound
+ Status Init(int32_t out_prec, int32_t out_scale) {
+ if (left_type->id() == Type::DECIMAL128) {
+ ARROW_ASSIGN_OR_RAISE(out_type, Decimal128Type::Make(out_prec,
out_scale));
+ } else {
+ ARROW_ASSIGN_OR_RAISE(out_type, Decimal256Type::Make(out_prec,
out_scale));
+ }
+ return Status::OK();
+ }
+
+ Result<std::shared_ptr<DataType>> ResolveOutput(const
std::vector<ValueDescr>&) const {
+ return out_type;
+ }
+};
+
+template <bool IsSubtract>
+struct AddOrSubtractDecimal : public BinaryDecimal {
+ using BinaryDecimal::BinaryDecimal;
+
+ int32_t left_scaleup, right_scaleup;
+
+ // called by kernel::init()
+ static Result<std::unique_ptr<KernelState>> Make(KernelContext*,
+ const KernelInitArgs& args)
{
+ return BinaryDecimal::Make<AddOrSubtractDecimal<IsSubtract>>(args);
+ }
+
+ // figure out output type and arg scaling, called by Make()
+ Status Init(int32_t p1, int32_t s1, int32_t p2, int32_t s2) {
+ const int32_t out_scale = std::max(s1, s2);
+ const int32_t out_prec = std::max(p1 - s1, p2 - s2) + 1 + out_scale;
+ left_scaleup = out_scale - s1;
+ right_scaleup = out_scale - s2;
+ return BinaryDecimal::Init(out_prec, out_scale);
+ }
+
+ // called by kerne::exec() for each value pair
+ // TODO(yibo): avoid repeat rescaling of scalar arg
+ template <typename T, typename Arg0, typename Arg1>
+ T Call(KernelContext*, Arg0 left, Arg1 right, Status*) const {
+ if (left_scaleup > 0) left = left.IncreaseScaleBy(left_scaleup);
+ if (right_scaleup > 0) right = right.IncreaseScaleBy(right_scaleup);
+ if (IsSubtract) right = -right;
+ return left + right;
+ }
+};
+
+using AddDecimal = AddOrSubtractDecimal</*IsSubtract=*/false>;
+using SubtractDecimal = AddOrSubtractDecimal</*IsSubtract=*/true>;
+
+struct MultiplyDecimal : public BinaryDecimal {
+ using BinaryDecimal::BinaryDecimal;
+
+ static Result<std::unique_ptr<KernelState>> Make(KernelContext*,
+ const KernelInitArgs& args)
{
+ return BinaryDecimal::Make<MultiplyDecimal>(args);
+ }
+
+ Status Init(int32_t p1, int32_t s1, int32_t p2, int32_t s2) {
+ return BinaryDecimal::Init(p1 + p2 + 1, s1 + s2);
+ }
+
+ template <typename T, typename Arg0, typename Arg1>
+ T Call(KernelContext*, Arg0 left, Arg1 right, Status*) const {
+ return left * right;
+ }
+};
+
+struct DivideDecimal : public BinaryDecimal {
+ using BinaryDecimal::BinaryDecimal;
+
+ int32_t left_scaleup;
+
+ static Result<std::unique_ptr<KernelState>> Make(KernelContext*,
+ const KernelInitArgs& args)
{
+ return BinaryDecimal::Make<DivideDecimal>(args);
+ }
+
+ Status Init(int32_t p1, int32_t s1, int32_t p2, int32_t s2) {
+ //
https://docs.aws.amazon.com/redshift/latest/dg/r_numeric_computations201.html
Review comment:
Added explanation to compute.rst
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]