@@ -695,22 +695,10 @@ static size_t conversion_arglen(const struct conversion *conv)
695695 return words ;
696696}
697697
698- /* Ceiling divide by two. */
699- static void _rlrshift (uint64_t * v )
700- {
701- * v = (* v & 1 ) + (* v >> 1 );
702- }
703-
704698#ifdef CONFIG_64BIT
705699
706700static void _ldiv5 (uint64_t * v )
707701{
708- /*
709- * Usage in this file wants rounded behavior, not truncation. So add
710- * two to get the threshold right.
711- */
712- * v += 2U ;
713-
714702 /* The compiler can optimize this on its own on 64-bit architectures */
715703 * v /= 5U ;
716704}
@@ -735,13 +723,11 @@ static void _ldiv5(uint64_t *v)
735723 *
736724 * Here the multiplier is: (1 << 64) / 5 = 0x3333333333333333
737725 * i.e. a 62 bits value. To compensate for the reduced precision, we
738- * add an initial bias of 1 to v. Enlarging the multiplier to 64 bits
739- * would also work but a final right shift would be needed, and carry
740- * handling on the summing of partial mults would be necessary, requiring
741- * more instructions. Given that we already want to add bias of 2 for
742- * the result to be rounded to nearest and not truncated, we might as well
743- * combine those together into a bias of 3. This also conveniently allows
744- * for keeping the multiplier in a single 32-bit register given its pattern.
726+ * add an initial bias of 1 to v. This conveniently allows for keeping
727+ * the multiplier in a single 32-bit register given its pattern.
728+ * Enlarging the multiplier to 64 bits would also work but carry handling
729+ * on the summing of partial mults would be necessary, and a final right
730+ * shift would be needed, requiring more instructions.
745731 */
746732static void _ldiv5 (uint64_t * v )
747733{
@@ -758,12 +744,10 @@ static void _ldiv5(uint64_t *v)
758744 __asm__ ("" : "+r" (m ));
759745
760746 /*
761- * Apply the bias of 3 . We can't add it to v as this would overflow
747+ * Apply a bias of 1 to v . We can't add it to v as this would overflow
762748 * it when at max range. Factor it out with the multiplier upfront.
763- * Here we multiply the low and high parts separately to avoid an
764- * unnecessary 64-bit add-with-carry.
765749 */
766- result = ((uint64_t )( m * 3U ) << 32 ) | ( m * 3U ) ;
750+ result = ((uint64_t )m << 32 ) | m ;
767751
768752 /* The actual multiplication. */
769753 result += (uint64_t )v_lo * m ;
@@ -778,6 +762,13 @@ static void _ldiv5(uint64_t *v)
778762
779763#endif /* CONFIG_64BIT */
780764
765+ /* Division by 10 */
766+ static void _ldiv10 (uint64_t * v )
767+ {
768+ * v >>= 1 ;
769+ _ldiv5 (v );
770+ }
771+
781772/* Extract the next decimal character in the converted representation of a
782773 * fractional component.
783774 */
@@ -855,9 +846,6 @@ static char *encode_uint(uint_value_type value,
855846 return bp ;
856847}
857848
858- /* A magic value used in conversion. */
859- #define MAX_FP1 UINT32_MAX
860-
861849/* Number of bits in the fractional part of an IEEE 754-2008 double
862850 * precision float.
863851 */
@@ -1110,41 +1098,56 @@ static char *encode_float(double value,
11101098 fract |= BIT_63 ;
11111099 }
11121100
1113-
1114- /* Magically convert the base-2 exponent to a base-10
1115- * exponent.
1101+ /*
1102+ * Let's consider:
1103+ *
1104+ * value = fract * 2^exp * 10^decexp
1105+ *
1106+ * Initially decexp = 0. The goal is to bring exp between
1107+ * 0 and -2 as the magnitude of a fractional decimal digit is 3 bits.
11161108 */
11171109 int decexp = 0 ;
11181110
1119- while (exp <= -3 ) {
1120- while ((fract >> 32 ) >= (MAX_FP1 / 5 )) {
1121- _rlrshift (& fract );
1111+ while (exp < -2 ) {
1112+ /*
1113+ * Make roon to allow a multiplication by 5 without overflow.
1114+ * We test only the top part for faster code.
1115+ */
1116+ do {
1117+ fract >>= 1 ;
11221118 exp ++ ;
1123- }
1119+ } while ((uint32_t )(fract >> 32 ) >= (UINT32_MAX / 5U ));
1120+
1121+ /* Perform fract * 5 * 2 / 10 */
11241122 fract *= 5U ;
11251123 exp ++ ;
11261124 decexp -- ;
1127-
1128- while ((fract >> 32 ) <= (MAX_FP1 / 2 )) {
1129- fract <<= 1 ;
1130- exp -- ;
1131- }
11321125 }
11331126
11341127 while (exp > 0 ) {
1128+ /*
1129+ * Perform fract / 5 / 2 * 10.
1130+ * The +2 is there to do round the result of the division
1131+ * by 5 not to lose too much precision in extreme cases.
1132+ */
1133+ fract += 2 ;
11351134 _ldiv5 (& fract );
11361135 exp -- ;
11371136 decexp ++ ;
1138- while ((fract >> 32 ) <= (MAX_FP1 / 2 )) {
1137+
1138+ /* Bring back our fractional number to full scale */
1139+ do {
11391140 fract <<= 1 ;
11401141 exp -- ;
1141- }
1142+ } while (!( fract & BIT_63 ));
11421143 }
11431144
1144- while (exp < (0 + 4 )) {
1145- _rlrshift (& fract );
1146- exp ++ ;
1147- }
1145+ /*
1146+ * The binary fractional point is located somewhere above bit 63.
1147+ * Move it between bits 59 and 60 to give 4 bits of room to the
1148+ * integer part.
1149+ */
1150+ fract >>= (4 - exp );
11481151
11491152 if ((c == 'g' ) || (c == 'G' )) {
11501153 /* Use the specified precision and exponent to select the
@@ -1165,32 +1168,31 @@ static char *encode_float(double value,
11651168 }
11661169 }
11671170
1171+ int decimals ;
11681172 if (c == 'f' ) {
1169- exp = precision + decexp ;
1170- if (exp < 0 ) {
1171- exp = 0 ;
1173+ decimals = precision + decexp ;
1174+ if (decimals < 0 ) {
1175+ decimals = 0 ;
11721176 }
11731177 } else {
1174- exp = precision + 1 ;
1178+ decimals = precision + 1 ;
11751179 }
11761180
11771181 int digit_count = 16 ;
11781182
1179- if (exp > 16 ) {
1180- exp = 16 ;
1183+ if (decimals > 16 ) {
1184+ decimals = 16 ;
11811185 }
11821186
1183- uint64_t ltemp = BIT64 (59 );
1184-
1185- while (exp -- ) {
1186- _ldiv5 (& ltemp );
1187- _rlrshift (& ltemp );
1187+ /* Round the value to the last digit being printed. */
1188+ uint64_t round = BIT64 (59 ); /* 0.5 */
1189+ while (decimals -- ) {
1190+ _ldiv10 (& round );
11881191 }
1189-
1190- fract += ltemp ;
1191- if ((fract >> 32 ) & (0x0FU << 28 )) {
1192- _ldiv5 (& fract );
1193- _rlrshift (& fract );
1192+ fract += round ;
1193+ /* Make sure rounding didn't make fract >= 1.0 */
1194+ if (fract >= BIT64 (60 )) {
1195+ _ldiv10 (& fract );
11941196 decexp ++ ;
11951197 }
11961198
0 commit comments