You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ra...@apache.org on 2022/04/26 11:02:18 UTC

[arrow] branch master updated: ARROW-15940: [Gandiva][C++] Add NEGATIVE function for decimal data type

This is an automated email from the ASF dual-hosted git repository.

ravindra pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 3e56a949c7 ARROW-15940: [Gandiva][C++] Add NEGATIVE function for decimal data type
3e56a949c7 is described below

commit 3e56a949c73168d789612a9022cdceae6088e2b7
Author: Johnnathan <jo...@gmail.com>
AuthorDate: Tue Apr 26 16:32:01 2022 +0530

    ARROW-15940: [Gandiva][C++] Add NEGATIVE function for decimal data type
    
    This PR implements the NEGATIVE function for decimal data type.
    
    The function receive a decimal128() and return a negative decimal128().
    
    Closes #12581 from Johnnathanalmeida/feature/negative-function-for-decimal
    
    Authored-by: Johnnathan <jo...@gmail.com>
    Signed-off-by: Pindikura Ravindra <ra...@dremio.com>
---
 cpp/src/gandiva/function_registry_arithmetic.cc    |  4 ++
 cpp/src/gandiva/precompiled/arithmetic_ops.cc      | 11 ++++
 cpp/src/gandiva/precompiled/arithmetic_ops_test.cc | 60 ++++++++++++++++++++++
 cpp/src/gandiva/precompiled/types.h                |  4 ++
 cpp/src/gandiva/tests/decimal_test.cc              | 45 ++++++++++++++++
 5 files changed, 124 insertions(+)

diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc b/cpp/src/gandiva/function_registry_arithmetic.cc
index 5baf84bfd8..6d10fd920d 100644
--- a/cpp/src/gandiva/function_registry_arithmetic.cc
+++ b/cpp/src/gandiva/function_registry_arithmetic.cc
@@ -176,6 +176,10 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() {
                      "negative_int64",
                      NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),
 
+      NativeFunction("negative", {}, DataTypeVector{decimal128()}, decimal128(),
+                     kResultNullIfNull, "negative_decimal",
+                     NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),
+
       // compare functions
       BINARY_RELATIONAL_BOOL_FN(equal, ({"eq", "same"})),
       BINARY_RELATIONAL_BOOL_FN(not_equal, {}),
diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops.cc b/cpp/src/gandiva/precompiled/arithmetic_ops.cc
index ccc09ab873..3fdc4d0b6a 100644
--- a/cpp/src/gandiva/precompiled/arithmetic_ops.cc
+++ b/cpp/src/gandiva/precompiled/arithmetic_ops.cc
@@ -17,6 +17,7 @@
 
 #include <cmath>
 #include <cstdint>
+#include "arrow/util/basic_decimal.h"
 
 extern "C" {
 
@@ -389,6 +390,16 @@ NEGATIVE_INTEGER(int64, 64)
 #undef NEGATIVE
 #undef NEGATIVE_INTEGER
 
+void negative_decimal(gdv_int64 context, int64_t high_bits, uint64_t low_bits,
+                      int32_t /*precision*/, int32_t /*scale*/, int32_t /*out_precision*/,
+                      int32_t /*out_scale*/, int64_t* out_high_bits,
+                      uint64_t* out_low_bits) {
+  arrow::BasicDecimal128 res = arrow::BasicDecimal128(high_bits, low_bits).Negate();
+
+  *out_high_bits = res.high_bits();
+  *out_low_bits = res.low_bits();
+}
+
 #define DIV(TYPE)                                                                     \
   FORCE_INLINE                                                                        \
   gdv_##TYPE div_##TYPE##_##TYPE(gdv_int64 context, gdv_##TYPE in1, gdv_##TYPE in2) { \
diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
index 91a1ae7f70..1cca0cb9c4 100644
--- a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
+++ b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
@@ -21,6 +21,9 @@
 #include <cstdint>
 
 #include "../execution_context.h"
+#include "arrow/testing/gtest_util.h"
+#include "arrow/util/decimal.h"
+#include "gandiva/decimal_scalar.h"
 #include "gandiva/precompiled/types.h"
 
 namespace gandiva {
@@ -80,6 +83,63 @@ TEST(TestArithmeticOps, TestMod) {
   EXPECT_FALSE(context.has_error());
 }
 
+TEST(TestArithmeticOps, TestNegativeDecimal) {
+  gandiva::ExecutionContext ctx;
+  int64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
+
+  int64_t out_high_bits = 0;
+  uint64_t out_low_bits = 0;
+
+  arrow::Decimal128 input_decimal("-10.5");
+  negative_decimal(ctx_ptr, input_decimal.high_bits(), input_decimal.low_bits(), 3, 1, 3,
+                   1, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal("10.5");
+  EXPECT_EQ(output_decimal.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal2("10.5");
+  negative_decimal(ctx_ptr, input_decimal2.high_bits(), input_decimal2.low_bits(), 3, 1,
+                   3, 1, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal2("-10.5");
+  EXPECT_EQ(output_decimal2.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal2.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal3("-23049223942343.532412");
+  negative_decimal(ctx_ptr, input_decimal3.high_bits(), input_decimal3.low_bits(), 20, 6,
+                   20, 6, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal3("23049223942343.532412");
+  EXPECT_EQ(output_decimal3.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal3.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal4("15.001");
+  negative_decimal(ctx_ptr, input_decimal4.high_bits(), input_decimal4.low_bits(), 2, 3,
+                   2, 3, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal4("-15.001");
+  EXPECT_EQ(output_decimal4.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal4.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal5("17");
+  negative_decimal(ctx_ptr, input_decimal5.high_bits(), input_decimal5.low_bits(), 2, 0,
+                   2, 0, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal5("-17");
+  EXPECT_EQ(output_decimal5.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal5.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal6("-99917");
+  negative_decimal(ctx_ptr, input_decimal6.high_bits(), input_decimal6.low_bits(), 5, 0,
+                   5, 0, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal6("99917");
+  EXPECT_EQ(output_decimal6.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal6.low_bits(), out_low_bits);
+
+  arrow::Decimal128 input_decimal7("0.99917");
+  negative_decimal(ctx_ptr, input_decimal7.high_bits(), input_decimal7.low_bits(), 0, 5,
+                   0, 5, &out_high_bits, &out_low_bits);
+  arrow::Decimal128 output_decimal7("-0.99917");
+  EXPECT_EQ(output_decimal7.high_bits(), out_high_bits);
+  EXPECT_EQ(output_decimal7.low_bits(), out_low_bits);
+}
+
 TEST(TestArithmeticOps, TestPositiveNegative) {
   EXPECT_EQ(positive_int32(10), 10);
   EXPECT_EQ(positive_int64(1000), 1000);
diff --git a/cpp/src/gandiva/precompiled/types.h b/cpp/src/gandiva/precompiled/types.h
index 1f1e42deb6..f3bd51ae80 100644
--- a/cpp/src/gandiva/precompiled/types.h
+++ b/cpp/src/gandiva/precompiled/types.h
@@ -207,6 +207,10 @@ gdv_float32 positive_float32(gdv_float32 in);
 gdv_float64 positive_float64(gdv_float64 in);
 gdv_float32 negative_float32(gdv_float32 in);
 gdv_float64 negative_float64(gdv_float64 in);
+void negative_decimal(gdv_int64 context, int64_t high_bits, uint64_t low_bits,
+                      int32_t /*precision*/, int32_t /*scale*/, int32_t /*out_precision*/,
+                      int32_t /*out_scale*/, int64_t* out_high_bits,
+                      uint64_t* out_low_bits);
 
 gdv_int64 divide_int64_int64(gdv_int64 context, gdv_int64 in1, gdv_int64 in2);
 
diff --git a/cpp/src/gandiva/tests/decimal_test.cc b/cpp/src/gandiva/tests/decimal_test.cc
index 31f2dedf5c..1924f5b408 100644
--- a/cpp/src/gandiva/tests/decimal_test.cc
+++ b/cpp/src/gandiva/tests/decimal_test.cc
@@ -301,6 +301,51 @@ TEST_F(TestDecimal, TestCompare) {
                             outputs[5]);  // greater_than_or_equal_to
 }
 
+TEST_F(TestDecimal, TestNegative) {
+  // schema for input fields
+  constexpr int32_t precision = 3;
+  constexpr int32_t scale = 1;
+
+  auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
+
+  auto field_a = field("a", decimal_type);
+  auto schema = arrow::schema({field_a});
+
+  // build expressions
+  auto exprs = std::vector<ExpressionPtr>{
+      TreeExprBuilder::MakeExpression("negative", {field_a},
+                                      field("res_negative", decimal_type)),
+  };
+
+  // Build a projector for the expression.
+  std::shared_ptr<Projector> projector;
+  auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
+  DCHECK_OK(status);
+
+  // Create a row-batch with some sample data
+  int num_records = 4;
+  auto validity = {true, true, true, true};
+  auto array_a = MakeArrowArrayDecimal(
+      decimal_type, MakeDecimalVector({"10.5", "-10.5", "-50.2", "50.2"}, scale),
+      validity);
+
+  // prepare input record batch
+  auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
+
+  // Evaluate expression
+  arrow::ArrayVector outputs;
+  status = projector->Evaluate(*in_batch, pool_, &outputs);
+  DCHECK_OK(status);
+
+  // Validate results
+  // negative(x)
+  EXPECT_ARROW_ARRAY_EQUALS(
+      MakeArrowArrayDecimal(decimal_type,
+                            MakeDecimalVector({"-10.5", "10.5", "50.2", "-50.2"}, scale),
+                            validity),
+      outputs[0]);
+}
+
 // ARROW-9092: This test is conditionally disabled when building with LLVM 9
 // because it hangs.
 #if GANDIVA_LLVM_VERSION != 9