mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-05 23:41:44 +00:00
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 <noreply@anthropic.com>
This commit is contained in:
committed by
Thomas Krijnen
parent
b1be7d92e6
commit
ee2b357d74
@@ -39,6 +39,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <charconv>
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -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<double>::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');
|
||||
|
||||
Reference in New Issue
Block a user