| 2999 | |
| 3000 | template <typename Float> |
| 3001 | FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, buffer<char>& buf) -> int { |
| 3002 | // float is passed as double to reduce the number of instantiations. |
| 3003 | static_assert(!std::is_same<Float, float>::value, ""); |
| 3004 | FMT_ASSERT(value >= 0, "value is negative"); |
| 3005 | auto converted_value = convert_float(value); |
| 3006 | |
| 3007 | const bool fixed = specs.format == float_format::fixed; |
| 3008 | if (value <= 0) { // <= instead of == to silence a warning. |
| 3009 | if (precision <= 0 || !fixed) { |
| 3010 | buf.push_back('0'); |
| 3011 | return 0; |
| 3012 | } |
| 3013 | buf.try_resize(to_unsigned(precision)); |
| 3014 | fill_n(buf.data(), precision, '0'); |
| 3015 | return -precision; |
| 3016 | } |
| 3017 | |
| 3018 | int exp = 0; |
| 3019 | bool use_dragon = true; |
| 3020 | unsigned dragon_flags = 0; |
| 3021 | if (!is_fast_float<Float>() || is_constant_evaluated()) { |
| 3022 | const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) |
| 3023 | using info = dragonbox::float_info<decltype(converted_value)>; |
| 3024 | const auto f = basic_fp<typename info::carrier_uint>(converted_value); |
| 3025 | // Compute exp, an approximate power of 10, such that |
| 3026 | // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). |
| 3027 | // This is based on log10(value) == log2(value) / log2(10) and approximation |
| 3028 | // of log2(value) by e + num_fraction_bits idea from double-conversion. |
| 3029 | auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; |
| 3030 | exp = static_cast<int>(e); |
| 3031 | if (e > exp) ++exp; // Compute ceil. |
| 3032 | dragon_flags = dragon::fixup; |
| 3033 | } else if (precision < 0) { |
| 3034 | // Use Dragonbox for the shortest format. |
| 3035 | if (specs.binary32) { |
| 3036 | auto dec = dragonbox::to_decimal(static_cast<float>(value)); |
| 3037 | write<char>(buffer_appender<char>(buf), dec.significand); |
| 3038 | return dec.exponent; |
| 3039 | } |
| 3040 | auto dec = dragonbox::to_decimal(static_cast<double>(value)); |
| 3041 | write<char>(buffer_appender<char>(buf), dec.significand); |
| 3042 | return dec.exponent; |
| 3043 | } else { |
| 3044 | // Extract significand bits and exponent bits. |
| 3045 | using info = dragonbox::float_info<double>; |
| 3046 | auto br = bit_cast<uint64_t>(static_cast<double>(value)); |
| 3047 | |
| 3048 | const uint64_t significand_mask = (static_cast<uint64_t>(1) << num_significand_bits<double>()) - 1; |
| 3049 | uint64_t significand = (br & significand_mask); |
| 3050 | int exponent = static_cast<int>((br & exponent_mask<double>()) >> num_significand_bits<double>()); |
| 3051 | |
| 3052 | if (exponent != 0) { // Check if normal. |
| 3053 | exponent -= exponent_bias<double>() + num_significand_bits<double>(); |
| 3054 | significand |= (static_cast<uint64_t>(1) << num_significand_bits<double>()); |
| 3055 | significand <<= 1; |
| 3056 | } else { |
| 3057 | // Normalize subnormal inputs. |
| 3058 | FMT_ASSERT(significand != 0, "zeros should not appear here"); |
nothing calls this directly
no test coverage detected