Pevent undefined behavior of ESMry scale factors for values <=0.

We use log10 of the value to compute the scale factor. This only makes
sense for positive values. For zero it returns -HUGE_VAL and for
negative values it returns nan where supported.

Unfortunately on some platforms (e.g. mips64el) further operations in
nan resulted in values so large that the scale factors were to large
for the columns. This resulted in invalid_argument exceptions in
strtod which were hard to debug. Out of pure luck on many platforms
the scale factors still were zero in this case.

To fix this we now always use a scale factor 0 for values less or
equal to zero. This fixes e.g. Debian packages on mips64el.

In addition we now make sure that printed scale factors have less
characters than the column width. Otherwise parsing the *.RSM file
might fail because of throwing strtod function.
This commit is contained in:
Markus Blatt
2023-08-18 18:06:26 +02:00
parent ddb94c15a3
commit 07d1d5f161

View File

@@ -186,7 +186,15 @@ void ESmry::write_block(std::ostream& os,
const auto& vector_data { this->get(vector) } ;
auto max = *std::max_element(vector_data.begin(), vector_data.end());
int scale_factor { std::max(0, 3 * static_cast<int>(std::floor(( std::log10(max) - 4 ) / 3 ))) } ;
// log10 for 0 is undefined and log10 for negative values yields nan.
// We skip the scale factor in these cases to prevent undefined behavior
int scale_factor {
max <= 0 ? 0 :
std::max(0, 3 * static_cast<int>(std::floor(( std::log10(max) - 4 ) / 3 ))) } ;
// Make sure that 10**scale_factor is less than 13 character
scale_factor = std::min(99999999, scale_factor);
if (scale_factor) {
has_scale_factors = true;
}