From 173d50235fa3c5b028fa3c8efa5beec56b752e75 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 23 Jan 2023 15:11:22 -0800 Subject: [PATCH] [libc] add printf auto float conversion This patch adds the final conversion to printf, %g. This is a floating point conversion that selects automatically between the %e and %f formats based on the precision requested and resulting exponent. Additionally it trims trailing zeroes. With this done all that's left for finishing printf is adding long double support to the decimal float conversions. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D143006 --- libc/src/__support/float_to_string.h | 2 + libc/src/stdio/printf_core/converter.cpp | 6 +- libc/src/stdio/printf_core/converter_atlas.h | 4 +- libc/src/stdio/printf_core/float_dec_converter.h | 392 +++++++++++++- libc/test/src/stdio/sprintf_test.cpp | 636 +++++++++++++++++++++++ 5 files changed, 1018 insertions(+), 22 deletions(-) diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h index 47b7ae8..7ea3c5da 100644 --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -89,6 +89,8 @@ LIBC_INLINE constexpr uint32_t length_for_num(const uint32_t idx, // Rewritten slightly we get: // floor(5^(-9i) * 2^(e + c_1 - 9i) + 1) % (10^9 * 2^c_1) +// TODO: Fix long doubles (needs bigger table or alternate algorithm.) +// Currently the table values are generated, which is very slow. template LIBC_INLINE constexpr cpp::UInt get_table_positive(int exponent, size_t i, const size_t constant) { diff --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp index 2ceee7a..7060d9c 100644 --- a/libc/src/stdio/printf_core/converter.cpp +++ b/libc/src/stdio/printf_core/converter.cpp @@ -52,9 +52,9 @@ int convert(Writer *writer, const FormatSection &to_conv) { case 'a': case 'A': return convert_float_hex_exp(writer, to_conv); - // case 'g': - // case 'G': - // return convert_float_mixed(writer, to_conv); + case 'g': + case 'G': + return convert_float_dec_auto(writer, to_conv); #endif // LLVM_LIBC_PRINTF_DISABLE_FLOAT #ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT case 'n': diff --git a/libc/src/stdio/printf_core/converter_atlas.h b/libc/src/stdio/printf_core/converter_atlas.h index 2ad0c72..592474b 100644 --- a/libc/src/stdio/printf_core/converter_atlas.h +++ b/libc/src/stdio/printf_core/converter_atlas.h @@ -24,11 +24,11 @@ #ifndef LLVM_LIBC_PRINTF_DISABLE_FLOAT // defines convert_float_decimal -#include "src/stdio/printf_core/float_dec_converter.h" // defines convert_float_dec_exp +// defines convert_float_dec_auto +#include "src/stdio/printf_core/float_dec_converter.h" // defines convert_float_hex_exp #include "src/stdio/printf_core/float_hex_converter.h" -// defines convert_float_mixed #endif // LLVM_LIBC_PRINTF_DISABLE_FLOAT #ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h index 0fc1d11..e4c3e3e 100644 --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -427,7 +427,8 @@ public: // Here we have to recalculate the total number of digits since the // exponent's width may have changed. We're only adding 1 to exponent // width since exp_str appends the sign. - total_digits = 1 + number_digits + 1 + exponent_width; + total_digits = + (has_decimal_point ? 1 : 0) + number_digits + 1 + exponent_width; // Normally write_left_padding is called by flush_buffer but since we're // rounding up all of the digits, the ones in the buffer are wrong and @@ -580,38 +581,38 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer, } else { const uint32_t maximum = precision - BLOCK_SIZE * i; - uint32_t lastDigit = 0; + uint32_t last_digit = 0; for (uint32_t k = 0; k < BLOCK_SIZE - maximum; ++k) { - lastDigit = digits % 10; + last_digit = digits % 10; digits /= 10; } RoundDirection round; // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? const int32_t requiredTwos = - -exponent - MANT_WIDTH - (int32_t)precision - 1; + -exponent - MANT_WIDTH - static_cast(precision) - 1; const bool trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), - (uint32_t)requiredTwos)); + static_cast(requiredTwos))); switch (fputil::get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. - if (lastDigit != 5) { - round = lastDigit > 5 ? RoundDirection::Up : RoundDirection::Down; + if (last_digit != 5) { + round = last_digit > 5 ? RoundDirection::Up : RoundDirection::Down; } else { round = trailingZeros ? RoundDirection::Even : RoundDirection::Up; } break; case FE_DOWNWARD: - if (is_negative && (!trailingZeros || lastDigit > 0)) { + if (is_negative && (!trailingZeros || last_digit > 0)) { round = RoundDirection::Up; } else { round = RoundDirection::Down; } break; case FE_UPWARD: - if (!is_negative && (!trailingZeros || lastDigit > 0)) { + if (!is_negative && (!trailingZeros || last_digit > 0)) { round = RoundDirection::Up; } else { round = RoundDirection::Down; @@ -746,37 +747,46 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer, // This is the last block. const uint32_t maximum = precision + 1 - digits_written; - uint32_t lastDigit = 0; + uint32_t last_digit = 0; for (uint32_t k = 0; k < last_block_size - maximum; ++k) { - lastDigit = digits % 10; + last_digit = digits % 10; digits /= 10; } + + // If the last block we read doesn't have the digit after the end of what + // we'll print, then we need to read the next block to get that digit. + if (maximum == last_block_size) { + BlockInt extra_block = float_converter.get_block(cur_block - 1); + last_digit = extra_block / ((MAX_BLOCK / 10) + 1); + } + RoundDirection round; // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? - const int32_t requiredTwos = -exponent - MANT_WIDTH - (int32_t)precision - 1; + const int32_t requiredTwos = + -exponent - MANT_WIDTH - static_cast(precision) - 1; const bool trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), - (uint32_t)requiredTwos)); + static_cast(requiredTwos))); switch (fputil::get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. - if (lastDigit != 5) { - round = lastDigit > 5 ? RoundDirection::Up : RoundDirection::Down; + if (last_digit != 5) { + round = last_digit > 5 ? RoundDirection::Up : RoundDirection::Down; } else { round = trailingZeros ? RoundDirection::Even : RoundDirection::Up; } break; case FE_DOWNWARD: - if (is_negative && (!trailingZeros || lastDigit > 0)) { + if (is_negative && (!trailingZeros || last_digit > 0)) { round = RoundDirection::Up; } else { round = RoundDirection::Down; } break; case FE_UPWARD: - if (!is_negative && (!trailingZeros || lastDigit > 0)) { + if (!is_negative && (!trailingZeros || last_digit > 0)) { round = RoundDirection::Up; } else { round = RoundDirection::Down; @@ -794,6 +804,334 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer, return WRITE_OK; } +template , int> = 0> +LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer, + const FormatSection &to_conv, + fputil::FPBits float_bits) { + // signed because later we use -MANT_WIDTH + constexpr int32_t MANT_WIDTH = fputil::MantissaWidth::VALUE; + bool is_negative = float_bits.get_sign(); + int exponent = float_bits.get_exponent(); + MantissaInt mantissa = float_bits.get_explicit_mantissa(); + + // From the standard: Let P (init_precision) equal the precision if nonzero, 6 + // if the precision is omitted, or 1 if the precision is zero. + const size_t init_precision = to_conv.precision <= 0 + ? (to_conv.precision == 0 ? 1 : 6) + : to_conv.precision; + + // Then, if a conversion with style E would have an exponent of X + // (base_10_exp): + int base_10_exp = 0; + // If P > X >= -4 the conversion is with style F and precision P - (X + 1). + // Otherwise, the conversion is with style E and precision P - 1. + + // For calculating the base 10 exponent, we need to process the number as if + // it has style E, so here we calculate the precision we'll use in that case. + const size_t exp_precision = init_precision - 1; + + FloatToString float_converter(static_cast(float_bits)); + + // Here we would subtract 1 to account for the fact that block 0 counts as a + // positive block, but the loop below accounts for this by starting with + // subtracting 1 from cur_block. + int cur_block; + + if (exponent < 0) { + cur_block = -float_converter.zero_blocks_after_point(); + } else { + cur_block = float_converter.get_positive_blocks(); + } + + BlockInt digits = 0; + + // If the mantissa is 0, then the number is 0, meaning that looping until a + // non-zero block is found will loop forever. + if (mantissa != 0) { + // This loop finds the first non-zero block. + while (digits == 0) { + --cur_block; + digits = float_converter.get_block(cur_block); + } + } else { + // In the case of 0.0, then it's always decimal format. If we don't have alt + // form then the trailing zeroes are trimmed to make "0", else the precision + // is 1 less than specified by the user. + FormatSection new_conv = to_conv; + if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { + // This is a style F conversion, making the precision P - 1 - X, but since + // this is for the number 0, X (the base 10 exponent) is always 0. + new_conv.precision = init_precision - 1; + } else { + new_conv.precision = 0; + } + return convert_float_decimal_typed(writer, new_conv, float_bits); + } + + size_t block_width = 0; + { + // TODO: Find a better way to calculate the number of digits in the + // initial block and exponent. + char buf[IntegerToString::dec_bufsize()]; + auto int_to_str = *IntegerToString::dec(digits, buf); + block_width = int_to_str.size(); + } + + size_t digits_checked = 0; + // TODO: look into unifying trailing_zeroes and trailing_nines. The number can + // end in a nine or a zero, but not both. + size_t trailing_zeroes = 0; + size_t trailing_nines = 0; + + base_10_exp = (cur_block * BLOCK_SIZE) + (block_width - 1); + + // If the first block is not also the last block + if (block_width <= exp_precision + 1) { + char buf[IntegerToString::dec_bufsize()]; + auto int_to_str = *IntegerToString::dec(digits, buf); + + for (size_t i = 0; i < block_width; ++i) { + if (int_to_str[i] == '9') { + ++trailing_nines; + trailing_zeroes = 0; + } else if (int_to_str[i] == '0') { + ++trailing_zeroes; + trailing_nines = 0; + } else { + trailing_nines = 0; + trailing_zeroes = 0; + } + } + digits_checked += block_width; + --cur_block; + } + + // Handle middle blocks + for (; digits_checked + BLOCK_SIZE < exp_precision + 1; --cur_block) { + digits = float_converter.get_block(cur_block); + digits_checked += BLOCK_SIZE; + if (digits == MAX_BLOCK) { + trailing_nines += 9; + trailing_zeroes = 0; + } else if (digits == 0) { + trailing_zeroes += 9; + trailing_nines = 0; + } else { + // The block is neither all nines nor all zeroes, so we need to figure out + // what it ends with. + trailing_nines = 0; + trailing_zeroes = 0; + BlockInt copy_of_digits = digits; + int cur_last_digit = copy_of_digits % 10; + // We only care if it ends in nines or zeroes. + while (copy_of_digits > 0 && + (cur_last_digit == 9 || cur_last_digit == 0)) { + // If the next digit is not the same as the previous one, then there are + // no more contiguous trailing digits. + if ((copy_of_digits % 10) != cur_last_digit) { + break; + } + if (cur_last_digit == 9) { + ++trailing_nines; + } else if (cur_last_digit == 0) { + ++trailing_zeroes; + } else { + break; + } + copy_of_digits /= 10; + } + } + } + + // Handle the last block + + digits = float_converter.get_block(cur_block); + + size_t last_block_size = BLOCK_SIZE; + + char buf[IntegerToString::dec_bufsize()]; + auto int_to_str = *IntegerToString::dec(digits, buf); + + int implicit_leading_zeroes = BLOCK_SIZE - int_to_str.size(); + + // if the last block is also the first block, then ignore leading zeroes. + if (digits_checked == 0) { + last_block_size = int_to_str.size(); + implicit_leading_zeroes = 0; + } else { + // If the block is not the maximum size, that means it has leading + // zeroes, and zeroes are not nines. + if (implicit_leading_zeroes > 0) { + trailing_nines = 0; + } + + // But leading zeroes are zeroes (that could be trailing). + trailing_zeroes += implicit_leading_zeroes; + } + + int digits_requested = (exp_precision + 1) - digits_checked; + + int digits_to_check = digits_requested - implicit_leading_zeroes; + if (digits_to_check < 0) { + digits_to_check = 0; + } + + // Check the upper digits of this block. + for (int i = 0; i < digits_to_check; ++i) { + if (int_to_str[i] == '9') { + ++trailing_nines; + trailing_zeroes = 0; + } else if (int_to_str[i] == '0') { + ++trailing_zeroes; + trailing_nines = 0; + } else { + trailing_nines = 0; + trailing_zeroes = 0; + } + } + + // Find the digit after the lowest digit that we'll actually print to + // determine the rounding. + const uint32_t maximum = exp_precision + 1 - digits_checked; + uint32_t last_digit = 0; + for (uint32_t k = 0; k < last_block_size - maximum; ++k) { + last_digit = digits % 10; + digits /= 10; + } + + // If the last block we read doesn't have the digit after the end of what + // we'll print, then we need to read the next block to get that digit. + if (maximum == last_block_size) { + BlockInt extra_block = float_converter.get_block(cur_block - 1); + last_digit = extra_block / ((MAX_BLOCK / 10) + 1); + } + + // TODO: unify this code across the three float conversions. + RoundDirection round; + // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? + const int32_t requiredTwos = + -exponent - MANT_WIDTH - static_cast(exp_precision) - 1; + // TODO: rename this variable to remove confusion with trailing_zeroes + const bool trailingZeros = + requiredTwos <= 0 || + (requiredTwos < 60 && + multiple_of_power_of_2(float_bits.get_explicit_mantissa(), + static_cast(requiredTwos))); + switch (fputil::get_round()) { + case FE_TONEAREST: + // Round to nearest, if it's exactly halfway then round to even. + if (last_digit != 5) { + round = last_digit > 5 ? RoundDirection::Up : RoundDirection::Down; + } else { + round = trailingZeros ? RoundDirection::Even : RoundDirection::Up; + } + break; + case FE_DOWNWARD: + if (is_negative && (!trailingZeros || last_digit > 0)) { + round = RoundDirection::Up; + } else { + round = RoundDirection::Down; + } + break; + case FE_UPWARD: + if (!is_negative && (!trailingZeros || last_digit > 0)) { + round = RoundDirection::Up; + } else { + round = RoundDirection::Down; + } + round = is_negative ? RoundDirection::Down : RoundDirection::Up; + break; + case FE_TOWARDZERO: + round = RoundDirection::Down; + break; + } + + bool round_up; + if (round == RoundDirection::Up) { + round_up = true; + } else if (round == RoundDirection::Down) { + round_up = false; + } else { + // RoundDirection is even, so check the extra digit. + uint32_t low_digit = digits % 10; + round_up = (low_digit % 2) != 0; + } + + digits_checked += digits_requested; + // assert(digits_checked == init_precision); + // At this point we should have checked all the digits requested by the + // precision. We may increment this number 1 more if we round up all of the + // digits, but at this point in the code digits_checked should always equal + // init_precision. + + if (round_up) { + // If all the digits that would be printed are nines, then rounding up means + // that the base 10 exponent is one higher and all those nines turn to + // zeroes (e.g. 999 -> 1000). + if (trailing_nines == init_precision) { + ++base_10_exp; + trailing_zeroes = digits_checked; + ++digits_checked; + } else { + // If there are trailing nines, they turn into trailing zeroes when + // they're rounded up. + if (trailing_nines > 0) { + trailing_zeroes += trailing_nines; + } else if (trailing_zeroes > 0) { + // If there are trailing zeroes, then the last digit will be rounded up + // to a 1 so they aren't trailing anymore. + trailing_zeroes = 0; + } + } + } + + // if P > X >= -4, the conversion is with style f (or F) and precision equals + // P - (X + 1). + if (static_cast(init_precision) > base_10_exp && base_10_exp >= -4) { + FormatSection new_conv = to_conv; + const size_t conv_precision = init_precision - (base_10_exp + 1); + + if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { + new_conv.precision = conv_precision; + } else { + // If alt form isn't set, then we need to determine the number of trailing + // zeroes and set the precision such that they are removed. + int trimmed_precision = + digits_checked - (base_10_exp + 1) - trailing_zeroes; + if (trimmed_precision < 0) { + trimmed_precision = 0; + } + new_conv.precision = + (static_cast(trimmed_precision) > conv_precision) + ? conv_precision + : trimmed_precision; + } + + return convert_float_decimal_typed(writer, new_conv, float_bits); + } else { + // otherwise, the conversion is with style e (or E) and precision equals + // P - 1 + const size_t conv_precision = init_precision - 1; + FormatSection new_conv = to_conv; + if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { + new_conv.precision = conv_precision; + } else { + // If alt form isn't set, then we need to determine the number of trailing + // zeroes and set the precision such that they are removed. + int trimmed_precision = digits_checked - 1 - trailing_zeroes; + if (trimmed_precision < 0) { + trimmed_precision = 0; + } + new_conv.precision = + (static_cast(trimmed_precision) > conv_precision) + ? conv_precision + : trimmed_precision; + } + return convert_float_dec_exp_typed(writer, new_conv, float_bits); + } +} + +// TODO: unify the float converters to remove the duplicated checks for inf/nan. LIBC_INLINE int convert_float_decimal(Writer *writer, const FormatSection &to_conv) { if (to_conv.length_modifier == LengthModifier::L) { @@ -834,6 +1172,26 @@ LIBC_INLINE int convert_float_dec_exp(Writer *writer, return convert_inf_nan(writer, to_conv); } +LIBC_INLINE int convert_float_dec_auto(Writer *writer, + const FormatSection &to_conv) { + if (to_conv.length_modifier == LengthModifier::L) { + fputil::FPBits::UIntType float_raw = to_conv.conv_val_raw; + fputil::FPBits float_bits(float_raw); + if (!float_bits.is_inf_or_nan()) { + return convert_float_dec_auto_typed(writer, to_conv, + float_bits); + } + } else { + fputil::FPBits::UIntType float_raw = to_conv.conv_val_raw; + fputil::FPBits float_bits(float_raw); + if (!float_bits.is_inf_or_nan()) { + return convert_float_dec_auto_typed(writer, to_conv, float_bits); + } + } + + return convert_inf_nan(writer, to_conv); +} + } // namespace printf_core } // namespace __llvm_libc diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp index 552cb70..8e16c88 100644 --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -13,6 +13,11 @@ #include "utils/UnitTest/Test.h" #include "utils/testutils/RoundingModeUtils.h" +// #include +// namespace __llvm_libc { +// using ::sprintf; +// } + class LlvmLibcSPrintfTest : public __llvm_libc::testing::Test { protected: char buff[1000]; @@ -1998,6 +2003,12 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) { written = __llvm_libc::sprintf(buff, "%10.1e", 9.99); ASSERT_STREQ_LEN(written, buff, " 1.0e+01"); + written = __llvm_libc::sprintf(buff, "%10.0e", 9.99); + ASSERT_STREQ_LEN(written, buff, " 1e+01"); + + written = __llvm_libc::sprintf(buff, "%10.0e", 0.0999); + ASSERT_STREQ_LEN(written, buff, " 1e-01"); + written = __llvm_libc::sprintf(buff, "%-10.2e", 9.99); ASSERT_STREQ_LEN(written, buff, "9.99e+00 "); @@ -2019,6 +2030,9 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) { written = __llvm_libc::sprintf(buff, "%25.13e", 9999999999999.99); ASSERT_STREQ_LEN(written, buff, " 1.0000000000000e+13"); + written = __llvm_libc::sprintf(buff, "%25.12e", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 1.000000000000e+13"); + written = __llvm_libc::sprintf(buff, "%12.3e %-12.3e", 0.1, 256.0); ASSERT_STREQ_LEN(written, buff, " 1.000e-01 2.560e+02 "); @@ -2026,6 +2040,628 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) { ASSERT_STREQ_LEN(written, buff, "+1.256e-01 001.256e+03"); } +TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Nearest); + double inf = __llvm_libc::fputil::FPBits::inf().get_val(); + double nan = __llvm_libc::fputil::FPBits::build_nan(1); + + written = __llvm_libc::sprintf(buff, "%g", 1.0); + ASSERT_STREQ_LEN(written, buff, "1"); + + written = __llvm_libc::sprintf(buff, "%G", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1"); + + written = __llvm_libc::sprintf(buff, "%g", -1.234567); + ASSERT_STREQ_LEN(written, buff, "-1.23457"); + + written = __llvm_libc::sprintf(buff, "%g", 0.0); + ASSERT_STREQ_LEN(written, buff, "0"); + + written = __llvm_libc::sprintf(buff, "%g", -0.0); + ASSERT_STREQ_LEN(written, buff, "-0"); + + written = __llvm_libc::sprintf(buff, "%g", 1.5); + ASSERT_STREQ_LEN(written, buff, "1.5"); + + written = __llvm_libc::sprintf(buff, "%g", 1e300); + ASSERT_STREQ_LEN(written, buff, "1e+300"); + + written = __llvm_libc::sprintf(buff, "%g", 0.1); + ASSERT_STREQ_LEN(written, buff, "0.1"); + + written = __llvm_libc::sprintf(buff, "%g", 0.001); + ASSERT_STREQ_LEN(written, buff, "0.001"); + + written = __llvm_libc::sprintf(buff, "%g", 0.00001); + ASSERT_STREQ_LEN(written, buff, "1e-05"); + + written = __llvm_libc::sprintf(buff, "%g", 0.0000001); + ASSERT_STREQ_LEN(written, buff, "1e-07"); + + written = __llvm_libc::sprintf(buff, "%g", 0.000000001); + ASSERT_STREQ_LEN(written, buff, "1e-09"); + + written = __llvm_libc::sprintf(buff, "%g", 1.0e-20); + ASSERT_STREQ_LEN(written, buff, "1e-20"); + + written = __llvm_libc::sprintf(buff, "%g", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, "1.23457e+18"); + + written = __llvm_libc::sprintf(buff, "%g", 9999990000000.00); + ASSERT_STREQ_LEN(written, buff, "9.99999e+12"); + + written = __llvm_libc::sprintf(buff, "%g", 9999999000000.00); + ASSERT_STREQ_LEN(written, buff, "1e+13"); + + // Simple Subnormal Tests. + + written = __llvm_libc::sprintf(buff, "%g", 0x1.0p-1027); + ASSERT_STREQ_LEN(written, buff, "6.95336e-310"); + + written = __llvm_libc::sprintf(buff, "%g", 0x1.0p-1074); + ASSERT_STREQ_LEN(written, buff, "4.94066e-324"); + + // Inf/Nan Tests. + + written = __llvm_libc::sprintf(buff, "%g", inf); + ASSERT_STREQ_LEN(written, buff, "inf"); + + written = __llvm_libc::sprintf(buff, "%G", -inf); + ASSERT_STREQ_LEN(written, buff, "-INF"); + + written = __llvm_libc::sprintf(buff, "%g", nan); + ASSERT_STREQ_LEN(written, buff, "nan"); + + written = __llvm_libc::sprintf(buff, "%G", -nan); + ASSERT_STREQ_LEN(written, buff, "-NAN"); + + // Length Modifier Tests. + + // TODO: Uncomment the below tests after long double support is added + /* + written = __llvm_libc::sprintf(buff, "%Lf", 1e100L); + ASSERT_STREQ_LEN(written, buff, + "99999999999999999996693535322073426194986990198284960792713" + "91541752018669482644324418977840117055488.000000"); + + written = __llvm_libc::sprintf(buff, "%Lf", 1.0L); + ASSERT_STREQ_LEN(written, buff, "1.000000"); + + char big_buff[10000]; + written = __llvm_libc::sprintf(big_buff, "%Lf", 1e1000L); + ASSERT_STREQ_LEN( + written, big_buff, + "999999999999999999973107317669562353428234857594552594925899449376328728" + "202461036775511405481186963193066642191664822065529414252060696836533522" + "387143501724276282079456797058697369889056407118642873669166717313763499" + "277025985141177344925615052465165938514140943010597323750202561187880136" + "174810574553749194614479541820148407958204853833697063267336294787191005" + "628217462261955103745349844675732989944229689277833828743730290177882029" + "042613704915899149603539993716885598351951895974316347947147507970269673" + "097709017164643598452451201499004104341931127294141495501309305995449742" + "273419524803597130450457553871345958049837885085168840317195672271085085" + "950520957945970913451088104971436093671776829538796532762184174216651692" + "640931965387852083906784898823494867055070322768919156031682291829761007" + "101483799978382119231551218582499361996919560548090784230386907125151658" + "086767207295524036170321059257942621398084478974000973622199163292708506" + "2431457550909271560663602154947063707982236377366647567795879936." + "000000"); + + written = __llvm_libc::sprintf(big_buff, "%Lf", 1e4900L); + ASSERT_STREQ_LEN( + written, big_buff, + "100000000000000000002708312230690349833224052504078834346502930111959028" + "517260692666637048230414374897655201843766090626319971729765251179632020" + "313912652522792711197087872698264530532442630109549129842736280196919130" + "242615101228133188193853826983121366159061148351354364472807590931218045" + "387490935930967150336231085015126034696883068553581691802388371635128003" + "615577299166097675723780877126495909902479233742826339471026068806070433" + "075629449530819183550315434973800271862658869400009022028602967197463980" + "126881829804282202449930132940824361207087494829502385835258094836304011" + "876250359661206802659650567866176246063987902366800491980400341950657151" + "370854446585517805253310195469184699955519312761482572080479702840420595" + "377369017651259376039167277822106875560385309101650382998482652792335482" + "865443482342801545877390859444282105890147577937366066315975231014810320" + "888482059656248277607763361589359794524314002443575149260630989130103550" + "443177966380769341050735632338583912575890190136462629316287947355057647" + "111088565611192544631519843618778618820046304429723908484879583579178075" + "456701368334212923379389029311286386996015804122917416008806233549005183" + "152461084266176543129004016414959261473645240454289630182591200574019087" + "358223489767381636349719510715487188747217311279465814538495924567014916" + "238565628036285599497236493491668884212847699052761266207598941300449276" + "447201387520841811835583254242213093566548778954711633721122784159793843" + "766802019309395771984693609426401362800013936338891483689127845928572536" + "790651156184721483511507878883282891696900630100211914227950790472211403" + "392549466062537498185758854079775888444518306635752468713312357556380082" + "275500658967283696421824354930077523691855699312544373220921962817907078" + "445538421941800259027487429330768616490865438859612697367766323925013940" + "918384858952407145253573823848733994146335416209309233074165707437420756" + "438833918763109580759409985573826485055208965115587885226774453455112406" + "581351429640282227888764449360534584421929291565334894907337572527922691" + "473242328379737396430908523008687037407295838014450772162091496534584696" + "605157436893236842602956298545594095307060870397506421786236892553632163" + "491468601982681381011940409602294892199042638682530687578982576819839451" + "907594697546439533559153604700750696252355362322662219852740143212566818" + "745528402265116534684566273868361460640280523251242059850044328669692159" + "629900374576027104298177006629276014371540945261309319363704125592775129" + "543526908667388673739382491147471395192495459318806593271282662311169392" + "196897003517840025298267505925987901751541005546610016067658227181318892" + "914686508281007582655667597441346214499847364272258631922040641860333431" + "409838623713258383681350233064164940590695888300919626215847587544298023" + "636416943680102708406086295669759876682046839368574433996997648445207805" + "615784339667691231286807666753972942872019850432610318031627872612657513" + "588188267160616660825719678199868371370527508463011236193719286066916786" + "169956541349011494927225747024994619057884118692213564790598702879596058" + "672338334720925179141906809470606964896245458600635183723159228561689808" + "246141482736625197373238197777325580142168245885279594913851700941789475" + "252421784152262567254611571822468808675893407728003047921107885664474662" + "930921581384003950729114103689170603748380178682003976896397305836815761" + "717676338115866650889936516794601457549097578905329423919798362140648664" + "569177147076571576101649257502509463877402424847669830852345415301684820" + "395813946416649808062227494112874521812750160935760825922220707178083076" + "380203450993589198835885505461509442443773367592842795410339065860781804" + "024975272228687688301824830333940416256885455008512598774611538878683158" + "183931461086893832255176926531299425504132104728730288984598001187854507" + "900417184206801359847651992484444933900133130832052346600926424167009902" + "829803553087005800387704758687923428053612864451456596148162238935900033" + "917094683141205188616000211702577553792389670853917118547527592495253773" + "028135298405566315903922235989614934474805789300370437580494193066066314" + "056627605207631392651010580925826419831250810981343093764403877594495896" + "516881097415880926429607388979497471571321217205535961262051641426436441" + "668989765107456413733909427384182109285933511623871034309722437967253289" + "084018145083721513211807496392673952789642893241520398827805325610653506" + "029060153153064455898648607959013571280930834475689835845791849456112104" + "462337569019001580859906425911782967213265389744605395555069797947978230" + "708108432086217134763779632408473684293543722127232658767439906910370146" + "716836295909075482355827087389127370874842532825987593970846704144140471" + "956027276735614286138656432085771988513977140957180090146798065497158947" + "229765733489703157617307078835099906185890777007500964162371428641176460" + "739074789794941408428328217107759915202650066155868439585510978709442590" + "231934194956788626761834746430104077432547436359522462253411168467463134" + "24896.000000"); +*/ + /* + written = __llvm_libc::sprintf(buff, "%La", 0.1L); + #if defined(SPECIAL_X86_LONG_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7"); + #elif defined(LONG_DOUBLE_IS_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4"); + #else // 128 bit long double + ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4"); + #endif + + written = __llvm_libc::sprintf(buff, "%La", 1.0e1000L); + #if defined(SPECIAL_X86_LONG_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318"); + #elif defined(LONG_DOUBLE_IS_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "inf"); + #else // 128 bit long double + ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321"); + #endif + + written = __llvm_libc::sprintf(buff, "%La", 1.0e-1000L); + #if defined(SPECIAL_X86_LONG_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325"); + #elif defined(LONG_DOUBLE_IS_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0x0p+0"); + #else // 128 bit long double + ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322"); + #endif + */ + + // Min Width Tests. + + written = __llvm_libc::sprintf(buff, "%15g", 1.0); + ASSERT_STREQ_LEN(written, buff, " 1"); + + written = __llvm_libc::sprintf(buff, "%15g", -1.0); + ASSERT_STREQ_LEN(written, buff, " -1"); + + written = __llvm_libc::sprintf(buff, "%15g", 1.0e5); + ASSERT_STREQ_LEN(written, buff, " 100000"); + + written = __llvm_libc::sprintf(buff, "%15g", -1.0e5); + ASSERT_STREQ_LEN(written, buff, " -100000"); + + written = __llvm_libc::sprintf(buff, "%10g", 1.0e-5); + ASSERT_STREQ_LEN(written, buff, " 1e-05"); + + // Precision Tests. + + written = __llvm_libc::sprintf(buff, "%.2g", 1.23456789); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + // Trimming trailing zeroes causes the precision to be ignored here. + written = __llvm_libc::sprintf(buff, "%.1g", 0.0); + ASSERT_STREQ_LEN(written, buff, "0"); + + written = __llvm_libc::sprintf(buff, "%.0g", 0.0); + ASSERT_STREQ_LEN(written, buff, "0"); + + written = __llvm_libc::sprintf(buff, "%.2g", 0.1); + ASSERT_STREQ_LEN(written, buff, "0.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.09); + ASSERT_STREQ_LEN(written, buff, "1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.04); + ASSERT_STREQ_LEN(written, buff, "1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.19); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.99); + ASSERT_STREQ_LEN(written, buff, "2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 9.99); + ASSERT_STREQ_LEN(written, buff, "10"); + + written = __llvm_libc::sprintf(buff, "%.3g", 99.9); + ASSERT_STREQ_LEN(written, buff, "99.9"); + + written = __llvm_libc::sprintf(buff, "%.2g", 99.9); + ASSERT_STREQ_LEN(written, buff, "1e+02"); + + written = __llvm_libc::sprintf(buff, "%.1g", 99.9); + ASSERT_STREQ_LEN(written, buff, "1e+02"); + + written = __llvm_libc::sprintf(buff, "%.5g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.25"); + + written = __llvm_libc::sprintf(buff, "%.0g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1"); + + written = __llvm_libc::sprintf(buff, "%.0g", 1.75); + ASSERT_STREQ_LEN(written, buff, "2"); + + written = __llvm_libc::sprintf(buff, "%.20g", 1.234e-10); + ASSERT_STREQ_LEN(written, buff, "1.2340000000000000814e-10"); + + written = __llvm_libc::sprintf(buff, "%.3g", -9.99); + ASSERT_STREQ_LEN(written, buff, "-9.99"); + + written = __llvm_libc::sprintf(buff, "%.2g", -9.99); + ASSERT_STREQ_LEN(written, buff, "-10"); + + written = __llvm_libc::sprintf(buff, "%.1g", -9.99); + ASSERT_STREQ_LEN(written, buff, "-1e+01"); + + written = __llvm_libc::sprintf(buff, "%.5g", 1.008); + ASSERT_STREQ_LEN(written, buff, "1.008"); + + written = __llvm_libc::sprintf(buff, "%.5g", 1.008e3); + ASSERT_STREQ_LEN(written, buff, "1008"); + + written = __llvm_libc::sprintf(buff, "%.4g", 9999.0); + ASSERT_STREQ_LEN(written, buff, "9999"); + + written = __llvm_libc::sprintf(buff, "%.3g", 9999.0); + ASSERT_STREQ_LEN(written, buff, "1e+04"); + + written = __llvm_libc::sprintf(buff, "%.3g", 1256.0); + ASSERT_STREQ_LEN(written, buff, "1.26e+03"); + + // Subnormal Precision Tests + + written = __llvm_libc::sprintf(buff, "%.310g", 0x1.0p-1022); + ASSERT_STREQ_LEN( + written, buff, + "2." + "225073858507201383090232717332404064219215980462331830553327416887204434" + "813918195854283159012511020564067339731035811005152434161553460108856012" + "385377718821130777993532002330479610147442583636071921565046942503734208" + "375250806650616658158948720491179968591639648500635908770118304874799780" + "887753749949451580452e-308"); + + written = __llvm_libc::sprintf(buff, "%.30g", 0x1.0p-1022); + ASSERT_STREQ_LEN(written, buff, "2.22507385850720138309023271733e-308"); + + written = __llvm_libc::sprintf(buff, "%.310g", 0x1.0p-1023); + ASSERT_STREQ_LEN( + written, buff, + "1." + "112536929253600691545116358666202032109607990231165915276663708443602217" + "406959097927141579506255510282033669865517905502576217080776730054428006" + "192688859410565388996766001165239805073721291818035960782523471251867104" + "187625403325308329079474360245589984295819824250317954385059152437399890" + "443876874974725790226e-308"); + + written = __llvm_libc::sprintf(buff, "%.7g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "9.99999e-310"); + + written = __llvm_libc::sprintf(buff, "%.6g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "9.99999e-310"); + + written = __llvm_libc::sprintf(buff, "%.5g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.4g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.3g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.2g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.1g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.0g", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.10g", 0x1.0p-1074); + ASSERT_STREQ_LEN(written, buff, "4.940656458e-324"); + + // Long double precision tests. + // These are currently commented out because they require long double support + // that isn't ready yet. + /* + written = __llvm_libc::sprintf(buff, "%.1La", 0.1L); + #if defined(SPECIAL_X86_LONG_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0xc.dp-7"); + #elif defined(LONG_DOUBLE_IS_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0x1.ap-4"); + #else // 128 bit long double + ASSERT_STREQ_LEN(written, buff, "0x1.ap-4"); + #endif + + written = __llvm_libc::sprintf(buff, "%.1La", 0xf.fffffffffffffffp16380L); + #if defined(SPECIAL_X86_LONG_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384"); + #elif defined(LONG_DOUBLE_IS_DOUBLE) + ASSERT_STREQ_LEN(written, buff, "inf"); + #else // 128 bit long double + ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383"); + #endif + */ + + // Rounding Mode Tests. + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Nearest); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.4"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.9"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.4"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.9"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Upward); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.4"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.9"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.8"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Downward); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.4"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.9"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::TowardZero); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.8"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.7"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.3"); + + written = __llvm_libc::sprintf(buff, "%.2g", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.8"); + } + + // Flag Tests. + written = __llvm_libc::sprintf(buff, "%+g", 1.0); + ASSERT_STREQ_LEN(written, buff, "+1"); + + written = __llvm_libc::sprintf(buff, "%+g", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1"); + + written = __llvm_libc::sprintf(buff, "% g", 1.0); + ASSERT_STREQ_LEN(written, buff, " 1"); + + written = __llvm_libc::sprintf(buff, "% g", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1"); + + written = __llvm_libc::sprintf(buff, "%-15g", 1.5); + ASSERT_STREQ_LEN(written, buff, "1.5 "); + + written = __llvm_libc::sprintf(buff, "%#.g", 1.0); + ASSERT_STREQ_LEN(written, buff, "1."); + + written = __llvm_libc::sprintf(buff, "%#g", 1.0); + ASSERT_STREQ_LEN(written, buff, "1.00000"); + + written = __llvm_libc::sprintf(buff, "%#.0g", 1.5); + ASSERT_STREQ_LEN(written, buff, "2."); + + written = __llvm_libc::sprintf(buff, "%015g", 1.5); + ASSERT_STREQ_LEN(written, buff, "0000000000001.5"); + + written = __llvm_libc::sprintf(buff, "%015g", -1.5); + ASSERT_STREQ_LEN(written, buff, "-000000000001.5"); + + written = __llvm_libc::sprintf(buff, "%+- #0g", 0.0); + ASSERT_STREQ_LEN(written, buff, "+0.00000"); + + // Combined Tests. + + written = __llvm_libc::sprintf(buff, "%10.3g", 9.99); + ASSERT_STREQ_LEN(written, buff, " 9.99"); + + written = __llvm_libc::sprintf(buff, "%10.2g", 9.99); + ASSERT_STREQ_LEN(written, buff, " 10"); + + written = __llvm_libc::sprintf(buff, "%10.1g", 9.99); + ASSERT_STREQ_LEN(written, buff, " 1e+01"); + + written = __llvm_libc::sprintf(buff, "%-10.3g", 9.99); + ASSERT_STREQ_LEN(written, buff, "9.99 "); + + written = __llvm_libc::sprintf(buff, "%-10.2g", 9.99); + ASSERT_STREQ_LEN(written, buff, "10 "); + + written = __llvm_libc::sprintf(buff, "%-10.1g", 9.99); + ASSERT_STREQ_LEN(written, buff, "1e+01 "); + + written = __llvm_libc::sprintf(buff, "%-10.1g", 1.0e-50); + ASSERT_STREQ_LEN(written, buff, "1e-50 "); + + written = __llvm_libc::sprintf(buff, "%30g", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, " 1.23457e+18"); + + written = __llvm_libc::sprintf(buff, "%-30g", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, "1.23457e+18 "); + + written = __llvm_libc::sprintf(buff, "%25.15g", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 9999999999999.99"); + + written = __llvm_libc::sprintf(buff, "%25.14g", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 10000000000000"); + + written = __llvm_libc::sprintf(buff, "%25.13g", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 1e+13"); + + written = __llvm_libc::sprintf(buff, "%#12.3g %-12.3g", 0.1, 256.0); + ASSERT_STREQ_LEN(written, buff, " 0.100 256 "); + + written = __llvm_libc::sprintf(buff, "%+-#12.3g % 012.3g", 0.1256, 1256.0); + ASSERT_STREQ_LEN(written, buff, "+0.126 0001.26e+03"); +} + #endif // LLVM_LIBC_PRINTF_DISABLE_FLOAT #ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT -- 2.7.4