-
Notifications
You must be signed in to change notification settings - Fork 107
fixes parse of -1e-308 #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| return tab[exp]; | ||
| if (exp < -308 || exp > 308) | ||
| { | ||
| return std::pow(10.0, exp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idk about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll get to it. I wanted to prevent the assert from happening
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this check? We need to add tests for the exponent edge cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could just check for "more than 3 digits" and then rely on the finalize to detect the over/underflow. I think i'd prefer that...
oh wait. What if the input is 0.[ten thousand zeroes]1e10000 ?
there's no reason we shouldn't parse this correctly.
It would be trivial to compute the exponent limits on entry into this state
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my view the check is superfluous. it's more expensive to perform the check than to fail late.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I think it is good to fail as soon as we know we have an invalid input. So if we get 309 as the exponent, we can fail right there. I'm not happy about having a potential call to std::pow, especially when we know that the exponent is out of range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0.0000000001e309 is actually 1e289. stod will parse this correctly.
|
The first line of a commit message should be short, certainly not with a number having 500 zeroes... There's no need to quote the number in the commit message, since it is already visible in the test. |
|
This should be squashed down into just one commit |
Fixes a number of issues. Number parsing tests now pass, including edge cases. Remaining: examine options for str to double rounding corrections when number is outside the range 1e-22->1e22 ref: David Gray's seminal work https://ampl.com/netlib/fp/dtoa.c
|
I think we should merge the |
| // abs(mantissa) < 1 | ||
| auto start = dig_ - sig_; | ||
| auto exponent_adjust = -start - 1; | ||
| exp_ += exponent_adjust; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
despite all the naming fanfare it produces warnings:
warning C4244: '+=': conversion from 'int' to 'short', possible loss of data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you take away the unnecessary local variables and simplify the formulas, the interesting relationship between the values becomes visible:
if (pos_ == 0)
{
// abs(mantissa) < 1
exp_ = static_cast<short>(
exp_ + sig_ - dig_ - 1);
}
else
{
// abs(mantissa) >= 1
exp_ = static_cast<short>(
exp_ + pos_ - sig_);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if my problem is related to your discussion. I have a simple Catch2 test for boost.json 1.75.0 that fails because float/double values are not written/read properly:
TEST_CASE("boost::json")
{
// There seems to be an issue with number formatting.
// create a boost::json::value
boost::json::value jv_original = {
{"pi", 3.14159265359},
{"e", 2.71828182846}};
// serialize the boost::json::value to a string
std::string s{boost::json::serialize(jv_original)};
// and write the string to a file
std::string file_name = std::tmpnam(nullptr);
file_name += ".json";
std::ofstream ofs(file_name.c_str());
ofs << s;
ofs.close();
// now read the file into a string
std::ifstream ifs(file_name);
std::string content((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
ifs.close();
std::remove(file_name);
// and create another boost::json::value from that string
boost::system::error_code parseErr;
boost::json::value jv_unserialized = boost::json::parse(content, parseErr);
// compare both boost::json::value objects
CHECK(jv_original == jv_unserialized);
} // TEST_CASE("boost::json")The error message from Catch2 is
[ctest] CHECK( jv_original == jv_unserialized )
[ctest] with expansion:
[ctest] {"pi":3.14159265359E0,"e":2.71828182846E0}
[ctest] ==
[ctest] {"pi":3.1415926535899996E0,"e":2.71828182846E0}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please test against recent Boost version. I can't reprodcue your issue locally on 1.81.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your answer, @grisumbras.
You're right. I built and installed Boost 1.81.0 (still running on Ubuntu 20.04) and the failure is gone.
Ignore the things I wrote below. I used the pretty_print code from the examples to serialize my object. When I use boost::json::value::serialize everything's fine.
Thanks for your input.
However, I use Boost.JSON 1.81.0 in one of my classes and still have the same problem with this value in a JSON file
"latitude": 79.824228,Putting this value in the code above results in success. But my compare(lhs, rhs) method says:
[ctest] values of "latitude" differ: [ctest] lhs 7.9824228E1 [ctest] rhs 7.98242E1I'll investigate further ...
error was in
finish()inexp3state