Skip to content

Commit

Permalink
ARROW-14315: [C++][Gandiva] Implement BROUND function
Browse files Browse the repository at this point in the history
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 <augusto.a.silva@hotmail.com>
Signed-off-by: Pindikura Ravindra <ravindra@dremio.com>
  • Loading branch information
augustoasilva authored and Pindikura Ravindra committed Nov 15, 2021
1 parent 8f0a560 commit f0e1a4f
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cpp/src/gandiva/function_registry_arithmetic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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, {}),
Expand Down
16 changes: 16 additions & 0 deletions cpp/src/gandiva/precompiled/extended_math_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 \
Expand Down
18 changes: 18 additions & 0 deletions cpp/src/gandiva/precompiled/extended_math_ops_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions cpp/src/gandiva/precompiled/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 37 additions & 0 deletions cpp/src/gandiva/tests/projector_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit f0e1a4f

Please sign in to comment.