| 1041 | // if T is a IEEE754 binary32 or binary64 and snprintf otherwise. |
| 1042 | template <typename T> |
| 1043 | int format_float(T value, int precision, float_specs specs, buffer<char>& buf) { |
| 1044 | static_assert(!std::is_same<T, float>::value, ""); |
| 1045 | FMT_ASSERT(value >= 0, "value is negative"); |
| 1046 | |
| 1047 | const bool fixed = specs.format == float_format::fixed; |
| 1048 | if (value <= 0) { // <= instead of == to silence a warning. |
| 1049 | if (precision <= 0 || !fixed) { |
| 1050 | buf.push_back('0'); |
| 1051 | return 0; |
| 1052 | } |
| 1053 | buf.resize(to_unsigned(precision)); |
| 1054 | std::uninitialized_fill_n(buf.data(), precision, '0'); |
| 1055 | return -precision; |
| 1056 | } |
| 1057 | |
| 1058 | if (!specs.use_grisu) return snprintf_float(value, precision, specs, buf); |
| 1059 | |
| 1060 | int exp = 0; |
| 1061 | const int min_exp = -60; // alpha in Grisu. |
| 1062 | int cached_exp10 = 0; // K in Grisu. |
| 1063 | if (precision < 0) { |
| 1064 | fp fp_value; |
| 1065 | auto boundaries = specs.binary32 |
| 1066 | ? fp_value.assign_float_with_boundaries(value) |
| 1067 | : fp_value.assign_with_boundaries(value); |
| 1068 | fp_value = normalize(fp_value); |
| 1069 | // Find a cached power of 10 such that multiplying value by it will bring |
| 1070 | // the exponent in the range [min_exp, -32]. |
| 1071 | const fp cached_pow = get_cached_power( |
| 1072 | min_exp - (fp_value.e + fp::significand_size), cached_exp10); |
| 1073 | // Multiply value and boundaries by the cached power of 10. |
| 1074 | fp_value = fp_value * cached_pow; |
| 1075 | boundaries.lower = multiply(boundaries.lower, cached_pow.f); |
| 1076 | boundaries.upper = multiply(boundaries.upper, cached_pow.f); |
| 1077 | assert(min_exp <= fp_value.e && fp_value.e <= -32); |
| 1078 | --boundaries.lower; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}. |
| 1079 | ++boundaries.upper; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}. |
| 1080 | // Numbers outside of (lower, upper) definitely do not round to value. |
| 1081 | grisu_shortest_handler handler{buf.data(), 0, |
| 1082 | boundaries.upper - fp_value.f}; |
| 1083 | auto result = |
| 1084 | grisu_gen_digits(fp(boundaries.upper, fp_value.e), |
| 1085 | boundaries.upper - boundaries.lower, exp, handler); |
| 1086 | if (result == digits::error) { |
| 1087 | exp += handler.size - cached_exp10 - 1; |
| 1088 | fallback_format(value, buf, exp); |
| 1089 | return exp; |
| 1090 | } |
| 1091 | buf.resize(to_unsigned(handler.size)); |
| 1092 | } else { |
| 1093 | if (precision > 17) return snprintf_float(value, precision, specs, buf); |
| 1094 | fp normalized = normalize(fp(value)); |
| 1095 | const auto cached_pow = get_cached_power( |
| 1096 | min_exp - (normalized.e + fp::significand_size), cached_exp10); |
| 1097 | normalized = normalized * cached_pow; |
| 1098 | fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; |
| 1099 | if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error) |
| 1100 | return snprintf_float(value, precision, specs, buf); |
no test coverage detected