| 1728 | |
| 1729 | template <typename Float> |
| 1730 | int format_float(Float value, int precision, float_specs specs, buffer<char>& buf) { |
| 1731 | // float is passed as double to reduce the number of instantiations. |
| 1732 | static_assert(!std::is_same<Float, float>::value, ""); |
| 1733 | FMT_ASSERT(value >= 0, "value is negative"); |
| 1734 | auto converted_value = convert_float(value); |
| 1735 | |
| 1736 | const bool fixed = specs.format == float_format::fixed; |
| 1737 | if (value <= 0) { // <= instead of == to silence a warning. |
| 1738 | if (precision <= 0 || !fixed) { |
| 1739 | buf.push_back('0'); |
| 1740 | return 0; |
| 1741 | } |
| 1742 | buf.try_resize(to_unsigned(precision)); |
| 1743 | fill_n(buf.data(), precision, '0'); |
| 1744 | return -precision; |
| 1745 | } |
| 1746 | |
| 1747 | int exp = 0; |
| 1748 | bool use_dragon = true; |
| 1749 | unsigned dragon_flags = 0; |
| 1750 | if (!is_fast_float<Float>()) { |
| 1751 | const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) |
| 1752 | using info = dragonbox::float_info<decltype(converted_value)>; |
| 1753 | const auto f = basic_fp<typename info::carrier_uint>(converted_value); |
| 1754 | // Compute exp, an approximate power of 10, such that |
| 1755 | // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). |
| 1756 | // This is based on log10(value) == log2(value) / log2(10) and approximation |
| 1757 | // of log2(value) by e + num_fraction_bits idea from double-conversion. |
| 1758 | exp = static_cast<int>( |
| 1759 | ::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); |
| 1760 | dragon_flags = dragon::fixup; |
| 1761 | } else if (!is_constant_evaluated() && precision < 0) { |
| 1762 | // Use Dragonbox for the shortest format. |
| 1763 | if (specs.binary32) { |
| 1764 | auto dec = dragonbox::to_decimal(static_cast<float>(value)); |
| 1765 | write<char>(buffer_appender<char>(buf), dec.significand); |
| 1766 | return dec.exponent; |
| 1767 | } |
| 1768 | auto dec = dragonbox::to_decimal(static_cast<double>(value)); |
| 1769 | write<char>(buffer_appender<char>(buf), dec.significand); |
| 1770 | return dec.exponent; |
| 1771 | } else { |
| 1772 | // Use Grisu + Dragon4 for the given precision: |
| 1773 | // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. |
| 1774 | const int min_exp = -60; // alpha in Grisu. |
| 1775 | int cached_exp10 = 0; // K in Grisu. |
| 1776 | fp normalized = normalize(fp(converted_value)); |
| 1777 | const auto cached_pow = get_cached_power( |
| 1778 | min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); |
| 1779 | normalized = normalized * cached_pow; |
| 1780 | gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; |
| 1781 | if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && |
| 1782 | !is_constant_evaluated()) { |
| 1783 | exp += handler.exp10; |
| 1784 | buf.try_resize(to_unsigned(handler.size)); |
| 1785 | use_dragon = false; |
| 1786 | } else { |
| 1787 | exp += handler.size - cached_exp10 - 1; |
no test coverage detected