| 3168 | |
| 3169 | template <typename Float> |
| 3170 | FMT_CONSTEXPR20 auto format_float(Float value, int precision, |
| 3171 | const format_specs& specs, bool binary32, |
| 3172 | buffer<char>& buf) -> int { |
| 3173 | // float is passed as double to reduce the number of instantiations. |
| 3174 | static_assert(!std::is_same<Float, float>::value, ""); |
| 3175 | auto converted_value = convert_float(value); |
| 3176 | |
| 3177 | const bool fixed = specs.type() == presentation_type::fixed; |
| 3178 | if (value == 0) { |
| 3179 | if (precision <= 0 || !fixed) { |
| 3180 | buf.push_back('0'); |
| 3181 | return 0; |
| 3182 | } |
| 3183 | buf.try_resize(to_unsigned(precision)); |
| 3184 | fill_n(buf.data(), precision, '0'); |
| 3185 | return -precision; |
| 3186 | } |
| 3187 | |
| 3188 | int exp = 0; |
| 3189 | bool use_dragon = true; |
| 3190 | unsigned dragon_flags = 0; |
| 3191 | if (!is_fast_float<Float>() || is_constant_evaluated()) { |
| 3192 | const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) |
| 3193 | using info = dragonbox::float_info<decltype(converted_value)>; |
| 3194 | const auto f = basic_fp<typename info::carrier_uint>(converted_value); |
| 3195 | // Compute exp, an approximate power of 10, such that |
| 3196 | // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). |
| 3197 | // This is based on log10(value) == log2(value) / log2(10) and approximation |
| 3198 | // of log2(value) by e + num_fraction_bits idea from double-conversion. |
| 3199 | auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; |
| 3200 | exp = static_cast<int>(e); |
| 3201 | if (e > exp) ++exp; // Compute ceil. |
| 3202 | dragon_flags = dragon::fixup; |
| 3203 | } else { |
| 3204 | // Extract significand bits and exponent bits. |
| 3205 | using info = dragonbox::float_info<double>; |
| 3206 | auto br = bit_cast<uint64_t>(static_cast<double>(value)); |
| 3207 | |
| 3208 | const uint64_t significand_mask = |
| 3209 | (static_cast<uint64_t>(1) << num_significand_bits<double>()) - 1; |
| 3210 | uint64_t significand = (br & significand_mask); |
| 3211 | int exponent = static_cast<int>((br & exponent_mask<double>()) >> |
| 3212 | num_significand_bits<double>()); |
| 3213 | |
| 3214 | if (exponent != 0) { // Check if normal. |
| 3215 | exponent -= exponent_bias<double>() + num_significand_bits<double>(); |
| 3216 | significand |= |
| 3217 | (static_cast<uint64_t>(1) << num_significand_bits<double>()); |
| 3218 | significand <<= 1; |
| 3219 | } else { |
| 3220 | // Normalize subnormal inputs. |
| 3221 | FMT_ASSERT(significand != 0, "zeros should not appear here"); |
| 3222 | int shift = countl_zero(significand); |
| 3223 | FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(), |
| 3224 | ""); |
| 3225 | shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2); |
| 3226 | exponent = (std::numeric_limits<double>::min_exponent - |
| 3227 | num_significand_bits<double>()) - |
nothing calls this directly
no test coverage detected