@ -92,27 +92,30 @@ class StackArray {
// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
// the carry.
// Requires: `0 <= carry <= 9`
template < typename Int >
inline Int MultiplyBy10WithCarry ( Int * v , Int carry ) {
inline char MultiplyBy10WithCarry ( Int * v , char carry ) {
using BiggerInt = absl : : conditional_t < sizeof ( Int ) = = 4 , uint64_t , uint128 > ;
BiggerInt tmp = 10 * static_cast < BiggerInt > ( * v ) + carry ;
BiggerInt tmp =
10 * static_cast < BiggerInt > ( * v ) + static_cast < BiggerInt > ( carry ) ;
* v = static_cast < Int > ( tmp ) ;
return static_cast < Int > ( tmp > > ( sizeof ( Int ) * 8 ) ) ;
return static_cast < char > ( tmp > > ( sizeof ( Int ) * 8 ) ) ;
}
// Calculates `(2^64 * carry + *v) / 10`.
// Stores the quotient in `*v` and returns the remainder.
// Requires: `0 <= carry <= 9`
inline uint64_t DivideBy10WithCarry ( uint64_t * v , uint64_t carry ) {
inline char DivideBy10WithCarry ( uint64_t * v , char carry ) {
constexpr uint64_t divisor = 10 ;
// 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
constexpr uint64_t chunk_quotient = ( uint64_t { 1 } < < 63 ) / ( divisor / 2 ) ;
constexpr uint64_t chunk_remainder = uint64_t { } - chunk_quotient * divisor ;
const uint64_t carry_u64 = static_cast < uint64_t > ( carry ) ;
const uint64_t mod = * v % divisor ;
const uint64_t next_carry = chunk_remainder * carry + mod ;
* v = * v / divisor + carry * chunk_quotient + next_carry / divisor ;
return next_carry % divisor ;
const uint64_t next_carry = chunk_remainder * carry_u64 + mod ;
* v = * v / divisor + carry_u64 * chunk_quotient + next_carry / divisor ;
return static_cast < char > ( next_carry % divisor ) ;
}
using MaxFloatType =
@ -125,11 +128,11 @@ using MaxFloatType =
//
// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
class BinaryToDecimal {
static constexpr in t ChunksNeeded ( int exp ) {
static constexpr size_ t ChunksNeeded ( int exp ) {
// We will left shift a uint128 by `exp` bits, so we need `128+exp` total
// bits. Round up to 32.
// See constructor for details about adding `10%` to the value.
return ( 128 + exp + 31 ) / 32 * 11 / 10 ;
return static_cast < size_t > ( ( 128 + exp + 31 ) / 32 * 11 / 10 ) ;
}
public :
@ -140,7 +143,7 @@ class BinaryToDecimal {
assert ( exp > 0 ) ;
assert ( exp < = std : : numeric_limits < MaxFloatType > : : max_exponent ) ;
static_assert (
static_cast < int > ( StackArray : : kMaxCapacity ) > =
StackArray : : kMaxCapacity > =
ChunksNeeded ( std : : numeric_limits < MaxFloatType > : : max_exponent ) ,
" " ) ;
@ -149,9 +152,9 @@ class BinaryToDecimal {
[ = ] ( absl : : Span < uint32_t > input ) { f ( BinaryToDecimal ( input , v , exp ) ) ; } ) ;
}
in t TotalDigits ( ) const {
return static_cast < int > ( ( decimal_end_ - decimal_start_ ) * kDigitsPerChunk +
CurrentDigits ( ) . size ( ) ) ;
size_ t TotalDigits ( ) const {
return ( decimal_end_ - decimal_start_ ) * kDigitsPerChunk +
CurrentDigits ( ) . size ( ) ;
}
// See the current block of digits.
@ -190,30 +193,31 @@ class BinaryToDecimal {
// the decimal representation is around 7% less efficient in space than the
// binary one. We allocate an extra 10% memory to account for this. See
// ChunksNeeded for this calculation.
int chunk_index = exp / 32 ;
size_t after_ chunk_index = static_cast < size_t > ( exp / 32 + 1 ) ;
decimal_start_ = decimal_end_ = ChunksNeeded ( exp ) ;
const int offset = exp % 32 ;
// Left shift v by exp bits.
data_ [ chunk_index ] = static_cast < uint32_t > ( v < < offset ) ;
data_ [ after_ chunk_index - 1 ] = static_cast < uint32_t > ( v < < offset ) ;
for ( v > > = ( 32 - offset ) ; v ; v > > = 32 )
data_ [ + + chunk_index ] = static_cast < uint32_t > ( v ) ;
data_ [ + + after_ chunk_index - 1 ] = static_cast < uint32_t > ( v ) ;
while ( chunk_index > = 0 ) {
while ( after_ chunk_index > 0 ) {
// While we have more than one chunk available, go in steps of 1e9.
// `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
// the variable updated.
// `data_[after_ chunk_index - 1 ]` holds the highest non-zero binary chunk,
// so keep the variable updated.
uint32_t carry = 0 ;
for ( in t i = chunk_index ; i > = 0 ; - - i ) {
uint64_t tmp = uint64_t { data_ [ i ] } + ( uint64_t { carry } < < 32 ) ;
data_ [ i ] = static_cast < uint32_t > ( tmp / uint64_t { 1000000000 } ) ;
for ( size_ t i = after_ chunk_index; i > 0 ; - - i ) {
uint64_t tmp = uint64_t { data_ [ i - 1 ] } + ( uint64_t { carry } < < 32 ) ;
data_ [ i - 1 ] = static_cast < uint32_t > ( tmp / uint64_t { 1000000000 } ) ;
carry = static_cast < uint32_t > ( tmp % uint64_t { 1000000000 } ) ;
}
// If the highest chunk is now empty, remove it from view.
if ( data_ [ chunk_index ] = = 0 ) - - chunk_index ;
if ( data_ [ after_chunk_index - 1 ] = = 0 )
- - after_chunk_index ;
- - decimal_start_ ;
assert ( decimal_start_ ! = chunk_index ) ;
assert ( decimal_start_ ! = after_ chunk_index - 1 ) ;
data_ [ decimal_start_ ] = carry ;
}
@ -225,13 +229,13 @@ class BinaryToDecimal {
}
private :
static constexpr in t kDigitsPerChunk = 9 ;
static constexpr size_ t kDigitsPerChunk = 9 ;
in t decimal_start_ ;
in t decimal_end_ ;
size_ t decimal_start_ ;
size_ t decimal_end_ ;
char digits_ [ kDigitsPerChunk ] ;
in t size_ = 0 ;
size_ t size_ = 0 ;
absl : : Span < uint32_t > data_ ;
} ;
@ -251,25 +255,26 @@ class FractionalDigitGenerator {
static_assert ( StackArray : : kMaxCapacity > =
( Limits : : digits + 128 - Limits : : min_exponent + 31 ) / 32 ,
" " ) ;
StackArray : : RunWithCapacity ( ( Limits : : digits + exp + 31 ) / 32 ,
[ = ] ( absl : : Span < uint32_t > input ) {
f ( FractionalDigitGenerator ( input , v , exp ) ) ;
} ) ;
StackArray : : RunWithCapacity (
static_cast < size_t > ( ( Limits : : digits + exp + 31 ) / 32 ) ,
[ = ] ( absl : : Span < uint32_t > input ) {
f ( FractionalDigitGenerator ( input , v , exp ) ) ;
} ) ;
}
// Returns true if there are any more non-zero digits left.
bool HasMoreDigits ( ) const { return next_digit_ ! = 0 | | chunk_index_ > = 0 ; }
bool HasMoreDigits ( ) const { return next_digit_ ! = 0 | | after_ chunk_index_; }
// Returns true if the remainder digits are greater than 5000...
bool IsGreaterThanHalf ( ) const {
return next_digit_ > 5 | | ( next_digit_ = = 5 & & chunk_index_ > = 0 ) ;
return next_digit_ > 5 | | ( next_digit_ = = 5 & & after_ chunk_index_) ;
}
// Returns true if the remainder digits are exactly 5000...
bool IsExactlyHalf ( ) const { return next_digit_ = = 5 & & chunk_index_ < 0 ; }
bool IsExactlyHalf ( ) const { return next_digit_ = = 5 & & ! after_chunk_index_ ; }
struct Digits {
int digit_before_nine ;
in t num_nines ;
char digit_before_nine ;
size_ t num_nines ;
} ;
// Get the next set of digits.
@ -288,35 +293,37 @@ class FractionalDigitGenerator {
private :
// Return the next digit.
int GetOneDigit ( ) {
if ( chunk_index_ < 0 ) return 0 ;
char GetOneDigit ( ) {
if ( ! after_chunk_index_ )
return 0 ;
uint32_t carry = 0 ;
for ( in t i = chunk_index_ ; i > = 0 ; - - i ) {
carry = MultiplyBy10WithCarry ( & data_ [ i ] , carry ) ;
char carry = 0 ;
for ( size_ t i = after_ chunk_index_; i > 0 ; - - i ) {
carry = MultiplyBy10WithCarry ( & data_ [ i - 1 ] , carry ) ;
}
// If the lowest chunk is now empty, remove it from view.
if ( data_ [ chunk_index_ ] = = 0 ) - - chunk_index_ ;
if ( data_ [ after_chunk_index_ - 1 ] = = 0 )
- - after_chunk_index_ ;
return carry ;
}
FractionalDigitGenerator ( absl : : Span < uint32_t > data , uint128 v , int exp )
: chunk_index_ ( exp / 32 ) , data_ ( data ) {
: after_ chunk_index_( static_cast < size_t > ( exp / 32 + 1 ) ) , data_ ( data ) {
const int offset = exp % 32 ;
// Right shift `v` by `exp` bits.
data_ [ chunk_index_ ] = static_cast < uint32_t > ( v < < ( 32 - offset ) ) ;
data_ [ after_ chunk_index_ - 1 ] = static_cast < uint32_t > ( v < < ( 32 - offset ) ) ;
v > > = offset ;
// Make sure we don't overflow the data. We already calculated that
// non-zero bits fit, so we might not have space for leading zero bits.
for ( in t pos = chunk_index_ ; v ; v > > = 32 )
for ( size_ t pos = after_ chunk_index_ - 1 ; v ; v > > = 32 )
data_ [ - - pos ] = static_cast < uint32_t > ( v ) ;
// Fill next_digit_, as GetDigits expects it to be populated always.
next_digit_ = GetOneDigit ( ) ;
}
int next_digit_ ;
int chunk_index_ ;
char next_digit_ ;
size_t after_ chunk_index_;
absl : : Span < uint32_t > data_ ;
} ;
@ -362,7 +369,7 @@ char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
auto low = static_cast < uint64_t > ( v ) ;
while ( high ! = 0 ) {
uint64_t carry = DivideBy10WithCarry ( & high , 0 ) ;
char carry = DivideBy10WithCarry ( & high , 0 ) ;
carry = DivideBy10WithCarry ( & low , carry ) ;
* - - p = carry + ' 0 ' ;
}
@ -373,13 +380,15 @@ char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
// shifting.
// Performs rounding if necessary to fit within `precision`.
// Returns the pointer to one after the last character written.
char * PrintFractionalDigitsFast ( uint64_t v , char * start , int exp ,
int precision ) {
char * PrintFractionalDigitsFast ( uint64_t v ,
char * start ,
int exp ,
size_t precision ) {
char * p = start ;
v < < = ( 64 - exp ) ;
while ( precision > 0 ) {
if ( ! v ) return p ;
* p + + = MultiplyBy10WithCarry ( & v , uint64_t { 0 } ) + ' 0 ' ;
* p + + = MultiplyBy10WithCarry ( & v , 0 ) + ' 0 ' ;
- - precision ;
}
@ -393,8 +402,6 @@ char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
RoundToEven ( p - 1 ) ;
}
assert ( precision = = 0 ) ;
// Precision can only be zero here.
return p ;
}
@ -402,8 +409,10 @@ char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
// after shifting.
// Performs rounding if necessary to fit within `precision`.
// Returns the pointer to one after the last character written.
char * PrintFractionalDigitsFast ( uint128 v , char * start , int exp ,
int precision ) {
char * PrintFractionalDigitsFast ( uint128 v ,
char * start ,
int exp ,
size_t precision ) {
char * p = start ;
v < < = ( 128 - exp ) ;
auto high = static_cast < uint64_t > ( v > > 64 ) ;
@ -412,7 +421,7 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
// While we have digits to print and `low` is not empty, do the long
// multiplication.
while ( precision > 0 & & low ! = 0 ) {
uint64_t carry = MultiplyBy10WithCarry ( & low , uint64_t { 0 } ) ;
char carry = MultiplyBy10WithCarry ( & low , 0 ) ;
carry = MultiplyBy10WithCarry ( & high , carry ) ;
* p + + = carry + ' 0 ' ;
@ -424,7 +433,7 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
// above.
while ( precision > 0 ) {
if ( ! high ) return p ;
* p + + = MultiplyBy10WithCarry ( & high , uint64_t { 0 } ) + ' 0 ' ;
* p + + = MultiplyBy10WithCarry ( & high , 0 ) + ' 0 ' ;
- - precision ;
}
@ -438,14 +447,12 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
RoundToEven ( p - 1 ) ;
}
assert ( precision = = 0 ) ;
// Precision can only be zero here.
return p ;
}
struct FormatState {
char sign_char ;
in t precision ;
size_ t precision ;
const FormatConversionSpecImpl & conv ;
FormatSinkImpl * sink ;
@ -455,9 +462,9 @@ struct FormatState {
} ;
struct Padding {
in t left_spaces ;
in t zeros ;
in t right_spaces ;
size_ t left_spaces ;
size_ t zeros ;
size_ t right_spaces ;
} ;
Padding ExtraWidthToPadding ( size_t total_size , const FormatState & state ) {
@ -465,7 +472,7 @@ Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
static_cast < size_t > ( state . conv . width ( ) ) < = total_size ) {
return { 0 , 0 , 0 } ;
}
in t missing_chars = state . conv . width ( ) - total_size ;
size_ t missing_chars = static_cast < size_t > ( state . conv . width ( ) ) - total_size ;
if ( state . conv . has_left_flag ( ) ) {
return { 0 , 0 , missing_chars } ;
} else if ( state . conv . has_zero_flag ( ) ) {
@ -475,8 +482,10 @@ Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
}
}
void FinalPrint ( const FormatState & state , absl : : string_view data ,
int padding_offset , int trailing_zeros ,
void FinalPrint ( const FormatState & state ,
absl : : string_view data ,
size_t padding_offset ,
size_t trailing_zeros ,
absl : : string_view data_postfix ) {
if ( state . conv . width ( ) < 0 ) {
// No width specified. Fast-path.
@ -487,10 +496,10 @@ void FinalPrint(const FormatState &state, absl::string_view data,
return ;
}
auto padding = ExtraWidthToPadding ( ( state . sign_char ! = ' \0 ' ? 1 : 0 ) +
data . size ( ) + data_postfix . size ( ) +
static_cast < size_t > ( trailing_zeros ) ,
state ) ;
auto padding =
ExtraWidthToPadding ( ( state . sign_char ! = ' \0 ' ? 1 : 0 ) + data . size ( ) +
data_postfix . size ( ) + trailing_zeros ,
state ) ;
state . sink - > Append ( padding . left_spaces , ' ' ) ;
if ( state . sign_char ! = ' \0 ' ) state . sink - > Append ( 1 , state . sign_char ) ;
@ -547,15 +556,16 @@ void FormatFFast(Int v, int exp, const FormatState &state) {
if ( integral_digits_start [ - 1 ] ! = ' 0 ' ) - - integral_digits_start ;
}
size_t size = fractional_digits_end - integral_digits_start ;
size_t size =
static_cast < size_t > ( fractional_digits_end - integral_digits_start ) ;
// In `alt` mode (flag #) we keep the `.` even if there are no fractional
// digits. In non-alt mode, we strip it.
if ( ! state . ShouldPrintDot ( ) ) - - size ;
FinalPrint ( state , absl : : string_view ( integral_digits_start , size ) ,
/*padding_offset=*/ 0 ,
static_cast < int > ( state . precision - ( fractional_digits_end -
fractional_digits_start ) ) ,
state . precision - static_cast < size_t > ( fractional_digits_end -
fractional_digits_start ) ,
/*data_postfix=*/ " " ) ;
}
@ -567,21 +577,22 @@ void FormatFFast(Int v, int exp, const FormatState &state) {
void FormatFPositiveExpSlow ( uint128 v , int exp , const FormatState & state ) {
BinaryToDecimal : : RunConversion ( v , exp , [ & ] ( BinaryToDecimal btd ) {
const size_t total_digits =
btd . TotalDigits ( ) +
( state . ShouldPrintDot ( ) ? static_cast < size_t > ( state . precision ) + 1 : 0 ) ;
btd . TotalDigits ( ) + ( state . ShouldPrintDot ( ) ? state . precision + 1 : 0 ) ;
const auto padding = ExtraWidthToPadding (
total_digits + ( state . sign_char ! = ' \0 ' ? 1 : 0 ) , state ) ;
state . sink - > Append ( padding . left_spaces , ' ' ) ;
if ( state . sign_char ! = ' \0 ' ) state . sink - > Append ( 1 , state . sign_char ) ;
if ( state . sign_char ! = ' \0 ' )
state . sink - > Append ( 1 , state . sign_char ) ;
state . sink - > Append ( padding . zeros , ' 0 ' ) ;
do {
state . sink - > Append ( btd . CurrentDigits ( ) ) ;
} while ( btd . AdvanceDigits ( ) ) ;
if ( state . ShouldPrintDot ( ) ) state . sink - > Append ( 1 , ' . ' ) ;
if ( state . ShouldPrintDot ( ) )
state . sink - > Append ( 1 , ' . ' ) ;
state . sink - > Append ( state . precision , ' 0 ' ) ;
state . sink - > Append ( padding . right_spaces , ' ' ) ;
} ) ;
@ -594,8 +605,7 @@ void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
// digits.
void FormatFNegativeExpSlow ( uint128 v , int exp , const FormatState & state ) {
const size_t total_digits =
/* 0 */ 1 +
( state . ShouldPrintDot ( ) ? static_cast < size_t > ( state . precision ) + 1 : 0 ) ;
/* 0 */ 1 + ( state . ShouldPrintDot ( ) ? state . precision + 1 : 0 ) ;
auto padding =
ExtraWidthToPadding ( total_digits + ( state . sign_char ? 1 : 0 ) , state ) ;
padding . zeros + = 1 ;
@ -606,7 +616,7 @@ void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
if ( state . ShouldPrintDot ( ) ) state . sink - > Append ( 1 , ' . ' ) ;
// Print digits
in t digits_to_go = state . precision ;
size_ t digits_to_go = state . precision ;
FractionalDigitGenerator : : RunConversion (
v , exp , [ & ] ( FractionalDigitGenerator digit_gen ) {
@ -666,7 +676,8 @@ void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
template < typename Int >
void FormatF ( Int mantissa , int exp , const FormatState & state ) {
if ( exp > = 0 ) {
const int total_bits = sizeof ( Int ) * 8 - LeadingZeros ( mantissa ) + exp ;
const int total_bits =
static_cast < int > ( sizeof ( Int ) * 8 ) - LeadingZeros ( mantissa ) + exp ;
// Fallback to the slow stack-based approach if we can't do it in a 64 or
// 128 bit state.
@ -686,9 +697,9 @@ void FormatF(Int mantissa, int exp, const FormatState &state) {
// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
// bits 4-7.
template < typename Int >
uint8_t GetNibble ( Int n , in t nibble_index ) {
uint8_t GetNibble ( Int n , size_ t nibble_index ) {
constexpr Int mask_low_nibble = Int { 0xf } ;
int shift = nibble_index * 4 ;
int shift = static_cast < int > ( nibble_index * 4 ) ;
n & = mask_low_nibble < < shift ;
return static_cast < uint8_t > ( ( n > > shift ) & 0xf ) ;
}
@ -696,9 +707,9 @@ uint8_t GetNibble(Int n, int nibble_index) {
// Add one to the given nibble, applying carry to higher nibbles. Returns true
// if overflow, false otherwise.
template < typename Int >
bool IncrementNibble ( in t nibble_index , Int * n ) {
constexpr in t kShift = sizeof ( Int ) * 8 - 1 ;
constexpr in t kNumNibbles = sizeof ( Int ) * 8 / 4 ;
bool IncrementNibble ( size_ t nibble_index , Int * n ) {
constexpr size_ t kShift = sizeof ( Int ) * 8 - 1 ;
constexpr size_ t kNumNibbles = sizeof ( Int ) * 8 / 4 ;
Int before = * n > > kShift ;
// Here we essentially want to take the number 1 and move it into the requsted
// nibble, then add it to *n to effectively increment the nibble. However,
@ -706,28 +717,32 @@ bool IncrementNibble(int nibble_index, Int *n) {
// i.e., if the nibble_index is out of range. So therefore we check for this
// and if we are out of range we just add 0 which leaves *n unchanged, which
// seems like the reasonable thing to do in that case.
* n + = ( ( nibble_index > = kNumNibbles ) ? 0 : ( Int { 1 } < < ( nibble_index * 4 ) ) ) ;
* n + = ( ( nibble_index > = kNumNibbles )
? 0
: ( Int { 1 } < < static_cast < int > ( nibble_index * 4 ) ) ) ;
Int after = * n > > kShift ;
return ( before & & ! after ) | | ( nibble_index > = kNumNibbles ) ;
}
// Return a mask with 1's in the given nibble and all lower nibbles.
template < typename Int >
Int MaskUpToNibbleInclusive ( in t nibble_index ) {
constexpr in t kNumNibbles = sizeof ( Int ) * 8 / 4 ;
Int MaskUpToNibbleInclusive ( size_ t nibble_index ) {
constexpr size_ t kNumNibbles = sizeof ( Int ) * 8 / 4 ;
static const Int ones = ~ Int { 0 } ;
return ones > > std : : max ( 0 , 4 * ( kNumNibbles - nibble_index - 1 ) ) ;
+ + nibble_index ;
return ones > > static_cast < int > (
4 * ( std : : max ( kNumNibbles , nibble_index ) - nibble_index ) ) ;
}
// Return a mask with 1's below the given nibble.
template < typename Int >
Int MaskUpToNibbleExclusive ( in t nibble_index ) {
return nibble_index < = 0 ? 0 : MaskUpToNibbleInclusive < Int > ( nibble_index - 1 ) ;
Int MaskUpToNibbleExclusive ( size_ t nibble_index ) {
return nibble_index = = 0 ? 0 : MaskUpToNibbleInclusive < Int > ( nibble_index - 1 ) ;
}
template < typename Int >
Int MoveToNibble ( uint8_t nibble , in t nibble_index ) {
return Int { nibble } < < ( 4 * nibble_index ) ;
Int MoveToNibble ( uint8_t nibble , size_ t nibble_index ) {
return Int { nibble } < < static_cast < int > ( 4 * nibble_index ) ;
}
// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
@ -744,10 +759,10 @@ Int MoveToNibble(uint8_t nibble, int nibble_index) {
// a multiple of four. Once again, the goal is to have all fractional digits
// represent real precision.
template < typename Float >
constexpr in t HexFloatLeadingDigitSizeInBits ( ) {
constexpr size_ t HexFloatLeadingDigitSizeInBits ( ) {
return std : : numeric_limits < Float > : : digits % 4 > 0
? std : : numeric_limits < Float > : : digits % 4
: 4 ;
? static_cast < size_t > ( std : : numeric_limits < Float > : : digits % 4 )
: size_t { 4 } ;
}
// This function captures the rounding behavior of glibc for hex float
@ -757,16 +772,17 @@ constexpr int HexFloatLeadingDigitSizeInBits() {
// point that is not followed by 800000..., it disregards the parity and rounds
// up if > 8 and rounds down if < 8.
template < typename Int >
bool HexFloatNeedsRoundUp ( Int mantissa , int final_nibble_displayed ,
bool HexFloatNeedsRoundUp ( Int mantissa ,
size_t final_nibble_displayed ,
uint8_t leading ) {
// If the last nibble (hex digit) to be displayed is the lowest on in the
// mantissa then that means that we don't have any further nibbles to inform
// rounding, so don't round.
if ( final_nibble_displayed < = 0 ) {
if ( final_nibble_displayed = = 0 ) {
return false ;
}
in t rounding_nibble_idx = final_nibble_displayed - 1 ;
constexpr in t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
size_ t rounding_nibble_idx = final_nibble_displayed - 1 ;
constexpr size_ t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
assert ( final_nibble_displayed < = kTotalNibbles ) ;
Int mantissa_up_to_rounding_nibble_inclusive =
mantissa & MaskUpToNibbleInclusive < Int > ( rounding_nibble_idx ) ;
@ -793,7 +809,7 @@ struct HexFloatTypeParams {
}
int min_exponent ;
in t leading_digit_size_bits ;
size_ t leading_digit_size_bits ;
} ;
// Hex Float Rounding. First check if we need to round; if so, then we do that
@ -803,10 +819,12 @@ struct HexFloatTypeParams {
template < typename Int >
void FormatARound ( bool precision_specified , const FormatState & state ,
uint8_t * leading , Int * mantissa , int * exp ) {
constexpr in t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
constexpr size_ t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
// Index of the last nibble that we could display given precision.
int final_nibble_displayed =
precision_specified ? std : : max ( 0 , ( kTotalNibbles - state . precision ) ) : 0 ;
size_t final_nibble_displayed =
precision_specified
? ( std : : max ( kTotalNibbles , state . precision ) - state . precision )
: 0 ;
if ( HexFloatNeedsRoundUp ( * mantissa , final_nibble_displayed , * leading ) ) {
// Need to round up.
bool overflow = IncrementNibble ( final_nibble_displayed , mantissa ) ;
@ -830,9 +848,9 @@ void FormatARound(bool precision_specified, const FormatState &state,
template < typename Int >
void FormatANormalize ( const HexFloatTypeParams float_traits , uint8_t * leading ,
Int * mantissa , int * exp ) {
constexpr in t kIntBits = sizeof ( Int ) * 8 ;
constexpr size_ t kIntBits = sizeof ( Int ) * 8 ;
static const Int kHighIntBit = Int { 1 } < < ( kIntBits - 1 ) ;
const in t kLeadDigitBitsCount = float_traits . leading_digit_size_bits ;
const size_ t kLeadDigitBitsCount = float_traits . leading_digit_size_bits ;
// Normalize mantissa so that highest bit set is in MSB position, unless we
// get interrupted by the exponent threshold.
while ( * mantissa & & ! ( * mantissa & kHighIntBit ) ) {
@ -846,18 +864,18 @@ void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
}
// Extract bits for leading digit then shift them away leaving the
// fractional part.
* leading =
static_cast < uint8_t > ( * mantissa > > ( kIntBits - kLeadDigitBitsCount ) ) ;
* exp - = ( * mantissa ! = 0 ) ? kLeadDigitBitsCount : * exp ;
* mantissa < < = kLeadDigitBitsCount ;
* leading = static_cast < uint8_t > (
* mantissa > > static_cast < int > ( kIntBits - kLeadDigitBitsCount ) ) ;
* exp - = ( * mantissa ! = 0 ) ? static_cast < int > ( kLeadDigitBitsCount ) : * exp ;
* mantissa < < = static_cast < int > ( kLeadDigitBitsCount ) ;
}
template < typename Int >
void FormatA ( const HexFloatTypeParams float_traits , Int mantissa , int exp ,
bool uppercase , const FormatState & state ) {
// Int properties.
constexpr in t kIntBits = sizeof ( Int ) * 8 ;
constexpr in t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
constexpr size_ t kIntBits = sizeof ( Int ) * 8 ;
constexpr size_ t kTotalNibbles = sizeof ( Int ) * 8 / 4 ;
// Did the user specify a precision explicitly?
const bool precision_specified = state . conv . precision ( ) > = 0 ;
@ -903,16 +921,19 @@ void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
}
// ============ Fractional Digits ============
in t digits_emitted = 0 ;
size_ t digits_emitted = 0 ;
while ( mantissa > 0 ) {
* digits_iter + + = digits [ GetNibble ( mantissa , kTotalNibbles - 1 ) ] ;
mantissa < < = 4 ;
+ + digits_emitted ;
}
int trailing_zeros =
precision_specified ? state . precision - digits_emitted : 0 ;
assert ( trailing_zeros > = 0 ) ;
auto digits_result = string_view ( digits_buffer , digits_iter - digits_buffer ) ;
size_t trailing_zeros = 0 ;
if ( precision_specified ) {
assert ( state . precision > = digits_emitted ) ;
trailing_zeros = state . precision - digits_emitted ;
}
auto digits_result = string_view (
digits_buffer , static_cast < size_t > ( digits_iter - digits_buffer ) ) ;
// =============== Exponent ==================
constexpr size_t kBufSizeForExpDecRepr =
@ -925,11 +946,11 @@ void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
numbers_internal : : FastIntToBuffer ( exp < 0 ? - exp : exp , exp_buffer + 2 ) ;
// ============ Assemble Result ==============
FinalPrint ( state , //
digits_result , // 0xN.NNN...
2 , // offset in `data` to start padding if needed.
trailing_zeros , // num remaining mantissa padding zeros
exp_buffer ) ; // exponent
FinalPrint ( state ,
digits_result , // 0xN.NNN...
2 , // offset of any padding
static_cast < size_t > ( trailing_zeros ) , // remaining mantissa padding
exp_buffer ) ; // exponent
}
char * CopyStringTo ( absl : : string_view v , char * out ) {
@ -961,10 +982,10 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
int n = snprintf ( & space [ 0 ] , space . size ( ) , fmt , w , p , v ) ;
if ( n < 0 ) return false ;
if ( static_cast < size_t > ( n ) < space . size ( ) ) {
result = absl : : string_view ( space . data ( ) , n ) ;
result = absl : : string_view ( space . data ( ) , static_cast < size_t > ( n ) ) ;
break ;
}
space . resize ( n + 1 ) ;
space . resize ( static_cast < size_t > ( n ) + 1 ) ;
}
sink - > Append ( result ) ;
return true ;
@ -972,13 +993,13 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
// 128-bits in decimal: ceil(128*log(2)/log(10))
// or std::numeric_limits<__uint128_t>::digits10
constexpr in t kMaxFixedPrecision = 39 ;
constexpr size_ t kMaxFixedPrecision = 39 ;
constexpr in t kBufferLength = /*sign*/ 1 +
/*integer*/ kMaxFixedPrecision +
/*point*/ 1 +
/*fraction*/ kMaxFixedPrecision +
/*exponent e+123*/ 5 ;
constexpr size_ t kBufferLength = /*sign*/ 1 +
/*integer*/ kMaxFixedPrecision +
/*point*/ 1 +
/*fraction*/ kMaxFixedPrecision +
/*exponent e+123*/ 5 ;
struct Buffer {
void push_front ( char c ) {
@ -1001,7 +1022,7 @@ struct Buffer {
char last_digit ( ) const { return end [ - 1 ] = = ' . ' ? end [ - 2 ] : end [ - 1 ] ; }
in t size ( ) const { return static_cast < in t> ( end - begin ) ; }
size_ t size ( ) const { return static_cast < size_ t> ( end - begin ) ; }
char data [ kBufferLength ] ;
char * begin ;
@ -1030,8 +1051,9 @@ bool ConvertNonNumericFloats(char sign_char, Float v,
return false ;
}
return sink - > PutPaddedString ( string_view ( text , ptr - text ) , conv . width ( ) , - 1 ,
conv . has_left_flag ( ) ) ;
return sink - > PutPaddedString (
string_view ( text , static_cast < size_t > ( ptr - text ) ) , conv . width ( ) , - 1 ,
conv . has_left_flag ( ) ) ;
}
// Round up the last digit of the value.
@ -1068,11 +1090,11 @@ void PrintExponent(int exp, char e, Buffer *out) {
}
// Exponent digits.
if ( exp > 99 ) {
out - > push_back ( exp / 100 + ' 0 ' ) ;
out - > push_back ( static_cast < char > ( exp / 100 ) + ' 0 ' ) ;
out - > push_back ( exp / 10 % 10 + ' 0 ' ) ;
out - > push_back ( exp % 10 + ' 0 ' ) ;
} else {
out - > push_back ( exp / 10 + ' 0 ' ) ;
out - > push_back ( static_cast < char > ( exp / 10 ) + ' 0 ' ) ;
out - > push_back ( exp % 10 + ' 0 ' ) ;
}
}
@ -1115,8 +1137,8 @@ Decomposed<Float> Decompose(Float v) {
// In Fixed mode, we add a '.' at the end.
// In Precision mode, we add a '.' after the first digit.
template < FormatStyle mode , typename Int >
in t PrintIntegralDigits ( Int digits , Buffer * out ) {
in t printed = 0 ;
size_ t PrintIntegralDigits ( Int digits , Buffer * out ) {
size_ t printed = 0 ;
if ( digits ) {
for ( ; digits ; digits / = 10 ) out - > push_front ( digits % 10 + ' 0 ' ) ;
printed = out - > size ( ) ;
@ -1135,10 +1157,10 @@ int PrintIntegralDigits(Int digits, Buffer *out) {
}
// Back out 'extra_digits' digits and round up if necessary.
bool RemoveExtraPrecision ( int extra_digits , bool has_leftover_value ,
Buffer * out , int * exp_out ) {
if ( extra_digits < = 0 ) return false ;
void RemoveExtraPrecision ( size_t extra_digits ,
bool has_leftover_value ,
Buffer * out ,
int * exp_out ) {
// Back out the extra digits
out - > end - = extra_digits ;
@ -1158,15 +1180,17 @@ bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value,
if ( needs_to_round_up ) {
RoundUp < FormatStyle : : Precision > ( out , exp_out ) ;
}
return true ;
}
// Print the value into the buffer.
// This will not include the exponent, which will be returned in 'exp_out' for
// Precision mode.
template < typename Int , typename Float , FormatStyle mode >
bool FloatToBufferImpl ( Int int_mantissa , int exp , int precision , Buffer * out ,
int * exp_out ) {
bool FloatToBufferImpl ( Int int_mantissa ,
int exp ,
size_t precision ,
Buffer * out ,
int * exp_out ) {
assert ( ( CanFitMantissa < Float , Int > ( ) ) ) ;
const int int_bits = std : : numeric_limits < Int > : : digits ;
@ -1182,14 +1206,16 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
// The value will overflow the Int
return false ;
}
in t digits_printed = PrintIntegralDigits < mode > ( int_mantissa < < exp , out ) ;
in t digits_to_zero_pad = precision ;
size_ t digits_printed = PrintIntegralDigits < mode > ( int_mantissa < < exp , out ) ;
size_ t digits_to_zero_pad = precision ;
if ( mode = = FormatStyle : : Precision ) {
* exp_out = digits_printed - 1 ;
digits_to_zero_pad - = digits_printed - 1 ;
if ( RemoveExtraPrecision ( - digits_to_zero_pad , false , out , exp_out ) ) {
* exp_out = static_cast < int > ( digits_printed - 1 ) ;
if ( digits_to_zero_pad < digits_printed - 1 ) {
RemoveExtraPrecision ( digits_printed - 1 - digits_to_zero_pad , false ,
out , exp_out ) ;
return true ;
}
digits_to_zero_pad - = digits_printed - 1 ;
}
for ( ; digits_to_zero_pad - - > 0 ; ) out - > push_back ( ' 0 ' ) ;
return true ;
@ -1203,10 +1229,10 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
const Int mask = ( Int { 1 } < < exp ) - 1 ;
// Print the integral part first.
in t digits_printed = PrintIntegralDigits < mode > ( int_mantissa > > exp , out ) ;
size_ t digits_printed = PrintIntegralDigits < mode > ( int_mantissa > > exp , out ) ;
int_mantissa & = mask ;
in t fractional_count = precision ;
size_ t fractional_count = precision ;
if ( mode = = FormatStyle : : Precision ) {
if ( digits_printed = = 0 ) {
// Find the first non-zero digit, when in Precision mode.
@ -1222,20 +1248,21 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
int_mantissa & = mask ;
} else {
// We already have a digit, and a '.'
* exp_out = digits_printed - 1 ;
fractional_count - = * exp_out ;
if ( RemoveExtraPrecision ( - fractional_count , int_mantissa ! = 0 , out ,
exp_out ) ) {
* exp_out = static_cast < int > ( digits_printed - 1 ) ;
if ( fractional_count < digits_printed - 1 ) {
// If we had enough digits, return right away.
// The code below will try to round again otherwise.
RemoveExtraPrecision ( digits_printed - 1 - fractional_count ,
int_mantissa ! = 0 , out , exp_out ) ;
return true ;
}
fractional_count - = digits_printed - 1 ;
}
}
auto get_next_digit = [ & ] {
int_mantissa * = 10 ;
int digit = static_cast < int > ( int_mantissa > > exp ) ;
char digit = static_cast < char > ( int_mantissa > > exp ) ;
int_mantissa & = mask ;
return digit ;
} ;
@ -1245,7 +1272,7 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
out - > push_back ( get_next_digit ( ) + ' 0 ' ) ;
}
int next_digit = get_next_digit ( ) ;
char next_digit = get_next_digit ( ) ;
if ( next_digit > 5 | |
( next_digit = = 5 & & ( int_mantissa | | out - > last_digit ( ) % 2 = = 1 ) ) ) {
RoundUp < mode > ( out , exp_out ) ;
@ -1255,24 +1282,25 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
}
template < FormatStyle mode , typename Float >
bool FloatToBuffer ( Decomposed < Float > decomposed , int precision , Buffer * out ,
int * exp ) {
bool FloatToBuffer ( Decomposed < Float > decomposed ,
size_t precision ,
Buffer * out ,
int * exp ) {
if ( precision > kMaxFixedPrecision ) return false ;
// Try with uint64_t.
if ( CanFitMantissa < Float , std : : uint64_t > ( ) & &
FloatToBufferImpl < std : : uint64_t , Float , mode > (
static_cast < std : : uint64_t > ( decomposed . mantissa ) ,
static_cast < std : : uint64_t > ( decomposed . exponent ) , precision , out , exp ) )
static_cast < std : : uint64_t > ( decomposed . mantissa ) , decomposed . exponent ,
precision , out , exp ) )
return true ;
# if defined(ABSL_HAVE_INTRINSIC_INT128)
// If that is not enough, try with __uint128_t.
return CanFitMantissa < Float , __uint128_t > ( ) & &
FloatToBufferImpl < __uint128_t , Float , mode > (
static_cast < __uint128_t > ( decomposed . mantissa ) ,
static_cast < __uint128_t > ( decomposed . exponent ) , precision , out ,
exp ) ;
static_cast < __uint128_t > ( decomposed . mantissa ) , decomposed . exponent ,
precision , out , exp ) ;
# endif
return false ;
}
@ -1280,12 +1308,15 @@ bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
void WriteBufferToSink ( char sign_char , absl : : string_view str ,
const FormatConversionSpecImpl & conv ,
FormatSinkImpl * sink ) {
int left_spaces = 0 , zeros = 0 , right_spaces = 0 ;
int missing_chars =
conv . width ( ) > = 0 ? std : : max ( conv . width ( ) - static_cast < int > ( str . size ( ) ) -
static_cast < int > ( sign_char ! = 0 ) ,
0 )
: 0 ;
size_t left_spaces = 0 , zeros = 0 , right_spaces = 0 ;
size_t missing_chars = 0 ;
if ( conv . width ( ) > = 0 ) {
const size_t conv_width_size_t = static_cast < size_t > ( conv . width ( ) ) ;
const size_t existing_chars =
str . size ( ) + static_cast < size_t > ( sign_char ! = 0 ) ;
if ( conv_width_size_t > existing_chars )
missing_chars = conv_width_size_t - existing_chars ;
}
if ( conv . has_left_flag ( ) ) {
right_spaces = missing_chars ;
} else if ( conv . has_zero_flag ( ) ) {
@ -1321,7 +1352,8 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
return true ;
}
int precision = conv . precision ( ) < 0 ? 6 : conv . precision ( ) ;
size_t precision =
conv . precision ( ) < 0 ? 6 : static_cast < size_t > ( conv . precision ( ) ) ;
int exp = 0 ;
@ -1348,12 +1380,12 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
& buffer ) ;
} else if ( c = = FormatConversionCharInternal : : g | |
c = = FormatConversionCharInternal : : G ) {
precision = std : : max ( 0 , precision - 1 ) ;
precision = std : : max ( precision , size_t { 1 } ) - 1 ;
if ( ! FloatToBuffer < FormatStyle : : Precision > ( decomposed , precision , & buffer ,
& exp ) ) {
return FallbackToSnprintf ( v , conv , sink ) ;
}
if ( precision + 1 > exp & & exp > = - 4 ) {
if ( ( exp < 0 | | precision + 1 > static_cast < size_t > ( exp ) ) & & exp > = - 4 ) {
if ( exp < 0 ) {
// Have 1.23456, needs 0.00123456
// Move the first digit
@ -1388,9 +1420,11 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
return false ;
}
WriteBufferToSink ( sign_char ,
absl : : string_view ( buffer . begin , buffer . end - buffer . begin ) ,
conv , sink ) ;
WriteBufferToSink (
sign_char ,
absl : : string_view ( buffer . begin ,
static_cast < size_t > ( buffer . end - buffer . begin ) ) ,
conv , sink ) ;
return true ;
}