[gem5-dev] Change in gem5/gem5[develop]: base: Fix scientific number conversion in base/str
Daniel Carvalho has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/38775 ) Change subject: base: Fix scientific number conversion in base/str .. base: Fix scientific number conversion in base/str Previously converting scientific numbers to non-floating numbers would yield incorrect results, because the underlying conversion was using stoll and stoull, which do not deal with scientific numbers properly. Therefore, converting to_number("8.234e+08", val) would yield val=8, which is blatantly wrong (expected 82340). This was fixed by searching for "e" within the string to be converted. To make sure all double and scientific number conversions are correct, a few extra tests were added. Change-Id: I6a9599d8473909d274326b6f8c268e3603044ab4 Signed-off-by: Daniel R. Carvalho Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/38775 Reviewed-by: Bobby R. Bruce Maintainer: Bobby R. Bruce Tested-by: kokoro --- M src/base/str.hh M src/base/str.test.cc 2 files changed, 74 insertions(+), 0 deletions(-) Approvals: Bobby R. Bruce: Looks good to me, approved; Looks good to me, approved kokoro: Regressions pass diff --git a/src/base/str.hh b/src/base/str.hh index 40fd780..d91761d 100644 --- a/src/base/str.hh +++ b/src/base/str.hh @@ -112,6 +112,10 @@ std::is_signed::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} // start big and narrow it down if needed, determine the base dynamically long long r = std::stoll(value, nullptr, 0); if (r < std::numeric_limits::lowest() @@ -126,6 +130,10 @@ !std::is_signed::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} // start big and narrow it down if needed, determine the base dynamically unsigned long long r = std::stoull(value, nullptr, 0); if (r > std::numeric_limits::max()) @@ -137,6 +145,10 @@ typename std::enable_if_t::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} auto r = __to_number::type>(value); return static_cast(r); } diff --git a/src/base/str.test.cc b/src/base/str.test.cc index f0cd483..d3cbc3d 100644 --- a/src/base/str.test.cc +++ b/src/base/str.test.cc @@ -285,6 +285,58 @@ EXPECT_FALSE(to_number(input, output)); } +/** Test that a double that can be converted to int is always rounded down. */ +TEST(StrTest, ToNumberUnsigned8BitIntRoundDown) +{ +uint8_t output; +std::string input_1 = "2.99"; +EXPECT_TRUE(to_number(input_1, output)); +EXPECT_EQ(2, output); + +std::string input_2 = "3.99"; +EXPECT_TRUE(to_number(input_2, output)); +EXPECT_EQ(3, output); +} + +/** + * Test that a double can still be converted to int as long as it is below + * the numerical limit + 1. + */ +TEST(StrTest, ToNumber8BitUnsignedLimit) +{ +uint8_t output; +std::string input = "255.99"; +EXPECT_TRUE(to_number(input, output)); +EXPECT_EQ(255, output); +} + +/** + * Test that a double cannot be converted to int when it passes the numerical + * limit. + */ +TEST(StrTest, ToNumber8BitUnsignedOutOfRange) +{ +uint8_t output; +std::string input = "256.99"; +EXPECT_FALSE(to_number(input, output)); +} + +/** Test that a scientific number cannot be converted to int. */ +TEST(StrTest, ToNumberUnsignedScientific) +{ +uint32_t output; +std::string input = "8.234e+08"; +EXPECT_FALSE(to_number(input, output)); +} + +/** Test that a negative scientific number cannot be converted to int. */ +TEST(StrTest, ToNumberIntScientificNegative) +{ +int32_t output; +std::string input = "-8.234e+08"; +EXPECT_FALSE(to_number(input, output)); +} + TEST(StrTest, ToNumber64BitInt) { int64_t output; @@ -379,6 +431,16 @@ EXPECT_EQ(expected_output, output); } +/** Test that a scientific number is converted properly to double. */ +TEST(StrTest, ToNumberScientific) +{ +double output; +std::string input = "8.234e+08"; +double expected_output = 82340; +EXPECT_TRUE(to_number(input, output)); +EXPECT_EQ(expected_output, output); +} + /* * The "to_bool" function takes a string, "true" or "false" * (case-insenstive), and sets the second argument to the bool equivilent. 5 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. -- To view, visit https://gem5-review.googleso
[gem5-dev] Change in gem5/gem5[develop]: base: Fix scientific number conversion in base/str
Daniel Carvalho has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/41333 ) Change subject: base: Fix scientific number conversion in base/str .. base: Fix scientific number conversion in base/str Previously converting scientific numbers to non-floating numbers would yield incorrect results, because the underlying conversion was using stoll and stoull, which do not deal with scientific numbers properly. Therefore, converting to_number("8.234e+08", val) would yield val=8, which is blatantly wrong (expected 82340). This was fixed by searching for "e" within the string to be converted. To make sure all double and scientific number conversions are correct, a few extra tests were added. Change-Id: I6a9599d8473909d274326b6f8c268e3603044ab4 Signed-off-by: Daniel R. Carvalho base: fixup Change-Id: I7191c8b591f26db0eb6a4ac63a4998ed442a94dc base: fixup Change-Id: I35adc188ec958d7c5a4de97121f28a7c3145c132 --- M src/base/str.hh M src/base/str.test.cc 2 files changed, 74 insertions(+), 0 deletions(-) diff --git a/src/base/str.hh b/src/base/str.hh index 40fd780..d91761d 100644 --- a/src/base/str.hh +++ b/src/base/str.hh @@ -112,6 +112,10 @@ std::is_signed::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} // start big and narrow it down if needed, determine the base dynamically long long r = std::stoll(value, nullptr, 0); if (r < std::numeric_limits::lowest() @@ -126,6 +130,10 @@ !std::is_signed::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} // start big and narrow it down if needed, determine the base dynamically unsigned long long r = std::stoull(value, nullptr, 0); if (r > std::numeric_limits::max()) @@ -137,6 +145,10 @@ typename std::enable_if_t::value, T> __to_number(const std::string &value) { +// Cannot parse scientific numbers +if (value.find('e') != std::string::npos) { +throw std::invalid_argument("Cannot convert scientific to integral"); +} auto r = __to_number::type>(value); return static_cast(r); } diff --git a/src/base/str.test.cc b/src/base/str.test.cc index a064a87..d1d1677 100644 --- a/src/base/str.test.cc +++ b/src/base/str.test.cc @@ -285,6 +285,58 @@ EXPECT_FALSE(to_number(input, output)); } +/** Test that a double that can be converted to int is always rounded down. */ +TEST(StrTest, ToNumberUnsigned8BitIntRoundDown) +{ +uint8_t output; +std::string input_1 = "2.99"; +EXPECT_TRUE(to_number(input_1, output)); +EXPECT_EQ(2, output); + +std::string input_2 = "3.99"; +EXPECT_TRUE(to_number(input_2, output)); +EXPECT_EQ(3, output); +} + +/** + * Test that a double can still be converted to int as long as it is below + * the numerical limit + 1. + */ +TEST(StrTest, ToNumber8BitUnsignedLimit) +{ +uint8_t output; +std::string input = "255.99"; +EXPECT_TRUE(to_number(input, output)); +EXPECT_EQ(255, output); +} + +/** + * Test that a double cannot be converted to int when it passes the numerical + * limit. + */ +TEST(StrTest, ToNumber8BitUnsignedOutOfRange) +{ +uint8_t output; +std::string input = "256.99"; +EXPECT_FALSE(to_number(input, output)); +} + +/** Test that a scientific number cannot be converted to int. */ +TEST(StrTest, ToNumberUnsignedScientific) +{ +uint32_t output; +std::string input = "8.234e+08"; +EXPECT_FALSE(to_number(input, output)); +} + +/** Test that a negative scientific number cannot be converted to int. */ +TEST(StrTest, ToNumberIntScientificNegative) +{ +int32_t output; +std::string input = "-8.234e+08"; +EXPECT_FALSE(to_number(input, output)); +} + TEST(StrTest, ToNumber64BitInt) { int64_t output; @@ -355,6 +407,16 @@ EXPECT_EQ(expected_output, output); } +/** Test that a scientific number is converted properly to double. */ +TEST(StrTest, ToNumberScientific) +{ +double output; +std::string input = "8.234e+08"; +double expected_output = 82340; +EXPECT_TRUE(to_number(input, output)); +EXPECT_EQ(expected_output, output); +} + /* * The "to_bool" function takes a string, "true" or "false" * (case-insenstive), and sets the second argument to the bool equivilent. -- To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/41333 To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings Gerrit-Project: public/gem5 Gerrit-Branch: develop Gerrit-Change-Id: I35adc188ec958d7c5a4de97121f28a7c