-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
Fixed Issue #187 - Change parse to record floating point representation #201
Conversation
@gregmarr, in relation to "0.0" my rationale was that since a floating point 0.0 was itself a special case it would be better not to complicate the code with yet another special case for -0.0, although it may be slightly more efficient to do so. I've had another look at it and the complication is not as bad as I thought so I have made the change. In relation to the comment - the mention of '15' digits has been there for some time even though |
I also merged With this test removed, |
Could you please put the additional test cases to a different place (best would be directly into |
I didn't realize that it also covered -0.0, since the comment didn't mention it. |
I am currently not sure whether it is a good idea to preserve optional |
@gregmarr, you are correct, the numeric limits should be number_float_t, not double. @nlohmann, it would reduce the code complexity to drop e/E and + preservation but this would not meaningfully affect performance as these are not computationally intensive operations - saving the representation is two comparisons that only need to be done once per number, while applying them involves two comparisons and a very fast loop if the '+' needs to be removed. But I agree it shouldn't be a priority to preserve such things... but in my view the precision needs to be preserved. Really what we need though is a custom function that doesn't depend on The problem I see it with custom double parsing/dumping functions is that both are very challenging to do efficiently. Integer parsing/dumping can easily and efficiently be done with minimal code (no more than 10 lines each) but I would not be surprised if adding custom floating point parsing/dumping added thousands of lines - but maybe I am just being pessimistic. |
I shall finally merge this this weekend. |
Thanks a lot! I merged the code and made some minor adjustments. I hope the tests all succeed. |
All tests are fine. Thanks so much @twelsby! |
// Remove '+' sign from the exponent if necessary | ||
if (!m_type.bits.exp_plus) | ||
{ | ||
if (len > static_cast<int>(sizeof(buf))) len = sizeof(buf); |
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.
Hi @twelsby!
I am currently trying to improve the test coverage of the code, but I fail to create a test case where len
is larger than the size of buf
. The previous snprintf
calls never seem to return anything greater than 263
- and if I understand snprintf
correctly, it would only return a value larger than sizeof(buf)
if writing to the buffer failed. In that case, capping it to sizeof(buf)
and continue to write to it would make no sense.
Before I jump to wrong conclusions, I would like to ask you what situation you had in mind that would require the if.
All the best
Niels
This pull request incorporates the following changes:
get_integer()
that is used instead ofstrtoull()
/strtoll()
. This function implements custom integer parsing that saves the number to the correct basic_json type and returns the type. This also eliminates the need forattempt_cast()
as overflow is detected internally. Additionally details about the floating point representation are collected during the parse (in the event it is not an integer) such as the number of significant figures, the capitalization of 'e' and the use of the optional positive exponential sign. For floating point numbers this function is faster then the method currently used in 2.0.0 and only slightly slower than the method used in 1.1.0. For integers this method is significantly faster than both 2.0.0 and 1.1.0.type_data_t
that incorporates thevalue_t
enum into a bitfield with the floating point representation information. This ensures that no additional memory is used in any packing scenario except byte level packing (unlikely and even then only a small amount extra is used). The type includes operator overloads so that it can be used as an almost drop in replacement for the straightvalue_t
(switch statements need to be changed to use the get() method). Using bitfields results in a small performance overhead but as these variables are accessed only infrequently it is not significant.snprintf()
for the conversion to enable application of the recorded floating point representation. This results in massive performance improvements simply from the change tosnprintf()
.