Add digits argument to String::num_scientific and fix serializing #96676
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Supersedes PR #86951, fixes #78204.
This PR adds a digits argument to
String::num_scientific
and various Variant methods, and uses this to serialize numbers with more precision.We need to serialize with more precision to ensure that a serialized number can be deserialized into the same number. For example, for the number
123456789
, the closest 32-bit float is123456792
. In master this is serialized as1.23457e8
, which becomes123457000
, over 200 off from the closest 32-bit float. With this PR, if a 32-bit float, it will be serialized with 9 digits as123456792
, which can be read back as exactly123456792
. 32-bit floats have 6 reliable digits, but 9 are needed to serialize to decimal in order to read back with full precision.For an example with 64-bit floats, I have
1.234567898765432123456789e30
included in the test cases. The closest 64-bit float is1.23456789876543218850569440461e30
(differs at the 8 which used to be a 2). This gets serialized as1.2345678987654322e+30
which is deserialized to exactly1.23456789876543218850569440461e30
. 64-bit floats have 14 reliable digits, but 17 are needed to serialize to decimal in order to read back with full precision.Note that this will result in more decimals being printed unnecessarily in some cases. For example,
3.4
becomes3.4000001
as a 32-bit float and3.3999999999999999
as a 64-bit float. A better but inefficient algorithm would be to keep increasing the digits until the value matches, but this would require constantly re-writing and re-parsing. I am not sure how this can be improved while still being efficient, but I am sure it's possible. If somebody wants to investigate how this can be improved before this PR is merged, that would be welcome.Note that this does not affect the version bound to GDScript, which uses 6 digits just like it already does in master. I tried adding the argument to the bindings and it seems to break GDExtension compatibility.
Note that writing the unreliable digits should not be done when printing to the user, this is just meant for serializing.
Note that the docs have special code that uses 6 digits, since those are intended to be displayed to the user.