@@ -406,19 +406,24 @@ class FloatWriter {
406
406
}
407
407
}
408
408
409
- char low_digit;
409
+ char low_digit = ' 0 ' ;
410
410
if (block_digits > 0 ) {
411
411
low_digit = end_buff[block_digits - 1 ];
412
412
} else if (max_block_count > 0 ) {
413
413
low_digit = ' 9' ;
414
- } else {
414
+ } else if (buffered_digits > 0 ) {
415
415
low_digit = block_buffer[buffered_digits - 1 ];
416
416
}
417
417
418
+ bool round_up_max_blocks = false ;
419
+
418
420
// Round up
419
421
if (round == RoundDirection::Up ||
420
422
(round == RoundDirection::Even && low_digit % 2 != 0 )) {
421
423
bool has_carry = true ;
424
+ round_up_max_blocks = true ; // if we're rounding up, we might need to
425
+ // round up the max blocks that are buffered.
426
+
422
427
// handle the low block that we're adding
423
428
for (int count = static_cast <int >(block_digits) - 1 ;
424
429
count >= 0 && has_carry; --count) {
@@ -427,6 +432,8 @@ class FloatWriter {
427
432
} else {
428
433
end_buff[count] += 1 ;
429
434
has_carry = false ;
435
+ round_up_max_blocks = false ; // If the low block isn't all nines, then
436
+ // the max blocks aren't rounded up.
430
437
}
431
438
}
432
439
// handle the high block that's buffered
@@ -490,7 +497,7 @@ class FloatWriter {
490
497
// Either we intend to round down, or the rounding up is complete. Flush the
491
498
// buffers.
492
499
493
- RET_IF_RESULT_NEGATIVE (flush_buffer ());
500
+ RET_IF_RESULT_NEGATIVE (flush_buffer (round_up_max_blocks ));
494
501
495
502
// And then write the final block. It's written via the buffer so that if
496
503
// this is also the first block, the decimal point will be placed correctly.
@@ -740,58 +747,59 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
740
747
last_block_size = IntegerToString<intmax_t >(digits).size ();
741
748
}
742
749
750
+ // This tracks if the number is truncated, that meaning that the digits after
751
+ // last_digit are non-zero.
752
+ bool truncated = false ;
753
+
743
754
// This is the last block.
744
755
const size_t maximum = precision + 1 - digits_written;
745
756
uint32_t last_digit = 0 ;
746
757
for (uint32_t k = 0 ; k < last_block_size - maximum; ++k) {
758
+ if (last_digit > 0 )
759
+ truncated = true ;
760
+
747
761
last_digit = digits % 10 ;
748
762
digits /= 10 ;
749
763
}
750
764
751
765
// If the last block we read doesn't have the digit after the end of what
752
766
// we'll print, then we need to read the next block to get that digit.
753
767
if (maximum == last_block_size) {
754
- BlockInt extra_block = float_converter.get_block (cur_block - 1 );
768
+ --cur_block;
769
+ BlockInt extra_block = float_converter.get_block (cur_block);
755
770
last_digit = extra_block / ((MAX_BLOCK / 10 ) + 1 );
771
+ if (extra_block % ((MAX_BLOCK / 10 ) + 1 ) > 0 ) {
772
+ truncated = true ;
773
+ }
756
774
}
757
775
758
776
RoundDirection round;
759
- // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer?
760
- const int32_t requiredTwos =
761
- -(exponent - MANT_WIDTH) - static_cast <int32_t >(precision) - 1 ;
762
- const bool trailingZeros =
763
- requiredTwos <= 0 ||
764
- (requiredTwos < 60 &&
765
- multiple_of_power_of_2 (float_bits.get_explicit_mantissa (),
766
- static_cast <uint32_t >(requiredTwos)));
767
- switch (fputil::quick_get_round ()) {
768
- case FE_TONEAREST:
769
- // Round to nearest, if it's exactly halfway then round to even.
770
- if (last_digit != 5 ) {
771
- round = last_digit > 5 ? RoundDirection::Up : RoundDirection::Down;
772
- } else {
773
- round = trailingZeros ? RoundDirection::Even : RoundDirection::Up;
774
- }
775
- break ;
776
- case FE_DOWNWARD:
777
- if (is_negative && (!trailingZeros || last_digit > 0 )) {
778
- round = RoundDirection::Up;
779
- } else {
780
- round = RoundDirection::Down;
777
+
778
+ // If we've already seen a truncated digit, then we don't need to check any
779
+ // more.
780
+ if (!truncated) {
781
+ // Check the blocks above the decimal point
782
+ if (cur_block >= 0 ) {
783
+ // Check every block until the decimal point for non-zero digits.
784
+ for (int cur_extra_block = cur_block - 1 ; cur_extra_block >= 0 ;
785
+ --cur_extra_block) {
786
+ BlockInt extra_block = float_converter.get_block (cur_extra_block);
787
+ if (extra_block > 0 ) {
788
+ truncated = true ;
789
+ break ;
790
+ }
791
+ }
781
792
}
782
- break ;
783
- case FE_UPWARD:
784
- if (!is_negative && (!trailingZeros || last_digit > 0 )) {
785
- round = RoundDirection::Up;
786
- } else {
787
- round = RoundDirection::Down ;
793
+ // If it's still not truncated and there are digits below the decimal point
794
+ if (!truncated && exponent - MANT_WIDTH < 0 ) {
795
+ // Use the formula from %f.
796
+ truncated =
797
+ ! zero_after_digits (exponent - MANT_WIDTH, precision - final_exponent,
798
+ float_bits. get_explicit_mantissa ()) ;
788
799
}
789
- round = is_negative ? RoundDirection::Down : RoundDirection::Up;
790
- break ;
791
- case FE_TOWARDZERO:
792
- round = RoundDirection::Down;
793
- break ;
794
800
}
801
+ round = get_round_direction (last_digit, truncated, is_negative);
802
+
795
803
RET_IF_RESULT_NEGATIVE (float_writer.write_last_block_exp (
796
804
digits, maximum, round, final_exponent, a + ' E' - ' A' ));
797
805
@@ -984,71 +992,93 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
984
992
}
985
993
}
986
994
995
+ bool truncated = false ;
996
+
987
997
// Find the digit after the lowest digit that we'll actually print to
988
998
// determine the rounding.
989
999
const uint32_t maximum =
990
1000
exp_precision + 1 - static_cast <uint32_t >(digits_checked);
991
1001
uint32_t last_digit = 0 ;
992
1002
for (uint32_t k = 0 ; k < last_block_size - maximum; ++k) {
1003
+ if (last_digit > 0 )
1004
+ truncated = true ;
1005
+
993
1006
last_digit = digits % 10 ;
994
1007
digits /= 10 ;
995
1008
}
996
1009
997
1010
// If the last block we read doesn't have the digit after the end of what
998
1011
// we'll print, then we need to read the next block to get that digit.
999
1012
if (maximum == last_block_size) {
1000
- BlockInt extra_block = float_converter.get_block (cur_block - 1 );
1013
+ --cur_block;
1014
+ BlockInt extra_block = float_converter.get_block (cur_block);
1001
1015
last_digit = extra_block / ((MAX_BLOCK / 10 ) + 1 );
1016
+
1017
+ if (extra_block % ((MAX_BLOCK / 10 ) + 1 ) > 0 )
1018
+ truncated = true ;
1002
1019
}
1003
1020
1004
1021
// TODO: unify this code across the three float conversions.
1005
1022
RoundDirection round;
1006
- // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer?
1007
- const int32_t requiredTwos =
1008
- -(exponent - MANT_WIDTH) - static_cast <int32_t >(exp_precision) - 1 ;
1009
- // TODO: rename this variable to remove confusion with trailing_zeroes
1010
- const bool trailingZeros =
1011
- requiredTwos <= 0 ||
1012
- (requiredTwos < 60 &&
1013
- multiple_of_power_of_2 (float_bits.get_explicit_mantissa (),
1014
- static_cast <uint32_t >(requiredTwos)));
1015
- switch (fputil::quick_get_round ()) {
1016
- case FE_TONEAREST:
1017
- // Round to nearest, if it's exactly halfway then round to even.
1018
- if (last_digit != 5 ) {
1019
- round = last_digit > 5 ? RoundDirection::Up : RoundDirection::Down;
1020
- } else {
1021
- round = trailingZeros ? RoundDirection::Even : RoundDirection::Up;
1022
- }
1023
- break ;
1024
- case FE_DOWNWARD:
1025
- if (is_negative && (!trailingZeros || last_digit > 0 )) {
1026
- round = RoundDirection::Up;
1027
- } else {
1028
- round = RoundDirection::Down;
1023
+
1024
+ // If we've already seen a truncated digit, then we don't need to check any
1025
+ // more.
1026
+ if (!truncated) {
1027
+ // Check the blocks above the decimal point
1028
+ if (cur_block >= 0 ) {
1029
+ // Check every block until the decimal point for non-zero digits.
1030
+ for (int cur_extra_block = cur_block - 1 ; cur_extra_block >= 0 ;
1031
+ --cur_extra_block) {
1032
+ BlockInt extra_block = float_converter.get_block (cur_extra_block);
1033
+ if (extra_block > 0 ) {
1034
+ truncated = true ;
1035
+ break ;
1036
+ }
1037
+ }
1029
1038
}
1030
- break ;
1031
- case FE_UPWARD:
1032
- if (!is_negative && (!trailingZeros || last_digit > 0 )) {
1033
- round = RoundDirection::Up;
1034
- } else {
1035
- round = RoundDirection::Down ;
1039
+ // If it's still not truncated and there are digits below the decimal point
1040
+ if (!truncated && exponent - MANT_WIDTH < 0 ) {
1041
+ // Use the formula from %f.
1042
+ truncated =
1043
+ ! zero_after_digits (exponent - MANT_WIDTH, exp_precision - base_10_exp,
1044
+ float_bits. get_explicit_mantissa ()) ;
1036
1045
}
1037
- round = is_negative ? RoundDirection::Down : RoundDirection::Up;
1038
- break ;
1039
- case FE_TOWARDZERO:
1040
- round = RoundDirection::Down;
1041
- break ;
1042
1046
}
1043
1047
1048
+ round = get_round_direction (last_digit, truncated, is_negative);
1049
+
1044
1050
bool round_up;
1045
1051
if (round == RoundDirection::Up) {
1046
1052
round_up = true ;
1047
1053
} else if (round == RoundDirection::Down) {
1048
1054
round_up = false ;
1049
1055
} else {
1050
- // RoundDirection is even, so check the extra digit.
1051
- uint32_t low_digit = digits % 10 ;
1056
+ // RoundDirection is even, so check the lowest digit that will be printed.
1057
+ uint32_t low_digit;
1058
+
1059
+ // maximum is the number of digits that will remain in digits after getting
1060
+ // last_digit. If it's greater than zero, we can just check the lowest digit
1061
+ // in digits.
1062
+ if (maximum > 0 ) {
1063
+ low_digit = digits % 10 ;
1064
+ } else {
1065
+ // Else if there are trailing nines, then the low digit is a nine, same
1066
+ // with zeroes.
1067
+ if (trailing_nines > 0 ) {
1068
+ low_digit = 9 ;
1069
+ } else if (trailing_zeroes > 0 ) {
1070
+ low_digit = 0 ;
1071
+ } else {
1072
+ // If there are no trailing zeroes or nines, then the round direction
1073
+ // doesn't actually matter here. Since this conversion passes off the
1074
+ // value to another one for final conversion, rounding only matters to
1075
+ // determine if the exponent is higher than expected (with an all nine
1076
+ // number) or to determine the trailing zeroes to trim. In this case
1077
+ // low_digit is set to 0, but it could be set to any number.
1078
+
1079
+ low_digit = 0 ;
1080
+ }
1081
+ }
1052
1082
round_up = (low_digit % 2 ) != 0 ;
1053
1083
}
1054
1084
0 commit comments