Skip to content

Commit 3fb63c2

Browse files
[libc] simplify printf float writing
The two decimal float printing styles are similar, but different in how they end. For simplicity of writing I initially gave them different "write_last_block" functions. This patch unifies them into one function. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D158036
1 parent 2a904f4 commit 3fb63c2

File tree

1 file changed

+77
-139
lines changed

1 file changed

+77
-139
lines changed

libc/src/stdio/printf_core/float_dec_converter.h

Lines changed: 77 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -299,100 +299,11 @@ class FloatWriter {
299299
return 0;
300300
}
301301

302-
int write_last_block_dec(BlockInt block, size_t block_digits,
303-
RoundDirection round) {
304-
char end_buff[BLOCK_SIZE];
305-
306-
const DecimalString buf(block + (MAX_BLOCK + 1));
307-
const cpp::string_view int_to_str = buf.view();
308-
309-
// copy the last block_digits characters into the start of end_buff.
310-
// TODO: Replace with memcpy
311-
for (size_t count = 0; count < block_digits; ++count) {
312-
end_buff[count] = int_to_str[count + 1 + (BLOCK_SIZE - block_digits)];
313-
}
314-
315-
char low_digit = '0';
316-
if (block_digits > 0) {
317-
low_digit = end_buff[block_digits - 1];
318-
} else if (max_block_count > 0) {
319-
low_digit = '9';
320-
} else if (buffered_digits > 0) {
321-
low_digit = block_buffer[buffered_digits - 1];
322-
}
323-
324-
bool round_up_max_blocks = false;
325-
326-
// Round up
327-
if (round == RoundDirection::Up ||
328-
(round == RoundDirection::Even && low_digit % 2 != 0)) {
329-
bool has_carry = true;
330-
round_up_max_blocks = true; // if we're rounding up, we might need to
331-
// round up the max blocks that are buffered.
332-
// handle the low block that we're adding
333-
for (int count = static_cast<int>(block_digits) - 1;
334-
count >= 0 && has_carry; --count) {
335-
if (end_buff[count] == '9') {
336-
end_buff[count] = '0';
337-
} else {
338-
end_buff[count] += 1;
339-
has_carry = false;
340-
round_up_max_blocks = false; // If the low block isn't all nines, then
341-
// the max blocks aren't rounded up.
342-
}
343-
}
344-
// handle the high block that's buffered
345-
for (int count = static_cast<int>(buffered_digits) - 1;
346-
count >= 0 && has_carry; --count) {
347-
if (block_buffer[count] == '9') {
348-
block_buffer[count] = '0';
349-
} else {
350-
block_buffer[count] += 1;
351-
has_carry = false;
352-
}
353-
}
354-
355-
// has_carry should only be true here if every previous digit is 9, which
356-
// implies that the number has never been written.
357-
if (has_carry /* && !has_written */) {
358-
++total_digits;
359-
++digits_before_decimal;
360-
// Normally write_left_padding is called by flush_buffer but since we're
361-
// rounding up all of the digits, the ones in the buffer are wrong and
362-
// can't be flushed.
363-
RET_IF_RESULT_NEGATIVE(
364-
padding_writer.write_left_padding(writer, total_digits));
365-
// Now we know we need to print a leading 1, zeroes up to the decimal
366-
// point, the decimal point, and then finally digits after it.
367-
RET_IF_RESULT_NEGATIVE(writer->write('1'));
368-
// digits_before_decimal - 1 to account for the leading '1'
369-
RET_IF_RESULT_NEGATIVE(writer->write('0', digits_before_decimal - 1));
370-
if (has_decimal_point) {
371-
RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT));
372-
// add one to digits_before_decimal to account for the decimal point
373-
// itself.
374-
if (total_digits > digits_before_decimal + 1) {
375-
RET_IF_RESULT_NEGATIVE(
376-
writer->write('0', total_digits - (digits_before_decimal + 1)));
377-
}
378-
}
379-
total_digits_written = total_digits;
380-
return 0;
381-
}
382-
}
383-
// Either we intend to round down, or the rounding up is complete. Flush the
384-
// buffers.
385-
386-
RET_IF_RESULT_NEGATIVE(flush_buffer(round_up_max_blocks));
302+
int write_last_block(BlockInt block, size_t block_digits,
303+
RoundDirection round, int exponent = 0,
304+
char exp_char = '\0') {
305+
bool has_exp = (exp_char != '\0');
387306

388-
// And then write the final block.
389-
RET_IF_RESULT_NEGATIVE(writer->write({end_buff, block_digits}));
390-
total_digits_written += block_digits;
391-
return 0;
392-
}
393-
394-
int write_last_block_exp(uint32_t block, size_t block_digits,
395-
RoundDirection round, int exponent, char exp_char) {
396307
char end_buff[BLOCK_SIZE];
397308

398309
{
@@ -450,48 +361,74 @@ class FloatWriter {
450361
// has_carry should only be true here if every previous digit is 9, which
451362
// implies that the number has never been written.
452363
if (has_carry /* && !has_written */) {
453-
// Since this is exponential notation, we don't write any more digits
454-
// but we do increment the exponent.
455-
++exponent;
456-
457-
const ExponentString buf(exponent);
458-
const cpp::string_view int_to_str = buf.view();
459-
460-
// TODO: also change this to calculate the width of the number more
461-
// efficiently.
462-
size_t exponent_width = int_to_str.size();
463-
size_t number_digits =
464-
buffered_digits + (max_block_count * BLOCK_SIZE) + block_digits;
465-
466-
// Here we have to recalculate the total number of digits since the
467-
// exponent's width may have changed. We're only adding 1 to exponent
468-
// width since exp_str appends the sign.
469-
total_digits =
470-
(has_decimal_point ? 1 : 0) + number_digits + 1 + exponent_width;
471-
472-
// Normally write_left_padding is called by flush_buffer but since we're
473-
// rounding up all of the digits, the ones in the buffer are wrong and
474-
// can't be flushed.
475-
RET_IF_RESULT_NEGATIVE(
476-
padding_writer.write_left_padding(writer, total_digits));
477-
// Now we know we need to print a leading 1, the decimal point, and then
478-
// zeroes after it.
479-
RET_IF_RESULT_NEGATIVE(writer->write('1'));
480-
// digits_before_decimal - 1 to account for the leading '1'
481-
if (has_decimal_point) {
482-
RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT));
483-
// This is just the length of the number, not including the decimal
484-
// point, or exponent.
485-
486-
if (number_digits > 1) {
487-
RET_IF_RESULT_NEGATIVE(writer->write('0', number_digits - 1));
364+
if (has_exp) { // This is in %e style
365+
// Since this is exponential notation, we don't write any more digits
366+
// but we do increment the exponent.
367+
++exponent;
368+
369+
const ExponentString buf(exponent);
370+
const cpp::string_view int_to_str = buf.view();
371+
372+
// TODO: also change this to calculate the width of the number more
373+
// efficiently.
374+
size_t exponent_width = int_to_str.size();
375+
size_t number_digits =
376+
buffered_digits + (max_block_count * BLOCK_SIZE) + block_digits;
377+
378+
// Here we have to recalculate the total number of digits since the
379+
// exponent's width may have changed. We're only adding 1 to exponent
380+
// width since exp_str appends the sign.
381+
total_digits =
382+
(has_decimal_point ? 1 : 0) + number_digits + 1 + exponent_width;
383+
384+
// Normally write_left_padding is called by flush_buffer but since
385+
// we're rounding up all of the digits, the ones in the buffer are
386+
// wrong and can't be flushed.
387+
RET_IF_RESULT_NEGATIVE(
388+
padding_writer.write_left_padding(writer, total_digits));
389+
// Now we know we need to print a leading 1, the decimal point, and
390+
// then zeroes after it.
391+
RET_IF_RESULT_NEGATIVE(writer->write('1'));
392+
// digits_before_decimal - 1 to account for the leading '1'
393+
if (has_decimal_point) {
394+
RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT));
395+
// This is just the length of the number, not including the decimal
396+
// point, or exponent.
397+
398+
if (number_digits > 1) {
399+
RET_IF_RESULT_NEGATIVE(writer->write('0', number_digits - 1));
400+
}
488401
}
402+
RET_IF_RESULT_NEGATIVE(writer->write(exp_char));
403+
RET_IF_RESULT_NEGATIVE(writer->write(int_to_str));
404+
405+
total_digits_written = total_digits;
406+
return WRITE_OK;
407+
} else { // This is in %f style
408+
++total_digits;
409+
++digits_before_decimal;
410+
// Normally write_left_padding is called by flush_buffer but since
411+
// we're rounding up all of the digits, the ones in the buffer are
412+
// wrong and can't be flushed.
413+
RET_IF_RESULT_NEGATIVE(
414+
padding_writer.write_left_padding(writer, total_digits));
415+
// Now we know we need to print a leading 1, zeroes up to the decimal
416+
// point, the decimal point, and then finally digits after it.
417+
RET_IF_RESULT_NEGATIVE(writer->write('1'));
418+
// digits_before_decimal - 1 to account for the leading '1'
419+
RET_IF_RESULT_NEGATIVE(writer->write('0', digits_before_decimal - 1));
420+
if (has_decimal_point) {
421+
RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT));
422+
// add one to digits_before_decimal to account for the decimal point
423+
// itself.
424+
if (total_digits > digits_before_decimal + 1) {
425+
RET_IF_RESULT_NEGATIVE(writer->write(
426+
'0', total_digits - (digits_before_decimal + 1)));
427+
}
428+
}
429+
total_digits_written = total_digits;
430+
return WRITE_OK;
489431
}
490-
RET_IF_RESULT_NEGATIVE(writer->write(exp_char));
491-
RET_IF_RESULT_NEGATIVE(writer->write(int_to_str));
492-
493-
total_digits_written = total_digits;
494-
return WRITE_OK;
495432
}
496433
}
497434
// Either we intend to round down, or the rounding up is complete. Flush the
@@ -509,10 +446,11 @@ class FloatWriter {
509446
buffered_digits = block_digits;
510447
RET_IF_RESULT_NEGATIVE(flush_buffer());
511448

512-
RET_IF_RESULT_NEGATIVE(writer->write(exp_char));
513-
const ExponentString buf(exponent);
514-
RET_IF_RESULT_NEGATIVE(writer->write(buf.view()));
515-
449+
if (has_exp) {
450+
RET_IF_RESULT_NEGATIVE(writer->write(exp_char));
451+
const ExponentString buf(exponent);
452+
RET_IF_RESULT_NEGATIVE(writer->write(buf.view()));
453+
}
516454
total_digits_written = total_digits;
517455

518456
return WRITE_OK;
@@ -634,7 +572,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
634572
round = get_round_direction(last_digit, truncated, is_negative);
635573

636574
RET_IF_RESULT_NEGATIVE(
637-
float_writer.write_last_block_dec(digits, maximum, round));
575+
float_writer.write_last_block(digits, maximum, round));
638576
break;
639577
}
640578
}
@@ -800,7 +738,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
800738
}
801739
round = get_round_direction(last_digit, truncated, is_negative);
802740

803-
RET_IF_RESULT_NEGATIVE(float_writer.write_last_block_exp(
741+
RET_IF_RESULT_NEGATIVE(float_writer.write_last_block(
804742
digits, maximum, round, final_exponent, a + 'E' - 'A'));
805743

806744
RET_IF_RESULT_NEGATIVE(float_writer.right_pad());

0 commit comments

Comments
 (0)