| 163 | } |
| 164 | |
| 165 | string formatDouble(double x, long int precision) |
| 166 | { |
| 167 | // This function ensures that trailing zeros resulting from round-off error |
| 168 | // are removed. Values are only rounded if at least three digits are removed, |
| 169 | // or the displayed value has multiple trailing zeros. |
| 170 | if (x == 0.0) { |
| 171 | return "0.0"; |
| 172 | } |
| 173 | |
| 174 | // Build string with full precision |
| 175 | bool useExp = std::abs(x) < 1e-2 || std::abs(x) >= 1e4; |
| 176 | int log10x = 0; |
| 177 | size_t last; |
| 178 | string s0; |
| 179 | if (useExp) { |
| 180 | s0 = fmt::format(fmt::runtime(fmt::format("{:.{}e}", x, precision))); |
| 181 | // last digit of significand |
| 182 | last = s0.size() - 5; |
| 183 | if (s0[last + 1] == 'e') { |
| 184 | // pass - most values use four letter exponent (examples: e+05, e-03) |
| 185 | } else if (s0[last] == 'e') { |
| 186 | last--; // exponents larger than e+99 or smaller than e-99 (example: e+100) |
| 187 | } else { |
| 188 | last = s0.find('e') - 1; // backstop; slower, but will always work |
| 189 | } |
| 190 | } else { |
| 191 | log10x = static_cast<int>(std::floor(std::log10(std::abs(x)))); |
| 192 | s0 = fmt::format("{:.{}f}", x, precision - log10x); |
| 193 | last = s0.size() - 1; // last digit |
| 194 | } |
| 195 | if (s0[last - 2] == '0' && s0[last - 1] == '0' && s0[last] < '5') { |
| 196 | // Value ending in '00x' and should be rounded down |
| 197 | } else if (s0[last - 2] == '9' && s0[last - 1] == '9' && s0[last] > '4') { |
| 198 | // Value ending in '99y' and should be rounded up |
| 199 | } else if (s0[last - 1] == '0' && s0[last] == '0') { |
| 200 | // Remove trailing zeros |
| 201 | } else { |
| 202 | // Value should not be rounded / do not round last digit |
| 203 | return s0; |
| 204 | } |
| 205 | |
| 206 | // Remove trailing zeros |
| 207 | string s1; |
| 208 | if (s0[last - 1] == '0') { |
| 209 | s1 = s0; // Recycle original string |
| 210 | } else if (useExp) { |
| 211 | s1 = fmt::format(fmt::runtime(fmt::format("{:.{}e}", x, precision - 2))); |
| 212 | } else { |
| 213 | s1 = fmt::format("{:.{}f}", x, precision - log10x - 2); |
| 214 | } |
| 215 | size_t digit = last - 2; |
| 216 | while (s1[digit] == '0' && s1[digit - 1] != '.') { |
| 217 | digit--; |
| 218 | } |
| 219 | |
| 220 | // Assemble rounded value and return |
| 221 | if (useExp) { |
| 222 | size_t eloc = s1.find('e'); |
no test coverage detected