From 89622d16ad7b22579184e93a13631cd7b550ed95 Mon Sep 17 00:00:00 2001 From: ti-srebot <66930949+ti-srebot@users.noreply.github.com> Date: Tue, 26 Jan 2021 16:52:39 +0800 Subject: [PATCH] expression: change the round rule for approximate value to `round to nearest even` (#21324) (#21628) Signed-off-by: ti-srebot --- expression/builtin_cast_test.go | 4 ++-- expression/builtin_math_test.go | 2 ++ expression/builtin_time_test.go | 2 +- expression/integration_test.go | 2 +- types/convert_test.go | 2 +- types/etc_test.go | 8 ++++---- types/helper.go | 10 +++------- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/expression/builtin_cast_test.go b/expression/builtin_cast_test.go index 2969b0ab848a9..fb5cc1e8ce079 100644 --- a/expression/builtin_cast_test.go +++ b/expression/builtin_cast_test.go @@ -488,8 +488,8 @@ func (s *testEvaluatorSuite) TestCastFuncSig(c *C) { // cast real as int. { &Column{RetType: types.NewFieldType(mysql.TypeDouble), Index: 0}, - 1, - chunk.MutRowFromDatums([]types.Datum{types.NewFloat64Datum(1)}), + 2, + chunk.MutRowFromDatums([]types.Datum{types.NewFloat64Datum(2.5)}), }, // cast Time as int. { diff --git a/expression/builtin_math_test.go b/expression/builtin_math_test.go index 81caabfb30791..e07c7a19f5b70 100644 --- a/expression/builtin_math_test.go +++ b/expression/builtin_math_test.go @@ -431,6 +431,8 @@ func (s *testEvaluatorSuite) TestRound(c *C) { {[]interface{}{1.298, 1}, 1.3}, {[]interface{}{1.298}, 1}, {[]interface{}{1.298, 0}, 1}, + {[]interface{}{-1.5, 0}, -2}, + {[]interface{}{1.5, 0}, 2}, {[]interface{}{23.298, -1}, 20}, {[]interface{}{newDec("-1.23")}, newDec("-1")}, {[]interface{}{newDec("-1.23"), 1}, newDec("-1.2")}, diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index 9cc0cef5260c1..3ee725e78d578 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -2166,7 +2166,7 @@ func (s *testEvaluatorSuite) TestMakeTime(c *C) { {[]interface{}{0, 58.4, 0}, "00:58:00"}, {[]interface{}{0, "58.4", 0}, "00:58:00"}, - {[]interface{}{0, 58.5, 1}, "00:59:01"}, + {[]interface{}{0, 58.5, 1}, "00:58:01"}, {[]interface{}{0, "58.5", 1}, "00:58:01"}, {[]interface{}{0, 59.5, 1}, nil}, {[]interface{}{0, "59.5", 1}, "00:59:01"}, diff --git a/expression/integration_test.go b/expression/integration_test.go index da50573ddb0b2..85602d0caf8cc 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -579,7 +579,7 @@ func (s *testIntegrationSuite2) TestMathBuiltin(c *C) { // for round result = tk.MustQuery("SELECT ROUND(2.5), ROUND(-2.5), ROUND(25E-1);") - result.Check(testkit.Rows("3 -3 3")) // TODO: Should be 3 -3 2 + result.Check(testkit.Rows("3 -3 2")) result = tk.MustQuery("SELECT ROUND(2.5, NULL), ROUND(NULL, 4), ROUND(NULL, NULL), ROUND(NULL);") result.Check(testkit.Rows(" ")) result = tk.MustQuery("SELECT ROUND('123.4'), ROUND('123e-2');") diff --git a/types/convert_test.go b/types/convert_test.go index a2c1978dc4ffd..1a2954d9c93e8 100644 --- a/types/convert_test.go +++ b/types/convert_test.go @@ -970,7 +970,7 @@ func (s *testTypeConvertSuite) TestConvertJSONToInt(c *C) { {`[]`, 0}, {`3`, 3}, {`-3`, -3}, - {`4.5`, 5}, + {`4.5`, 4}, {`true`, 1}, {`false`, 0}, {`null`, 0}, diff --git a/types/etc_test.go b/types/etc_test.go index 6f061018fb390..1a5778f16b8e8 100644 --- a/types/etc_test.go +++ b/types/etc_test.go @@ -137,14 +137,14 @@ func (s *testTypeEtcSuite) TestRoundFloat(c *C) { Input float64 Expect float64 }{ - {2.5, 3}, + {2.5, 2}, {1.5, 2}, - {0.5, 1}, + {0.5, 0}, {0.49999999999999997, 0}, {0, 0}, {-0.49999999999999997, 0}, - {-0.5, -1}, - {-2.5, -3}, + {-0.5, 0}, + {-2.5, -2}, {-1.5, -2}, } diff --git a/types/helper.go b/types/helper.go index 2c8d4b3c8f9f8..e0ea721c53a96 100644 --- a/types/helper.go +++ b/types/helper.go @@ -21,16 +21,12 @@ import ( "github.com/pingcap/errors" ) -// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function. +// RoundFloat rounds float val to the nearest even integer value with float64 format, like MySQL Round function. // RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html -// so rounding use "round half away from zero". +// so rounding use "round to nearest even". // e.g, 1.5 -> 2, -1.5 -> -2. func RoundFloat(f float64) float64 { - if math.Abs(f) < 0.5 { - return 0 - } - - return math.Trunc(f + math.Copysign(0.5, f)) + return math.RoundToEven(f) } // Round rounds the argument f to dec decimal places.