ToString function now returns double values with precision 15 (#1576)

The DoubleToString function has been updated to handle higher precision doubles correctly. The unnecessary string length restriction has been removed, allowing the function to convert the full double value without prematurely truncating it. This change ensures that the string representation of doubles is more accurate, especially for very large or very small numbers. Unit tests have been added to verify the correct behavior for a range of double values.
This commit is contained in:
Aidar Samerkhanov 2024-01-12 11:32:34 +03:00 committed by GitHub
parent 2e4d27c59a
commit c772cab766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 6 deletions

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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");
}