-
-
Notifications
You must be signed in to change notification settings - Fork 25.3k
Use Grisu2 algorithm in String::num_scientific to fix serializing
#98750
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1934,22 +1934,30 @@ Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, | |
| ////////////////////////////////////////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // These two functions serialize floats or doubles using num_scientific to ensure | ||
| // it can be read back in the same way (except collapsing -0 to 0, and NaN values). | ||
| static String rtos_fix(float p_value, bool p_compat) { | ||
| if (p_value == 0.0f) { | ||
| return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. | ||
| } else if (p_compat) { | ||
| // Write old inf_neg for compatibility. | ||
| if (std::isinf(p_value) && p_value < 0.0f) { | ||
| return "inf_neg"; | ||
| } | ||
| } | ||
| return String::num_scientific(p_value); | ||
| } | ||
|
|
||
| static String rtos_fix(double p_value, bool p_compat) { | ||
| if (p_value == 0.0) { | ||
| return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. | ||
| } else if (std::isnan(p_value)) { | ||
| return "nan"; | ||
| } else if (std::isinf(p_value)) { | ||
| if (p_value > 0) { | ||
| return "inf"; | ||
| } else if (p_compat) { | ||
| return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. | ||
| } else if (p_compat) { | ||
| // Write old inf_neg for compatibility. | ||
| if (std::isinf(p_value) && p_value < 0.0) { | ||
| return "inf_neg"; | ||
| } else { | ||
| return "-inf"; | ||
| } | ||
| } else { | ||
| return rtoss(p_value); | ||
| } | ||
| return String::num_scientific(p_value); | ||
| } | ||
|
|
||
| Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) { | ||
|
|
@@ -1964,11 +1972,17 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str | |
| p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t())); | ||
| } break; | ||
| case Variant::FLOAT: { | ||
| String s = rtos_fix(p_variant.operator double(), p_compat); | ||
| if (s != "inf" && s != "-inf" && s != "nan") { | ||
| if (!s.contains_char('.') && !s.contains_char('e') && !s.contains_char('E')) { | ||
| s += ".0"; | ||
| } | ||
| const double value = p_variant.operator double(); | ||
| String s; | ||
| // Hack to avoid garbage digits when the underlying float is 32-bit. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I found that this "Hack" is also necessary on all the Vectors, AABBs, etc. when compiling with
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This hack works by checking if it's equivalent to the closest 32-bit float value. If you are seeing places where this is needed for vectors with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The two places I see constant git changes are when saving a mesh to a file on import, the AABB is changing between computers, even without a re-import. I haven't been able to follow that code path but it's possible that is getting downcast at some point. The second place is surprisingly on transforms on a saved scene. Many of the node transforms will sometimes change in the scene file despite not being moved. Usually just one digit of change. Given we use double precision for runtime physics and rendering and our individual scenes and meshes don't need the full precision, I'll likely just always cast down to single precision (when it matches) in our variant writer.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I opened this PR to apply this to all float serialization: #110616 |
||
| if ((double)(float)value == value) { | ||
| s = rtos_fix((float)value, p_compat); | ||
| } else { | ||
| s = rtos_fix(value, p_compat); | ||
| } | ||
| // Append ".0" to floats to ensure they are float literals. | ||
| if (s != "inf" && s != "-inf" && s != "nan" && !s.contains_char('.') && !s.contains_char('e') && !s.contains_char('E')) { | ||
| s += ".0"; | ||
| } | ||
| p_store_string_func(p_store_string_ud, s); | ||
| } break; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.