From ee2b357d749fa0dcda5e1113a651d9e2e3f37be1 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Mon, 6 Jul 2026 12:44:52 +0300 Subject: [PATCH] IfcParse: serialize REALs with shortest round-trip form #7696 format_double formatted doubles with setprecision(max_digits10) (17 digits), which padded clean values with noise: 0.0174532925199433 was rewritten as 0.017453292519943299 and 1.E-05 as 1.0000000000000001E-05. Every REAL in a file changed on save, producing enormous diffs for anyone version-controlling IFC. Use std::to_chars, which emits the shortest string that round-trips exactly (like Python's repr), then keep the existing mantissa/exponent formatting. Verified in a standalone compile of the exact function logic: the reporter's values become 0.0174532925199433 and 1.E-05, 0.1 stays 0.1, and every tested value (including a denormal) round-trips back to the identical double. Co-Authored-By: Claude Fable 5 --- src/ifcparse/IfcParse.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 52f8a686de..88e1841cec 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef USE_MMAP #include @@ -753,11 +754,16 @@ namespace { // the output of the C++ ostream formatting operation. // REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] . static std::string format_double(const double& d) { + // Use the shortest representation that round-trips exactly (like + // Python's repr) instead of max_digits10. max_digits10 padded clean + // values with noise digits (0.0174532925199433 -> 0.017453292519943299), + // which rewrote every REAL and produced huge diffs when a file was + // re-saved. See #7696. + char buf[64]; + const auto res = std::to_chars(buf, buf + sizeof(buf), d); + const std::string str(buf, res.ptr); std::ostringstream oss; oss.imbue(std::locale::classic()); - oss << std::setprecision(std::numeric_limits::max_digits10) << d; - const std::string str = oss.str(); - oss.str(""); std::string::size_type e = str.find('e'); if (e == std::string::npos) { e = str.find('E');