[libc-commits] [libc] 5112651 - [libc] add exponent format to printf
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Dec 22 10:21:05 PST 2022
Author: Michael Jones
Date: 2022-12-22T10:20:59-08:00
New Revision: 51126518261a061624110b013d6cc0a414488f5b
URL: https://github.com/llvm/llvm-project/commit/51126518261a061624110b013d6cc0a414488f5b
DIFF: https://github.com/llvm/llvm-project/commit/51126518261a061624110b013d6cc0a414488f5b.diff
LOG: [libc] add exponent format to printf
Add support for the %e/E conversion in printf, as well as unit tests. It
does not yet support long doubles.
Reviewed By: sivachandra
Differential Revision: https://reviews.llvm.org/D140042
Added:
Modified:
libc/src/__support/float_to_string.h
libc/src/stdio/printf_core/converter.cpp
libc/src/stdio/printf_core/float_dec_converter.h
libc/test/src/stdio/sprintf_test.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index 966c6dff4a0ba..874093505c99f 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -310,6 +310,15 @@ class FloatToString {
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
index 458d86b00d1d4..2ceee7a56372c 100644
--- a/libc/src/stdio/printf_core/converter.cpp
+++ b/libc/src/stdio/printf_core/converter.cpp
@@ -46,9 +46,9 @@ int convert(Writer *writer, const FormatSection &to_conv) {
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
index c0af675ed44b8..9c7d3ad193562 100644
--- 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 @@ class PaddingWriter {
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 @@ class FloatWriter {
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 @@ class FloatWriter {
// 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 @@ class FloatWriter {
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 @@ class FloatWriter {
return 0;
}
+ cpp::string_view exp_str(int exponent, cpp::span<char> 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<long double>::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 @@ class FloatWriter {
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<intmax_t>()];
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 @@ class FloatWriter {
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 @@ class FloatWriter {
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<intmax_t>()];
+ 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<intmax_t>()];
+ 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<intmax_t>()];
+ 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 @@ int inline convert_float_decimal_typed(Writer *writer,
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 @@ int inline convert_float_decimal_typed(Writer *writer,
return WRITE_OK;
}
+template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+int inline convert_float_dec_exp_typed(Writer *writer,
+ const FormatSection &to_conv,
+ fputil::FPBits<T> float_bits) {
+ // signed because later we use -MANT_WIDTH
+ constexpr int32_t MANT_WIDTH = fputil::MantissaWidth<T>::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<T> float_converter(static_cast<T>(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<intmax_t>()];
+ 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<intmax_t>()];
+ 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<long double>::UIntType float_raw = to_conv.conv_val_raw;
@@ -474,6 +812,26 @@ int inline convert_float_decimal(Writer *writer, const FormatSection &to_conv) {
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<long double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<long double> float_bits(float_raw);
+ if (!float_bits.is_inf_or_nan()) {
+ return convert_float_dec_exp_typed<long double>(writer, to_conv,
+ float_bits);
+ }
+ } else {
+ fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double> float_bits(float_raw);
+ if (!float_bits.is_inf_or_nan()) {
+ return convert_float_dec_exp_typed<double>(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 73bad738b03e3..552cb70819368 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -1439,6 +1439,593 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
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<double>::inf().get_val();
+ double nan = __llvm_libc::fputil::FPBits<double>::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
More information about the libc-commits
mailing list