diff --git a/image_analysis/WriteReflections.cpp b/image_analysis/WriteReflections.cpp index faf3b5075..22bfb3e1c 100644 --- a/image_analysis/WriteReflections.cpp +++ b/image_analysis/WriteReflections.cpp @@ -9,6 +9,7 @@ #include "../common/ParallelFor.h" #include +#include #include #include #include @@ -45,16 +46,28 @@ std::string CurrentDateISO() { return buf; } +/// The C locale's "%.*f" of a finite double. std::to_chars where the standard library has it for +/// floating point: the same digits - both round the exact binary value, halfway cases to even - at a +/// quarter of snprintf's time, and with no locale to consult. snprintf elsewhere (libc++ before macOS +/// 13.3). 512 characters hold any finite double. +std::string FixedDigits(double val, int decimals) { + char buf[512]; +#ifdef __cpp_lib_to_chars + const auto r = std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::fixed, decimals); + return std::string(buf, r.ptr); +#else + const int n = std::snprintf(buf, sizeof(buf), "%.*f", decimals, val); + return std::string(buf, n); +#endif +} + /// Format a double with given decimal places; returns "?" for non-finite. -/// snprintf rather than an ostringstream: the reflection loop below calls this twelve times per -/// reflection, and building a stream (and its locale) per call dominated the time spent writing a -/// merged file. Same digits - both go through the C locale's %.*f. +/// Not an ostringstream: the reflection loop below calls this twelve times per reflection, and +/// building a stream (and its locale) per call dominated the time spent writing a merged file. std::string Fmt(double val, int decimals = 4) { if (!std::isfinite(val)) return "?"; - char buf[512]; - const int n = std::snprintf(buf, sizeof(buf), "%.*f", decimals, val); - return std::string(buf, n); + return FixedDigits(val, decimals); } /// Quote a CIF string value; returns "?" for empty. @@ -691,11 +704,7 @@ namespace { if (v.size() < width) s.append(width - v.size(), ' '); s.append(v); }; - const auto num2 = [](double v) { - char b[64]; - const int n = std::snprintf(b, sizeof b, "%.2f", v); - return std::string(b, static_cast(std::clamp(n, 0, static_cast(sizeof b) - 1))); - }; + const auto num2 = [](double v) { return FixedDigits(v, 2); }; column(std::to_string(h), 4); column(std::to_string(k), 4); column(std::to_string(l), 4);