Skip to content

Commit

Permalink
Mode for Round (#5680)
Browse files Browse the repository at this point in the history
* add 6 modes to round func

* format

* fix logic of round

* add half_even

* add e2e tests for round function with 7 different modes

* reformat

* fix some logics and add test cases

* add test cases

* add test cases for badtype

* chore: SemanticError in tck

* Update round.feature

* Update round.feature

---------

Co-authored-by: Wey Gu <weyl.gu@gmail.com>
Co-authored-by: Sophie <84560950+Sophie-Xie@users.noreply.github.com>
  • Loading branch information
3 people committed Aug 23, 2023
1 parent 8675e73 commit 793c914
Show file tree
Hide file tree
Showing 3 changed files with 363 additions and 4 deletions.
63 changes: 59 additions & 4 deletions src/common/function/FunctionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

#include "FunctionManager.h"

#include <float.h>
#include <folly/json.h>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <cstdint>

Expand Down Expand Up @@ -68,8 +70,11 @@ std::unordered_map<std::string, std::vector<TypeSignature>> FunctionManager::typ
{"round",
{TypeSignature({Value::Type::INT}, Value::Type::FLOAT),
TypeSignature({Value::Type::INT, Value::Type::INT}, Value::Type::FLOAT),
TypeSignature({Value::Type::INT, Value::Type::INT, Value::Type::STRING}, Value::Type::FLOAT),
TypeSignature({Value::Type::FLOAT}, Value::Type::FLOAT),
TypeSignature({Value::Type::FLOAT, Value::Type::INT}, Value::Type::FLOAT)}},
TypeSignature({Value::Type::FLOAT, Value::Type::INT}, Value::Type::FLOAT),
TypeSignature({Value::Type::FLOAT, Value::Type::INT, Value::Type::STRING},
Value::Type::FLOAT)}},
{"sqrt",
{TypeSignature({Value::Type::INT}, Value::Type::FLOAT),
TypeSignature({Value::Type::FLOAT}, Value::Type::FLOAT)}},
Expand Down Expand Up @@ -568,7 +573,7 @@ FunctionManager::FunctionManager() {
// to nearest integral (as a floating-point value)
auto &attr = functions_["round"];
attr.minArity_ = 1;
attr.maxArity_ = 2;
attr.maxArity_ = 3;
attr.isAlwaysPure_ = true;
attr.body_ = [](const auto &args) -> Value {
switch (args[0].get().type()) {
Expand All @@ -577,10 +582,60 @@ FunctionManager::FunctionManager() {
}
case Value::Type::INT:
case Value::Type::FLOAT: {
if (args.size() == 2) {
if (args.size() >= 2) {
if (args[1].get().type() == Value::Type::INT) {
auto val = args[0].get().getFloat();
auto decimal = args[1].get().getInt();
return std::round(args[0].get().getFloat() * pow(10, decimal)) / pow(10, decimal);
auto factor = pow(10.0, decimal);

string mode = "half_up";
if (args.size() == 3 && args[2].get().type() == Value::Type::STRING) {
mode = args[2].get().getStr();
}
if (boost::iequals(mode, "up")) {
auto roundedVal = std::round(val * factor) / factor;
if ((val < 0) && (roundedVal > val)) {
roundedVal -= 1.0 / factor;
} else if ((val > 0) && (roundedVal < val)) {
roundedVal += 1.0 / factor;
}
return roundedVal;
} else if (boost::iequals(mode, "down")) {
auto roundedVal = std::round(val * factor) / factor;
if ((val < 0) && (roundedVal < val)) {
roundedVal += 1.0 / factor;
} else if ((val > 0) && (roundedVal > val)) {
roundedVal -= 1.0 / factor;
}
return roundedVal;
} else if (boost::iequals(mode, "ceiling")) {
return std::ceil(val * factor) / factor;
} else if (boost::iequals(mode, "floor")) {
return std::floor(val * factor) / factor;
} else if (boost::iequals(mode, "half_up")) {
return std::round(val * factor) / factor;
} else if (boost::iequals(mode, "half_down")) {
auto val_factor = val * factor;
auto integral_part = 0.0;
auto fraction_part = std::fabs(std::modf(val_factor, &integral_part));
if (((fraction_part <= 0.5) && (val < 0)) || ((fraction_part > 0.5) && (val > 0))) {
return std::ceil(val_factor) / factor;
} else {
return std::floor(val_factor) / factor;
}
} else if (boost::iequals(mode, "half_even")) {
auto val_factor = val * factor;
auto integral_part = 0.0;
auto fraction_part = std::fabs(std::modf(val_factor, &integral_part));
if (((fraction_part == 0.5) && (std::fmod(val_factor - 0.5, 2.0) == 1.0)) ||
((fraction_part > 0.5) && (val > 0)) || ((fraction_part < 0.5) && (val < 0))) {
return std::ceil(val_factor) / factor;
} else {
return std::floor(val_factor) / factor;
}
} else {
return Value::kNullBadType;
}
} else {
return Value::kNullBadType;
}
Expand Down
68 changes: 68 additions & 0 deletions src/common/function/test/FunctionManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,40 @@ std::unordered_map<std::string, std::vector<Value>> FunctionManagerTest::args_ =
{"round1", {11111.11111, 2}},
{"round2", {11111.11111, -1}},
{"round3", {11111.11111, -5}},
{"round4", {1.249, 1, "up"}},
{"round5", {-1.251, 1, "up"}},
{"round6", {1.25, 1, "up"}},
{"round7", {-1.35, 1, "up"}},
{"round8", {1.249, 1, "down"}},
{"round9", {-1.251, 1, "down"}},
{"round10", {1.25, 1, "down"}},
{"round11", {-1.35, 1, "down"}},
{"round12", {1.249, 1, "ceiling"}},
{"round13", {-1.251, 1, "ceiling"}},
{"round14", {1.25, 1, "ceiling"}},
{"round15", {-1.35, 1, "ceiling"}},
{"round16", {1.249, 1, "floor"}},
{"round17", {-1.251, 1, "floor"}},
{"round18", {1.25, 1, "floor"}},
{"round19", {-1.35, 1, "floor"}},
{"round20", {1.249, 1, "half_up"}},
{"round21", {-1.251, 1, "half_up"}},
{"round22", {1.25, 1, "half_up"}},
{"round23", {-1.35, 1, "half_up"}},
{"round24", {1.249, 1, "half_down"}},
{"round25", {-1.251, 1, "half_down"}},
{"round26", {1.25, 1, "half_down"}},
{"round27", {-1.35, 1, "half_down"}},
{"round28", {1.249, 1, "half_even"}},
{"round29", {-1.251, 1, "half_even"}},
{"round30", {1.25, 1, "half_even"}},
{"round31", {-1.35, 1, "half_even"}},
{"round32", {1.5, 0, "half_up"}},
{"round33", {1.5, 0, "half_down"}},
{"round34", {12.22, 0, "half_up"}},
{"round35", {1.5, 0}},
{"round36", {-1.5, 1}},
{"round37", {1.25, 1, "dummy_mode"}},
{"radians", {180}},
{"range1", {1, 5}},
{"range2", {1, 5, 2}},
Expand Down Expand Up @@ -282,6 +316,40 @@ TEST_F(FunctionManagerTest, functionCall) {
TEST_FUNCTION(round, args_["round1"], 11111.11);
TEST_FUNCTION(round, args_["round2"], 11110.0);
TEST_FUNCTION(round, args_["round3"], 0.0);
TEST_FUNCTION(round, args_["round4"], 1.3);
TEST_FUNCTION(round, args_["round5"], -1.3);
TEST_FUNCTION(round, args_["round6"], 1.3);
TEST_FUNCTION(round, args_["round7"], -1.4);
TEST_FUNCTION(round, args_["round8"], 1.2);
TEST_FUNCTION(round, args_["round9"], -1.2);
TEST_FUNCTION(round, args_["round10"], 1.2);
TEST_FUNCTION(round, args_["round11"], -1.3);
TEST_FUNCTION(round, args_["round12"], 1.3);
TEST_FUNCTION(round, args_["round13"], -1.2);
TEST_FUNCTION(round, args_["round14"], 1.3);
TEST_FUNCTION(round, args_["round15"], -1.3);
TEST_FUNCTION(round, args_["round16"], 1.2);
TEST_FUNCTION(round, args_["round17"], -1.3);
TEST_FUNCTION(round, args_["round18"], 1.2);
TEST_FUNCTION(round, args_["round19"], -1.4);
TEST_FUNCTION(round, args_["round20"], 1.2);
TEST_FUNCTION(round, args_["round21"], -1.3);
TEST_FUNCTION(round, args_["round22"], 1.3);
TEST_FUNCTION(round, args_["round23"], -1.4);
TEST_FUNCTION(round, args_["round24"], 1.2);
TEST_FUNCTION(round, args_["round25"], -1.3);
TEST_FUNCTION(round, args_["round26"], 1.2);
TEST_FUNCTION(round, args_["round27"], -1.3);
TEST_FUNCTION(round, args_["round28"], 1.2);
TEST_FUNCTION(round, args_["round29"], -1.3);
TEST_FUNCTION(round, args_["round30"], 1.2);
TEST_FUNCTION(round, args_["round31"], -1.4);
TEST_FUNCTION(round, args_["round32"], 2.0);
TEST_FUNCTION(round, args_["round33"], 1.0);
TEST_FUNCTION(round, args_["round34"], 12.0);
TEST_FUNCTION(round, args_["round35"], 2.0);
TEST_FUNCTION(round, args_["round36"], -1.5);
TEST_FUNCTION(round, args_["round37"], Value::kNullBadData);
}
{
TEST_FUNCTION(range, args_["range1"], Value(List({1, 2, 3, 4, 5})));
Expand Down
Loading

0 comments on commit 793c914

Please sign in to comment.