diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp index 7e1a7290f..ece0aec78 100644 --- a/src/query/interpret/awesome_memgraph_functions.cpp +++ b/src/query/interpret/awesome_memgraph_functions.cpp @@ -957,7 +957,7 @@ TypedValue ToString(const TypedValue *args, int64_t nargs, const FunctionContext return TypedValue(std::to_string(arg.ValueInt()), ctx.memory); } if (arg.IsDouble()) { - return TypedValue(std::to_string(arg.ValueDouble()), ctx.memory); + return TypedValue(memgraph::utils::DoubleToString(arg.ValueDouble()), ctx.memory); } if (arg.IsDate()) { return TypedValue(arg.ValueDate().ToString(), ctx.memory); diff --git a/src/utils/string.hpp b/src/utils/string.hpp index 833c158c8..8593fc57f 100644 --- a/src/utils/string.hpp +++ b/src/utils/string.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -17,6 +17,7 @@ #include <charconv> #include <cstdint> #include <cstring> +#include <iomanip> #include <iostream> #include <iterator> #include <random> @@ -459,4 +460,30 @@ inline std::string_view Substr(const std::string_view string, size_t pos = 0, si return string.substr(pos, len); } +/** + * Convert a double value to a string representation. + * Precision of converted value is 16. + * Function also removes trailing zeros after the dot. + * + * @param value The double value to be converted. + * + * @return The string representation of the double value. + * + * @throws None + */ +inline std::string DoubleToString(const double value) { + static const int PRECISION = 15; + + std::stringstream ss; + ss << std::setprecision(PRECISION) << std::fixed << value; + auto sv = ss.view(); + + // Because of setprecision and fixed manipulator we are guaranteed to have the dot + sv = sv.substr(0, sv.find_last_not_of('0') + 1); + if (sv.ends_with('.')) { + sv = sv.substr(0, sv.size() - 1); + } + return std::string(sv); +} + } // namespace memgraph::utils diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index c070aaa32..b2a7c1f7a 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -2075,9 +2075,10 @@ TYPED_TEST(FunctionTest, ToStringInteger) { } TYPED_TEST(FunctionTest, ToStringDouble) { - EXPECT_EQ(this->EvaluateFunction("TOSTRING", -42.42).ValueString(), "-42.420000"); - EXPECT_EQ(this->EvaluateFunction("TOSTRING", 0.0).ValueString(), "0.000000"); - EXPECT_EQ(this->EvaluateFunction("TOSTRING", 238910.2313217).ValueString(), "238910.231322"); + EXPECT_EQ(this->EvaluateFunction("TOSTRING", -42.42).ValueString(), "-42.420000000000002"); + EXPECT_EQ(this->EvaluateFunction("TOSTRING", 0.0).ValueString(), "0"); + EXPECT_EQ(this->EvaluateFunction("TOSTRING", 238910.2313217).ValueString(), "238910.231321700004628"); + EXPECT_EQ(this->EvaluateFunction("TOSTRING", 238910.23132171234).ValueString(), "238910.231321712344652"); } TYPED_TEST(FunctionTest, ToStringBool) { diff --git a/tests/unit/utils_string.cpp b/tests/unit/utils_string.cpp index cefe57a6a..fdf64ae9f 100644 --- a/tests/unit/utils_string.cpp +++ b/tests/unit/utils_string.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -171,3 +171,22 @@ TEST(String, Substr) { EXPECT_EQ(Substr(string, string.size() - 1, 1), string.substr(string.size() - 1, 1)); EXPECT_EQ(Substr(string, string.size() - 1, 2), string.substr(string.size() - 1, 2)); } + +TEST(String, DoubleToString) { + EXPECT_EQ(DoubleToString(0), "0"); + EXPECT_EQ(DoubleToString(1), "1"); + EXPECT_EQ(DoubleToString(1234567890123456), "1234567890123456"); + EXPECT_EQ(DoubleToString(static_cast<double>(12345678901234567)), "12345678901234568"); + EXPECT_EQ(DoubleToString(0.5), "0.5"); + EXPECT_EQ(DoubleToString(1.0), "1"); + EXPECT_EQ(DoubleToString(5.8), "5.8"); + EXPECT_EQ(DoubleToString(1.01234000), "1.01234"); + EXPECT_EQ(DoubleToString(1.036837585345), "1.036837585345"); + EXPECT_EQ(DoubleToString(103.6837585345), "103.683758534500001"); + EXPECT_EQ(DoubleToString(1.01234567890123456789), "1.012345678901235"); + EXPECT_EQ(DoubleToString(1234567.01234567891234567), "1234567.012345678871498"); + EXPECT_EQ(DoubleToString(0.00001), "0.00001"); + EXPECT_EQ(DoubleToString(0.00000000000001), "0.00000000000001"); + EXPECT_EQ(DoubleToString(0.000000000000001), "0.000000000000001"); + EXPECT_EQ(DoubleToString(0.0000000000000001), "0"); +}