diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -310,6 +310,15 @@ return 0; } } + + constexpr BlockInt get_block(int block_index) { + if (block_index >= 0) { + return get_positive_block(block_index); + } else { + return get_negative_block(-1 - block_index); + } + } + constexpr size_t get_positive_blocks() { if (exponent >= -MANT_WIDTH) { const uint32_t idx = diff --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp --- a/libc/src/stdio/printf_core/converter.cpp +++ b/libc/src/stdio/printf_core/converter.cpp @@ -46,9 +46,9 @@ case 'f': case 'F': return convert_float_decimal(writer, to_conv); - // case 'e': - // case 'E': - // return convert_float_dec_exp(writer, to_conv); + case 'e': + case 'E': + return convert_float_dec_exp(writer, to_conv); case 'a': case 'A': return convert_float_hex_exp(writer, to_conv); diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/string_view.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/FloatProperties.h" #include "src/__support/UInt.h" #include "src/__support/UInt128.h" #include "src/__support/float_to_string.h" @@ -106,16 +107,16 @@ output when necessary. */ class FloatWriter { - char block_buffer[BLOCK_SIZE]; - size_t buffered_digits = 0; - bool has_written = false; - size_t max_block_count = 0; - size_t total_digits = 0; - size_t digits_before_decimal = 0; - size_t total_digits_written = 0; - bool has_decimal_point; - Writer *writer; - PaddingWriter padding_writer; + char block_buffer[BLOCK_SIZE]; // The buffer that holds a block. + size_t buffered_digits = 0; // The number of digits held in the buffer. + bool has_written = false; // True once any digits have been output. + size_t max_block_count = 0; // The # of blocks of all 9s currently buffered. + size_t total_digits = 0; // The number of digits that will be output. + size_t digits_before_decimal = 0; // The # of digits to write before the '.' + size_t total_digits_written = 0; // The # of digits that have been output. + bool has_decimal_point; // True if the number has a decimal point. + Writer *writer; // Writes to the final output. + PaddingWriter padding_writer; // Handles prefixes/padding, uses total_digits. int flush_buffer() { // Write the most recent buffered block, and mark has_written @@ -125,6 +126,31 @@ padding_writer.write_left_padding(writer, total_digits)); } + // if the decimal point is the next character, or is in the range covered + // by the buffered block, write the appropriate digits and the decimal + // point. + if (total_digits_written < digits_before_decimal && + total_digits_written + buffered_digits >= digits_before_decimal && + has_decimal_point) { + size_t digits_to_write = digits_before_decimal - total_digits_written; + if (digits_to_write > 0) { + // Write the digits before the decimal point. + RET_IF_RESULT_NEGATIVE(writer->write({block_buffer, digits_to_write})); + } + RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); + if (buffered_digits - digits_to_write > 0) { + // Write the digits after the decimal point. + RET_IF_RESULT_NEGATIVE( + writer->write({block_buffer + digits_to_write, + (buffered_digits - digits_to_write)})); + } + // add 1 for the decimal point + total_digits_written += buffered_digits + 1; + // Mark the buffer as empty. + buffered_digits = 0; + } + + // Clear the buffered digits. if (buffered_digits > 0) { RET_IF_RESULT_NEGATIVE(writer->write({block_buffer, buffered_digits})); total_digits_written += buffered_digits; @@ -133,7 +159,7 @@ // if the decimal point is the next character, or is in the range covered // by the max blocks, write the appropriate digits and the decimal point. - if (total_digits_written <= digits_before_decimal && + if (total_digits_written < digits_before_decimal && total_digits_written + BLOCK_SIZE * max_block_count >= digits_before_decimal && has_decimal_point) { @@ -142,9 +168,9 @@ RET_IF_RESULT_NEGATIVE(writer->write('9', digits_to_write)); } RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); - if (digits_to_write - (BLOCK_SIZE * max_block_count) > 0) { + if ((BLOCK_SIZE * max_block_count) - digits_to_write > 0) { RET_IF_RESULT_NEGATIVE(writer->write( - '9', digits_to_write - (BLOCK_SIZE * max_block_count))); + '9', (BLOCK_SIZE * max_block_count) - digits_to_write)); } // add 1 for the decimal point total_digits_written += BLOCK_SIZE * max_block_count + 1; @@ -161,6 +187,40 @@ return 0; } + cpp::string_view exp_str(int exponent, cpp::span exp_buffer) { + + // -exponent will never overflow because all long double types we support + // have at most 15 bits of mantissa and the C standard defines an int as + // being at least 16 bits. + static_assert(fputil::FloatProperties::EXPONENT_WIDTH < + (sizeof(int) * 8)); + + int positive_exponent = exponent < 0 ? -exponent : exponent; + char exp_sign = exponent < 0 ? '-' : '+'; + auto const int_to_str = + *IntegerToString::dec(positive_exponent, exp_buffer); + + // IntegerToString writes the digits from right to left so there will be + // space to the left of int_to_str. + size_t digits_in_exp = int_to_str.size(); + size_t index = exp_buffer.size() - digits_in_exp - 1; + + // Ensure that at least two digits were written. IntegerToString always + // writes at least 1 digit (it writes "0" when the input number is 0). + if (digits_in_exp < 2) { + exp_buffer[index] = '0'; + --index; + } + + // Since the exp_buffer has to be sized to handle an intmax_t, it has space + // for a sign. In this case we're handling the sign on our own since we also + // want plus signs for positive numbers. + exp_buffer[index] = exp_sign; + + return cpp::string_view(exp_buffer.data() + index, + exp_buffer.size() - index); + } + public: FloatWriter(Writer *init_writer, bool init_has_decimal_point, const PaddingWriter &init_padding_writer) @@ -172,20 +232,25 @@ digits_before_decimal = init_digits_before_decimal; } - void write_first_block(BlockInt block) { + void write_first_block(BlockInt block, bool exp_format = false) { char buf[IntegerToString::dec_bufsize()]; auto const int_to_str = *IntegerToString::dec(block, buf); - size_t digits_written = int_to_str.size(); + size_t digits_buffered = int_to_str.size(); // Block Buffer is guaranteed to not overflow since block cannot have more // than BLOCK_SIZE digits. // TODO: Replace with memcpy - for (size_t count = 0; count < digits_written; ++count) { + for (size_t count = 0; count < digits_buffered; ++count) { block_buffer[count] = int_to_str[count]; } - total_digits_written = 0; - buffered_digits = digits_written; - total_digits += digits_written; - digits_before_decimal += digits_written; + buffered_digits = digits_buffered; + + // In the exponent format (%e) we know how many digits will be written even + // before calculating any blocks, whereas the decimal format (%f) has to + // write all of the blocks that would come before the decimal place. + if (!exp_format) { + total_digits += digits_buffered; + digits_before_decimal += digits_buffered; + } } int write_middle_block(BlockInt block) { @@ -260,7 +325,9 @@ if (has_carry /* && !has_written */) { ++total_digits; ++digits_before_decimal; - // TODO: Handle prefixes here + // 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 + // can't be flushed. RET_IF_RESULT_NEGATIVE( padding_writer.write_left_padding(writer, total_digits)); // Now we know we need to print a leading 1, zeroes up to the decimal @@ -292,13 +359,124 @@ return 0; } - int write_last_block_exp(uint32_t block, size_t block_digits, int exponent) { - // TODO - // This should be almost identical to the above, except in the case of - // rounding all digits up. Instead of adding an extra digit in front of the - // decimal point, we want to add 1 to the exponent. - // Also we need to write the exponent, but that's pretty simple. - return -1; + int write_last_block_exp(uint32_t block, size_t block_digits, + RoundDirection round, int exponent, char exp_char) { + char end_buff[BLOCK_SIZE]; + + { + char buf[IntegerToString::dec_bufsize()]; + auto const int_to_str = + *IntegerToString::dec(block + (MAX_BLOCK + 1), buf); + + // copy the last block_digits characters into the start of end_buff. + // TODO: Replace with memcpy + for (int count = block_digits - 1; count >= 0; --count) { + end_buff[count] = int_to_str[count + 1 + (BLOCK_SIZE - block_digits)]; + } + } + + char low_digit; + if (block_digits > 0) { + low_digit = end_buff[block_digits - 1]; + } else if (max_block_count > 0) { + low_digit = '9'; + } else { + low_digit = block_buffer[buffered_digits - 1]; + } + + // Round up + if (round == RoundDirection::Up || + (round == RoundDirection::Even && low_digit % 2 != 0)) { + bool has_carry = true; + // handle the low block that we're adding + for (int count = block_digits - 1; count >= 0 && has_carry; --count) { + if (end_buff[count] == '9') { + end_buff[count] = '0'; + } else { + end_buff[count] += 1; + has_carry = false; + } + } + // handle the high block that's buffered + for (int count = buffered_digits - 1; count >= 0 && has_carry; --count) { + if (block_buffer[count] == '9') { + block_buffer[count] = '0'; + } else { + block_buffer[count] += 1; + has_carry = false; + } + } + + // has_carry should only be true here if every previous digit is 9, which + // implies that the number has never been written. + if (has_carry /* && !has_written */) { + // Since this is exponential notation, we don't write any more digits + // but we do increment the exponent. + ++exponent; + + char buf[IntegerToString::dec_bufsize()]; + auto const int_to_str = exp_str(exponent, buf); + + // TODO: also change this to calculate the width of the number more + // efficiently. + size_t exponent_width = int_to_str.size(); + size_t number_digits = + buffered_digits + (max_block_count * BLOCK_SIZE) + block_digits; + + // 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; + + // 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 + // can't be flushed. + RET_IF_RESULT_NEGATIVE( + padding_writer.write_left_padding(writer, total_digits)); + // Now we know we need to print a leading 1, the decimal point, and then + // zeroes after it. + RET_IF_RESULT_NEGATIVE(writer->write('1')); + // digits_before_decimal - 1 to account for the leading '1' + if (has_decimal_point) { + RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); + // This is just the length of the number, not including the decimal + // point, or exponent. + + if (number_digits > 1) { + RET_IF_RESULT_NEGATIVE(writer->write('0', number_digits - 1)); + } + } + RET_IF_RESULT_NEGATIVE(writer->write(exp_char)); + RET_IF_RESULT_NEGATIVE(writer->write(int_to_str)); + + total_digits_written = total_digits; + return WRITE_OK; + } + } + // Either we intend to round down, or the rounding up is complete. Flush the + // buffers. + + RET_IF_RESULT_NEGATIVE(flush_buffer()); + + // And then write the final block. It's written via the buffer so that if + // this is also the first block, the decimal point will be placed correctly. + + // TODO: Replace with memcpy + for (size_t count = 0; count < block_digits; ++count) { + block_buffer[count] = end_buff[count]; + } + buffered_digits = block_digits; + RET_IF_RESULT_NEGATIVE(flush_buffer()); + + char buf[IntegerToString::dec_bufsize()]; + auto const int_to_str = exp_str(exponent, buf); + + RET_IF_RESULT_NEGATIVE(writer->write(exp_char)); + RET_IF_RESULT_NEGATIVE(writer->write(int_to_str)); + + total_digits_written = total_digits; + + return WRITE_OK; } int write_zeroes(uint32_t num_zeroes) { @@ -333,7 +511,7 @@ sign_char = ' '; // If to_conv doesn't specify a precision, the precision defaults to 6. - size_t precision = to_conv.precision < 0 ? 6 : to_conv.precision; + const size_t precision = to_conv.precision < 0 ? 6 : to_conv.precision; bool has_decimal_point = (precision > 0) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0); @@ -456,6 +634,166 @@ return WRITE_OK; } +template , int> = 0> +int inline convert_float_dec_exp_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(); + + const char a = (to_conv.conv_name & 32) | 'A'; + + char sign_char = 0; + + if (is_negative) + sign_char = '-'; + else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) + sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == + FormatFlags::SPACE_PREFIX) + sign_char = ' '; + + // If to_conv doesn't specify a precision, the precision defaults to 6. + const size_t precision = to_conv.precision < 0 ? 6 : to_conv.precision; + bool has_decimal_point = + (precision > 0) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0); + + PaddingWriter padding_writer(to_conv, sign_char); + FloatWriter float_writer(writer, has_decimal_point, padding_writer); + FloatToString float_converter(static_cast(float_bits)); + + size_t digits_written = 0; + int final_exponent = 0; + + // 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. The first block is just 0. + if (mantissa != 0) { + // This loop finds the first block. + while (digits == 0) { + --cur_block; + digits = float_converter.get_block(cur_block); + } + } else { + cur_block = 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); + size_t block_width = int_to_str.size(); + + final_exponent = (cur_block * BLOCK_SIZE) + (block_width - 1); + int positive_exponent = final_exponent < 0 ? -final_exponent : final_exponent; + + int_to_str = *IntegerToString::dec(positive_exponent, buf); + size_t exponent_width = int_to_str.size(); + + // Calculate the total number of digits in the number. + // 1 - the digit before the decimal point + // 1 - the decimal point (optional) + // precision - the number of digits after the decimal point + // 1 - the 'e' at the start of the exponent + // 1 - the sign at the start of the exponent + // max(2, exp width) - the digits of the exponent, min 2. + + float_writer.init(1 + (has_decimal_point ? 1 : 0) + precision + 2 + + (exponent_width < 2 ? 2 : exponent_width), + 1); + + // If this block is not the last block + if (block_width <= precision + 1) { + float_writer.write_first_block(digits, true); + digits_written += block_width; + --cur_block; + } + + // For each middle block. + for (; digits_written + BLOCK_SIZE < precision + 1; --cur_block) { + digits = float_converter.get_block(cur_block); + + RET_IF_RESULT_NEGATIVE(float_writer.write_middle_block(digits)); + digits_written += BLOCK_SIZE; + } + + digits = float_converter.get_block(cur_block); + + size_t last_block_size = BLOCK_SIZE; + + // if the last block is also the first block, then ignore leading zeroes. + if (digits_written == 0) { + // TODO: Find a better way to calculate the number of digits in a block. + char buf[IntegerToString::dec_bufsize()]; + auto int_to_str = *IntegerToString::dec(digits, buf); + last_block_size = int_to_str.size(); + } + + // This is the last block. + const uint32_t maximum = precision + 1 - digits_written; + uint32_t lastDigit = 0; + for (uint32_t k = 0; k < last_block_size - maximum; ++k) { + lastDigit = 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; + const bool trailingZeros = + requiredTwos <= 0 || + (requiredTwos < 60 && + multiple_of_power_of_2(float_bits.get_explicit_mantissa(), + (uint32_t)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; + } else { + round = trailingZeros ? RoundDirection::Even : RoundDirection::Up; + } + break; + case FE_DOWNWARD: + if (is_negative && (!trailingZeros || lastDigit > 0)) { + round = RoundDirection::Up; + } else { + round = RoundDirection::Down; + } + break; + case FE_UPWARD: + if (!is_negative && (!trailingZeros || lastDigit > 0)) { + round = RoundDirection::Up; + } else { + round = RoundDirection::Down; + } + round = is_negative ? RoundDirection::Down : RoundDirection::Up; + break; + case FE_TOWARDZERO: + round = RoundDirection::Down; + break; + } + RET_IF_RESULT_NEGATIVE(float_writer.write_last_block_exp( + digits, maximum, round, final_exponent, a + 'E' - 'A')); + + RET_IF_RESULT_NEGATIVE(float_writer.right_pad()); + return WRITE_OK; +} + int inline convert_float_decimal(Writer *writer, const FormatSection &to_conv) { if (to_conv.length_modifier == LengthModifier::L) { fputil::FPBits::UIntType float_raw = to_conv.conv_val_raw; @@ -474,6 +812,26 @@ return convert_inf_nan(writer, to_conv); } + +int inline convert_float_dec_exp(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_exp_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_exp_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 --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -1439,6 +1439,593 @@ written = __llvm_libc::sprintf(buff, "%+-#12.3f % 012.3f", 0.1256, 1256.0); ASSERT_STREQ_LEN(written, buff, "+0.126 0001256.000"); } + +TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) { + __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, "%e", 1.0); + ASSERT_STREQ_LEN(written, buff, "1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%E", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1.000000E+00"); + + written = __llvm_libc::sprintf(buff, "%e", -1.234567); + ASSERT_STREQ_LEN(written, buff, "-1.234567e+00"); + + written = __llvm_libc::sprintf(buff, "%e", 0.0); + ASSERT_STREQ_LEN(written, buff, "0.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%e", 1.5); + ASSERT_STREQ_LEN(written, buff, "1.500000e+00"); + + written = __llvm_libc::sprintf(buff, "%e", 1e300); + ASSERT_STREQ_LEN(written, buff, "1.000000e+300"); + + written = __llvm_libc::sprintf(buff, "%e", 0.1); + ASSERT_STREQ_LEN(written, buff, "1.000000e-01"); + + written = __llvm_libc::sprintf(buff, "%e", 0.001); + ASSERT_STREQ_LEN(written, buff, "1.000000e-03"); + + written = __llvm_libc::sprintf(buff, "%e", 0.00001); + ASSERT_STREQ_LEN(written, buff, "1.000000e-05"); + + written = __llvm_libc::sprintf(buff, "%e", 0.0000001); + ASSERT_STREQ_LEN(written, buff, "1.000000e-07"); + + written = __llvm_libc::sprintf(buff, "%e", 0.000000001); + ASSERT_STREQ_LEN(written, buff, "1.000000e-09"); + + written = __llvm_libc::sprintf(buff, "%e", 1.0e-20); + ASSERT_STREQ_LEN(written, buff, "1.000000e-20"); + + written = __llvm_libc::sprintf(buff, "%e", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, "1.234568e+18"); + + written = __llvm_libc::sprintf(buff, "%e", 9999999000000.00); + ASSERT_STREQ_LEN(written, buff, "9.999999e+12"); + + // Simple Subnormal Tests. + + written = __llvm_libc::sprintf(buff, "%e", 0x1.0p-1027); + ASSERT_STREQ_LEN(written, buff, "6.953356e-310"); + + written = __llvm_libc::sprintf(buff, "%e", 0x1.0p-1074); + ASSERT_STREQ_LEN(written, buff, "4.940656e-324"); + + // Inf/Nan Tests. + + written = __llvm_libc::sprintf(buff, "%e", inf); + ASSERT_STREQ_LEN(written, buff, "inf"); + + written = __llvm_libc::sprintf(buff, "%E", -inf); + ASSERT_STREQ_LEN(written, buff, "-INF"); + + written = __llvm_libc::sprintf(buff, "%e", nan); + ASSERT_STREQ_LEN(written, buff, "nan"); + + written = __llvm_libc::sprintf(buff, "%E", -nan); + ASSERT_STREQ_LEN(written, buff, "-NAN"); + + // Length Modifier Tests. + + // TODO: Fix long doubles (needs bigger table or alternate algorithm.) + // Currently the table values are generated, which is very slow. + /* + 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, "%15e", 1.0); + ASSERT_STREQ_LEN(written, buff, " 1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%15e", -1.0); + ASSERT_STREQ_LEN(written, buff, " -1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%15e", 1.0e5); + ASSERT_STREQ_LEN(written, buff, " 1.000000e+05"); + + written = __llvm_libc::sprintf(buff, "%15e", -1.0e5); + ASSERT_STREQ_LEN(written, buff, " -1.000000e+05"); + + written = __llvm_libc::sprintf(buff, "%10e", 1.0e-5); + ASSERT_STREQ_LEN(written, buff, "1.000000e-05"); + + // Precision Tests. + + written = __llvm_libc::sprintf(buff, "%.1e", 1.0); + ASSERT_STREQ_LEN(written, buff, "1.0e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 0.0); + ASSERT_STREQ_LEN(written, buff, "0.0e+00"); + + written = __llvm_libc::sprintf(buff, "%.0e", 0.0); + ASSERT_STREQ_LEN(written, buff, "0e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 0.1); + ASSERT_STREQ_LEN(written, buff, "1.0e-01"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.09); + ASSERT_STREQ_LEN(written, buff, "1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.04); + ASSERT_STREQ_LEN(written, buff, "1.0e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.19); + ASSERT_STREQ_LEN(written, buff, "1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.99); + ASSERT_STREQ_LEN(written, buff, "2.0e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 9.99); + ASSERT_STREQ_LEN(written, buff, "1.0e+01"); + + written = __llvm_libc::sprintf(buff, "%.2e", 99.9); + ASSERT_STREQ_LEN(written, buff, "9.99e+01"); + + written = __llvm_libc::sprintf(buff, "%.1e", 99.9); + ASSERT_STREQ_LEN(written, buff, "1.0e+02"); + + written = __llvm_libc::sprintf(buff, "%.5e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.25000e+00"); + + written = __llvm_libc::sprintf(buff, "%.0e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1e+00"); + + written = __llvm_libc::sprintf(buff, "%.0e", 1.75); + ASSERT_STREQ_LEN(written, buff, "2e+00"); + + written = __llvm_libc::sprintf(buff, "%.20e", 1.234e-10); + ASSERT_STREQ_LEN(written, buff, "1.23400000000000008140e-10"); + + written = __llvm_libc::sprintf(buff, "%.2e", -9.99); + ASSERT_STREQ_LEN(written, buff, "-9.99e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -9.99); + ASSERT_STREQ_LEN(written, buff, "-1.0e+01"); + + written = __llvm_libc::sprintf(buff, "%.5e", 0.0); + ASSERT_STREQ_LEN(written, buff, "0.00000e+00"); + + written = __llvm_libc::sprintf(buff, "%.5e", 1.008); + ASSERT_STREQ_LEN(written, buff, "1.00800e+00"); + + written = __llvm_libc::sprintf(buff, "%.5e", 1.008e3); + ASSERT_STREQ_LEN(written, buff, "1.00800e+03"); + + // Subnormal Precision Tests + + written = __llvm_libc::sprintf(buff, "%.310e", 0x1.0p-1022); + ASSERT_STREQ_LEN( + written, buff, + "2." + "225073858507201383090232717332404064219215980462331830553327416887204434" + "813918195854283159012511020564067339731035811005152434161553460108856012" + "385377718821130777993532002330479610147442583636071921565046942503734208" + "375250806650616658158948720491179968591639648500635908770118304874799780" + "8877537499494515804516e-308"); + + written = __llvm_libc::sprintf(buff, "%.30e", 0x1.0p-1022); + ASSERT_STREQ_LEN(written, buff, "2.225073858507201383090232717332e-308"); + + written = __llvm_libc::sprintf(buff, "%.310e", 0x1.0p-1023); + ASSERT_STREQ_LEN( + written, buff, + "1." + "112536929253600691545116358666202032109607990231165915276663708443602217" + "406959097927141579506255510282033669865517905502576217080776730054428006" + "192688859410565388996766001165239805073721291818035960782523471251867104" + "187625403325308329079474360245589984295819824250317954385059152437399890" + "4438768749747257902258e-308"); + + written = __llvm_libc::sprintf(buff, "%.6e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "9.999990e-310"); + + written = __llvm_libc::sprintf(buff, "%.5e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "9.99999e-310"); + + written = __llvm_libc::sprintf(buff, "%.4e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1.0000e-309"); + + written = __llvm_libc::sprintf(buff, "%.3e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1.000e-309"); + + written = __llvm_libc::sprintf(buff, "%.2e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1.00e-309"); + + written = __llvm_libc::sprintf(buff, "%.1e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1.0e-309"); + + written = __llvm_libc::sprintf(buff, "%.0e", 9.99999e-310); + ASSERT_STREQ_LEN(written, buff, "1e-309"); + + written = __llvm_libc::sprintf(buff, "%.10e", 0x1.0p-1074); + ASSERT_STREQ_LEN(written, buff, "4.9406564584e-324"); + + /* + 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, "%.1e", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.4e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.9e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.4e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.9e+00"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Upward); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.4e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.9e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.8e+00"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::Downward); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.4e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.9e+00"); + } + + { + __llvm_libc::testutils::ForceRoundingMode r( + __llvm_libc::testutils::RoundingMode::TowardZero); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.75); + ASSERT_STREQ_LEN(written, buff, "1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.25); + ASSERT_STREQ_LEN(written, buff, "1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.125); + ASSERT_STREQ_LEN(written, buff, "1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.625); + ASSERT_STREQ_LEN(written, buff, "1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.375); + ASSERT_STREQ_LEN(written, buff, "1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", 1.875); + ASSERT_STREQ_LEN(written, buff, "1.8e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.75); + ASSERT_STREQ_LEN(written, buff, "-1.7e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.25); + ASSERT_STREQ_LEN(written, buff, "-1.2e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.125); + ASSERT_STREQ_LEN(written, buff, "-1.1e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.625); + ASSERT_STREQ_LEN(written, buff, "-1.6e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.375); + ASSERT_STREQ_LEN(written, buff, "-1.3e+00"); + + written = __llvm_libc::sprintf(buff, "%.1e", -1.875); + ASSERT_STREQ_LEN(written, buff, "-1.8e+00"); + } + + // Flag Tests. + written = __llvm_libc::sprintf(buff, "%+e", 1.0); + ASSERT_STREQ_LEN(written, buff, "+1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%+e", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "% e", 1.0); + ASSERT_STREQ_LEN(written, buff, " 1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "% e", -1.0); + ASSERT_STREQ_LEN(written, buff, "-1.000000e+00"); + + written = __llvm_libc::sprintf(buff, "%-15e", 1.5); + ASSERT_STREQ_LEN(written, buff, "1.500000e+00 "); + + written = __llvm_libc::sprintf(buff, "%#.e", 1.0); + ASSERT_STREQ_LEN(written, buff, "1.e+00"); + + written = __llvm_libc::sprintf(buff, "%#.0e", 1.5); + ASSERT_STREQ_LEN(written, buff, "2.e+00"); + + written = __llvm_libc::sprintf(buff, "%015e", 1.5); + ASSERT_STREQ_LEN(written, buff, "0001.500000e+00"); + + written = __llvm_libc::sprintf(buff, "%015e", -1.5); + ASSERT_STREQ_LEN(written, buff, "-001.500000e+00"); + + written = __llvm_libc::sprintf(buff, "%+- #0e", 0.0); + ASSERT_STREQ_LEN(written, buff, "+0.000000e+00"); + + // Combined Tests. + + written = __llvm_libc::sprintf(buff, "%10.2e", 9.99); + ASSERT_STREQ_LEN(written, buff, " 9.99e+00"); + + written = __llvm_libc::sprintf(buff, "%10.1e", 9.99); + ASSERT_STREQ_LEN(written, buff, " 1.0e+01"); + + written = __llvm_libc::sprintf(buff, "%-10.2e", 9.99); + ASSERT_STREQ_LEN(written, buff, "9.99e+00 "); + + written = __llvm_libc::sprintf(buff, "%-10.1e", 9.99); + ASSERT_STREQ_LEN(written, buff, "1.0e+01 "); + + written = __llvm_libc::sprintf(buff, "%-10.1e", 1.0e-50); + ASSERT_STREQ_LEN(written, buff, "1.0e-50 "); + + written = __llvm_libc::sprintf(buff, "%30e", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, " 1.234568e+18"); + + written = __llvm_libc::sprintf(buff, "%-30e", 1234567890123456789.0); + ASSERT_STREQ_LEN(written, buff, "1.234568e+18 "); + + written = __llvm_libc::sprintf(buff, "%25.14e", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 9.99999999999999e+12"); + + written = __llvm_libc::sprintf(buff, "%25.13e", 9999999999999.99); + ASSERT_STREQ_LEN(written, buff, " 1.0000000000000e+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 "); + + written = __llvm_libc::sprintf(buff, "%+-#12.3e % 012.3e", 0.1256, 1256.0); + ASSERT_STREQ_LEN(written, buff, "+1.256e-01 001.256e+03"); +} + #endif // LLVM_LIBC_PRINTF_DISABLE_FLOAT #ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT