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 2021/11/15 11:52:46 UTC

[arrow] branch master updated: ARROW-14315: [C++][Gandiva] Implement BROUND function

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 f0e1a4f  ARROW-14315: [C++][Gandiva] Implement BROUND function
f0e1a4f is described below

commit f0e1a4f043bb0e8e0ac84467edd94f7ffa2b8ddc
Author: Augusto Silva <au...@hotmail.com>
AuthorDate: Mon Nov 15 17:21:13 2021 +0530

    ARROW-14315: [C++][Gandiva] Implement BROUND function
    
    Returns the rounded BIGINT value of a using HALF_EVEN rounding mode. Also known as Gaussian rounding or bankers' rounding.
    
    Closes #11415 from augustoasilva/feature/implement-bround-function
    
    Authored-by: Augusto Silva <au...@hotmail.com>
    Signed-off-by: Pindikura Ravindra <ra...@dremio.com>
---
 cpp/src/gandiva/function_registry_arithmetic.cc    |  4 +++
 cpp/src/gandiva/precompiled/extended_math_ops.cc   | 16 ++++++++++
 .../gandiva/precompiled/extended_math_ops_test.cc  | 18 +++++++++++
 cpp/src/gandiva/precompiled/types.h                |  1 +
 cpp/src/gandiva/tests/projector_test.cc            | 37 ++++++++++++++++++++++
 5 files changed, 76 insertions(+)

diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc b/cpp/src/gandiva/function_registry_arithmetic.cc
index f34289f..3901407 100644
--- a/cpp/src/gandiva/function_registry_arithmetic.cc
+++ b/cpp/src/gandiva/function_registry_arithmetic.cc
@@ -107,6 +107,10 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() {
       BINARY_GENERIC_SAFE_NULL_IF_NULL(round, {}, int32, int32, int32),
       BINARY_GENERIC_SAFE_NULL_IF_NULL(round, {}, int64, int32, int64),
 
+      // bround functions
+      NativeFunction("bround", {}, DataTypeVector{float64()}, float64(),
+                     kResultNullIfNull, "bround_float64"),
+
       // compare functions
       BINARY_RELATIONAL_BOOL_FN(equal, ({"eq", "same"})),
       BINARY_RELATIONAL_BOOL_FN(not_equal, {}),
diff --git a/cpp/src/gandiva/precompiled/extended_math_ops.cc b/cpp/src/gandiva/precompiled/extended_math_ops.cc
index 365b08a..c233197 100644
--- a/cpp/src/gandiva/precompiled/extended_math_ops.cc
+++ b/cpp/src/gandiva/precompiled/extended_math_ops.cc
@@ -28,6 +28,7 @@ extern "C" {
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include "./types.h"
 
 // Expand the inner fn for types that support extended math.
@@ -236,6 +237,21 @@ gdv_int64 round_int64(gdv_int64 num) { return num; }
 ROUND_DECIMAL(float32)
 ROUND_DECIMAL(float64)
 
+// rounds the number to the nearest integer
+FORCE_INLINE
+gdv_float64 bround_float64(gdv_float64 num) {
+  gdv_float64 round_num = round(num);
+  gdv_float64 diff_num = round_num - num;
+  if ((diff_num != 0.5) && (diff_num != -0.5)) {
+    return round_num;
+  }
+  if (fmod(round_num, 2.0) == 0.0) {
+    return round_num;
+  }
+
+  return num - diff_num;
+}
+
 // rounds the number to the given scale
 #define ROUND_DECIMAL_TO_SCALE(TYPE)                                        \
   FORCE_INLINE                                                              \
diff --git a/cpp/src/gandiva/precompiled/extended_math_ops_test.cc b/cpp/src/gandiva/precompiled/extended_math_ops_test.cc
index 147b403..9d84734 100644
--- a/cpp/src/gandiva/precompiled/extended_math_ops_test.cc
+++ b/cpp/src/gandiva/precompiled/extended_math_ops_test.cc
@@ -120,6 +120,24 @@ TEST(TestExtendedMathOps, TestRoundDecimal) {
   VerifyFuzzyEquals(round_float64_int32((double)INT_MIN - 1, 0), (double)INT_MIN - 1);
 }
 
+TEST(TestExtendedMathOps, TestBRoundDecimal) {
+  EXPECT_DOUBLE_EQ(bround_float64(0.0), 0);
+  EXPECT_DOUBLE_EQ(bround_float64(2.5), 2);
+  EXPECT_DOUBLE_EQ(bround_float64(3.5), 4);
+  EXPECT_DOUBLE_EQ(bround_float64(-2.5), -2);
+  EXPECT_DOUBLE_EQ(bround_float64(-3.5), -4);
+  EXPECT_DOUBLE_EQ(bround_float64(1.4999999), 1);
+  EXPECT_DOUBLE_EQ(bround_float64(1.50001), 2);
+  EXPECT_EQ(std::signbit(bround_float64(0)), 0);
+
+  VerifyFuzzyEquals(bround_float64(2.5), 2);
+  VerifyFuzzyEquals(bround_float64(3.5), 4);
+  VerifyFuzzyEquals(bround_float64(-2.5), -2);
+  VerifyFuzzyEquals(bround_float64(-3.5), -4);
+  VerifyFuzzyEquals(bround_float64(1.4999999), 1);
+  VerifyFuzzyEquals(bround_float64(1.50001), 2);
+}
+
 TEST(TestExtendedMathOps, TestRound) {
   EXPECT_EQ(round_int32(21134), 21134);
   EXPECT_EQ(round_int32(-132422), -132422);
diff --git a/cpp/src/gandiva/precompiled/types.h b/cpp/src/gandiva/precompiled/types.h
index 987ee2c..2e6e9c6 100644
--- a/cpp/src/gandiva/precompiled/types.h
+++ b/cpp/src/gandiva/precompiled/types.h
@@ -167,6 +167,7 @@ gdv_float64 div_float64_float64(gdv_int64 context, gdv_float64 in1, gdv_float64
 
 gdv_float32 round_float32(gdv_float32);
 gdv_float64 round_float64(gdv_float64);
+gdv_float64 bround_float64(gdv_float64);
 gdv_float32 round_float32_int32(gdv_float32 number, gdv_int32 out_scale);
 gdv_float64 round_float64_int32(gdv_float64 number, gdv_int32 out_scale);
 gdv_float64 get_scale_multiplier(gdv_int32);
diff --git a/cpp/src/gandiva/tests/projector_test.cc b/cpp/src/gandiva/tests/projector_test.cc
index 1202077..dea66a7 100644
--- a/cpp/src/gandiva/tests/projector_test.cc
+++ b/cpp/src/gandiva/tests/projector_test.cc
@@ -1606,4 +1606,41 @@ TEST_F(TestProjector, TestCastNullableIntYearInterval) {
   EXPECT_ARROW_ARRAY_EQUALS(out_int64, outputs.at(1));
 }
 
+TEST_F(TestProjector, TestBround) {
+  // schema for input fields
+  auto field0 = field("f0", arrow::float64());
+
+  auto schema_bround = arrow::schema({field0});
+
+  // output fields
+  auto field_bround = field("bround", arrow::float64());
+
+  // Build expression
+  auto bround_expr = TreeExprBuilder::MakeExpression("bround", {field0}, field_bround);
+
+  std::shared_ptr<Projector> projector;
+  auto status =
+      Projector::Make(schema_bround, {bround_expr}, TestConfiguration(), &projector);
+
+  EXPECT_TRUE(status.ok()) << status.message();
+
+  // Create a row-batch with some sample data
+  int num_records = 4;
+  auto array0 =
+      MakeArrowArrayFloat64({0.0, 2.5, -3.5, 1.499999}, {true, true, true, true});
+  // expected output
+  auto exp_bround = MakeArrowArrayFloat64({0, 2, -4, 1}, {true, true, true, true});
+
+  // prepare input record batch
+  auto in_batch = arrow::RecordBatch::Make(schema_bround, num_records, {array0});
+
+  // Evaluate expression
+  arrow::ArrayVector outputs;
+  status = projector->Evaluate(*in_batch, pool_, &outputs);
+  EXPECT_TRUE(status.ok()) << status.message();
+
+  // Validate results
+  EXPECT_ARROW_ARRAY_EQUALS(exp_bround, outputs.at(0));
+}
+
 }  // namespace gandiva