in renderdoc/strings/utf8printf.cpp [542:1182]
void PrintFloat(double argd, FormatterParams &formatter, bool e, bool f, bool g, bool a,
bool uppercaseDigits, char *&output, size_t &actualsize, char *end)
{
// extract the pieces out of the double
uint64_t *arg64 = (uint64_t *)&argd;
bool signbit = (*arg64 & 0x8000000000000000) ? true : false;
uint64_t rawexp = (*arg64 & 0x7ff0000000000000) >> 52;
int exponent = int(rawexp) - 1023;
uint64_t mantissa = (*arg64 & 0x000fffffffffffff);
char prepend = '\0';
if(signbit)
prepend = '-';
else if(formatter.Flags & PrependPos)
prepend = '+';
else if(formatter.Flags & PrependSpace)
prepend = ' ';
// special-case handling of printing 0
if(rawexp == 0 && mantissa == 0)
{
PrintFloat0(e, f, a, uppercaseDigits, formatter, prepend, output, actualsize, end);
}
// handle 'special' values, inf and nan
else if(rawexp == 0x7ff)
{
if(mantissa == 0)
{
if(signbit)
appendstring(output, actualsize, end, uppercaseDigits ? "-INF" : "-inf");
else
appendstring(output, actualsize, end, uppercaseDigits ? "+INF" : "+inf");
}
else
{
appendstring(output, actualsize, end, uppercaseDigits ? "NAN" : "nan");
}
}
else if(a)
{
char digits[18] = {0};
int ndigits = 0;
for(int d = 12; mantissa && d >= 0; d--)
{
const uint64_t mask = 0xfULL << (d * 4);
const uint64_t digit = (mantissa & mask) >> (d * 4);
char c = char('0' + digit);
if(digit >= 10)
c = char((uppercaseDigits ? 'A' : 'a') + digit - 10);
digits[ndigits++] = c;
mantissa &= ~mask;
}
// if no precision is specified, drop trailing 0s and ensure we don't pad or trim
if(formatter.Precision == FormatterParams::NoPrecision)
{
while(ndigits > 0 && digits[ndigits - 1] == '0')
ndigits--;
formatter.Precision = ndigits;
}
// hold the carry bit because if it's needed we have no decimals and need to format 0x2p+E
// instead of 0x1.Mp+E
bool carry = false;
// see if we need to trim and round
if(ndigits > formatter.Precision)
{
int removedigs = ndigits - formatter.Precision;
// if we're removing all digits, just check the first to see if it should be
// rounded up or down
if(removedigs == ndigits)
{
ndigits = 0;
// all hex digits are above '8' in ascii order, so we can do just one comparison
carry = (digits[0] >= '8');
}
else
{
// remove the specified number of digits
ndigits -= removedigs;
// round up the last digit (continually rolling up if necessary)
// note this will look 'ahead' into the last removed digits at first
carry = true;
for(int i = ndigits - 1; i >= 0; i--)
{
// should we round up?
if(digits[i + 1] >= '8')
{
digits[i + 1] = 0;
// unless current digit is an f, we can just increment it and stop
if(digits[i] != 'f' && digits[i] != 'F')
{
if(digits[i] != '9')
digits[i]++;
else
digits[i] = uppercaseDigits ? 'A' : 'a';
carry = false;
break;
}
// continue (carry to next digit)
}
else
{
// didn't need to round up, everything's fine.
carry = false;
break;
}
// trim off a digit (was an f/F)
ndigits--;
continue;
}
}
}
if(digits[0] == '0' && !carry && ndigits == 0)
{
// if we rounded off to a 0.0, print it with special handling
PrintFloat0(e, f, a, uppercaseDigits, formatter, prepend, output, actualsize, end);
}
int padtrailing0s = formatter.Precision - ndigits;
{
int numwidth = 0;
// first calculate the width of the produced output, so we can calculate any padding
numwidth = 3; // 0x1
numwidth += ndigits; // post-decimal digits
if(ndigits > 0 || (formatter.Flags & AlternateForm) || padtrailing0s > 0)
numwidth++; // '.'
numwidth += padtrailing0s;
numwidth += 2; // 'p+' or 'p-'
if(exponent >= 0xff || exponent <= -0xff)
numwidth += 3;
else if(exponent >= 0xf || exponent <= -0xf)
numwidth += 2;
else
numwidth += 1;
if(prepend)
numwidth++; // +, - or ' '
int padlen = 0;
if(formatter.Width != FormatterParams::NoWidth && formatter.Width > numwidth)
padlen = formatter.Width - numwidth;
// pad with 0s or ' 's and insert the sign character
if(formatter.Flags & PadZeroes)
{
if(a)
appendstring(output, actualsize, end, uppercaseDigits ? "0X" : "0x");
if(prepend)
addchar(output, actualsize, end, prepend);
addchars(output, actualsize, end, size_t(padlen), '0');
}
else if(padlen > 0 && (formatter.Flags & LeftJustify) == 0)
{
addchars(output, actualsize, end, size_t(padlen), ' ');
if(prepend)
addchar(output, actualsize, end, prepend);
if(a)
appendstring(output, actualsize, end, uppercaseDigits ? "0X" : "0x");
}
else
{
if(prepend)
addchar(output, actualsize, end, prepend);
if(a)
appendstring(output, actualsize, end, uppercaseDigits ? "0X" : "0x");
}
if(carry)
addchar(output, actualsize, end, '2');
else
addchar(output, actualsize, end, '1');
// insert the decimals
if(ndigits > 0 || (formatter.Flags & AlternateForm) || padtrailing0s > 0)
addchar(output, actualsize, end, '.');
for(int i = 0; i < ndigits; i++)
addchar(output, actualsize, end, digits[i]);
// add the trailing 0s here
if(padtrailing0s > 0)
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
// print the p+XXX exponential
addchar(output, actualsize, end, uppercaseDigits ? 'P' : 'p');
if(exponent >= 0)
addchar(output, actualsize, end, '+');
else
addchar(output, actualsize, end, '-');
int exponaccum = exponent >= 0 ? exponent : -exponent;
if(exponaccum >= 1000)
addchar(output, actualsize, end, '0' + char(exponaccum / 1000));
exponaccum %= 1000;
if(exponaccum >= 100)
addchar(output, actualsize, end, '0' + char(exponaccum / 100));
exponaccum %= 100;
if(exponaccum >= 10)
addchar(output, actualsize, end, '0' + char(exponaccum / 10));
exponaccum %= 10;
addchar(output, actualsize, end, '0' + char(exponaccum));
if(padlen > 0 && (formatter.Flags & LeftJustify))
{
addchars(output, actualsize, end, size_t(padlen), ' ');
}
}
}
else
{
// call out to grisu2 to generate digits + exponent
char digits[18] = {0};
int K = 0;
int ndigits = grisu2(mantissa, exponent, digits, K);
// this is the decimal exponent (ie. 0 if the digits are 1.2345)
int expon = K + ndigits - 1;
// number of digits after the decimal
int decdigits = ndigits - expon - 1;
// for exponential form, this is always 1 less than the total number of digits
if(e)
decdigits = RDCMAX(0, ndigits - 1);
// see if we need to trim some digits (for %g, the precision is the number of
// significant figures which is just ndigits at the moment, will be padded with 0s
// later).
if(decdigits > formatter.Precision || (g && ndigits > formatter.Precision))
{
int removedigs = decdigits - formatter.Precision;
if(g)
removedigs = RDCMAX(0, ndigits - formatter.Precision);
// if we're removing all digits, just check the first to see if it should be
// rounded up or down
if(removedigs == ndigits)
{
ndigits = 1;
if(digits[0] < '5')
{
digits[0] = '0';
}
else
{
// round up to "1" on the next exponent
digits[0] = '1';
expon++;
}
}
else if(removedigs > ndigits)
{
ndigits = 1;
digits[0] = '0';
expon = 0;
}
else
{
// remove the specified number of digits
ndigits -= removedigs;
// round up the last digit (continually rolling up if necessary)
// note this will look 'ahead' into the last removed digits at first
bool carry = true;
for(int i = ndigits - 1; i >= 0; i--)
{
// should we round up?
if(digits[i + 1] >= '5')
{
digits[i + 1] = 0;
// unless current digit is a 9, we can just increment it and stop
if(digits[i] < '9')
{
digits[i]++;
carry = false;
break;
}
// continue (carry to next digit)
}
else
{
// didn't need to round up, everything's fine.
carry = false;
break;
}
// trim off a digit (was a 9)
ndigits--;
continue;
}
// we only get here with carry still true if digits are 9999999
if(carry)
{
// round up to "1" on the next exponent
ndigits = 1;
digits[0] = '1';
expon++;
}
}
}
// recalculate decimal digits with new ndigits
decdigits = ndigits - expon - 1;
if(e)
decdigits = RDCMAX(0, ndigits - 1);
// number of trailing 0s we need to pad after decimal point determined by
// the precision
int padtrailing0s = formatter.Precision - RDCMAX(0, decdigits);
if(g)
{
// for %g if the exponent is too far out of range, we revert to exponential form
if(expon >= formatter.Precision || expon < -4)
{
e = true;
// if not alternate form, all trailing 0 digits are removed and there is no padding.
if((formatter.Flags & AlternateForm) == 0)
{
while(ndigits > 1 && digits[ndigits - 1] == '0')
ndigits--;
padtrailing0s = 0;
}
else
padtrailing0s = formatter.Precision - RDCMAX(0, ndigits);
}
else
{
padtrailing0s = formatter.Precision - RDCMAX(0, ndigits);
}
}
// exponential display
if(e)
{
int numwidth = 0;
// first calculate the width of the produced output, so we can calculate any padding
numwidth = ndigits; // digits
if(ndigits > 1 || (formatter.Flags & AlternateForm) || padtrailing0s > 0)
numwidth++; // '.'
numwidth += padtrailing0s;
numwidth += 2; // 'e+' or 'e-'
if(expon >= 1000 || expon <= -1000)
numwidth += 4;
else if(expon >= 100 || expon <= -100)
numwidth += 3;
else
numwidth += 2;
if(prepend)
numwidth++; // +, - or ' '
int padlen = 0;
if(formatter.Width != FormatterParams::NoWidth && formatter.Width > numwidth)
padlen = formatter.Width - numwidth;
// pad with 0s or ' 's and insert the sign character
if(formatter.Flags & PadZeroes)
{
if(prepend)
addchar(output, actualsize, end, prepend);
addchars(output, actualsize, end, size_t(padlen), '0');
}
else if(padlen > 0 && (formatter.Flags & LeftJustify) == 0)
{
addchars(output, actualsize, end, size_t(padlen), ' ');
if(prepend)
addchar(output, actualsize, end, prepend);
}
else
{
if(prepend)
addchar(output, actualsize, end, prepend);
}
// insert the mantissa as a 1.23456 decimal
addchar(output, actualsize, end, digits[0]);
if(ndigits > 1 || (formatter.Flags & AlternateForm) || padtrailing0s > 0)
addchar(output, actualsize, end, '.');
for(int i = 1; i < ndigits; i++)
addchar(output, actualsize, end, digits[i]);
// add the trailing 0s here
if(padtrailing0s > 0)
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
// print the e-XXX exponential
addchar(output, actualsize, end, uppercaseDigits ? 'E' : 'e');
if(expon >= 0)
addchar(output, actualsize, end, '+');
else
addchar(output, actualsize, end, '-');
int exponaccum = expon >= 0 ? expon : -expon;
if(exponaccum >= 1000)
addchar(output, actualsize, end, '0' + char(exponaccum / 1000));
exponaccum %= 1000;
if(exponaccum >= 100)
addchar(output, actualsize, end, '0' + char(exponaccum / 100));
exponaccum %= 100;
addchar(output, actualsize, end, '0' + char(exponaccum / 10));
exponaccum %= 10;
addchar(output, actualsize, end, '0' + char(exponaccum));
if(padlen > 0 && (formatter.Flags & LeftJustify))
{
addchars(output, actualsize, end, size_t(padlen), ' ');
}
}
else if(digits[0] == '0' && ndigits == 1)
{
// if we rounded off to a 0.0, print it with special handling
PrintFloat0(e, f, a, uppercaseDigits, formatter, prepend, output, actualsize, end);
}
else
{
// we're printing as a normal decimal, e.g. 12345.6789
// if %g and not in alternate form, all 0s after the decimal point are stripped
if(g && (formatter.Flags & AlternateForm) == 0)
while(ndigits > 1 && ndigits - 1 > expon && digits[ndigits - 1] == '0')
ndigits--;
int numwidth = 0;
// first calculate the width of the produced output, so we can calculate any padding
// always all digits are printed (after trailing 0s optionally removed above)
numwidth = ndigits;
if(prepend)
numwidth++; // prefix +, - or ' '
// if the exponent is exactly the number of digits we have, we have one 0 to pad
// before the decimal point, and special handling of whether to display the decimal
// point for %g. (note that exponent 0 is mantissa x 10^0 which is 1.2345
if(expon == ndigits)
{
numwidth++; // 0 before decimal place
// if in alternate form for %g we print a . and any trailing 0s necessary to make
// up the precision (number of significant figures)
if(g && (formatter.Flags & AlternateForm))
{
numwidth++; // .
if(padtrailing0s > 1)
numwidth += (padtrailing0s - 1);
}
else if(!g)
{
// otherwise we only print the . if alternate form is specified or we need to
// print trailing 0s
if(padtrailing0s > 0 || (formatter.Flags & AlternateForm))
numwidth++; // .
if(padtrailing0s > 0)
numwidth += padtrailing0s;
}
}
// exponent greater than ndigits means we have padding before the decimal place
// and no values after the decimal place
else if(expon > ndigits)
{
numwidth += (expon + 1 - ndigits); // 0s between digits and decimal place
if(!g || (formatter.Flags & AlternateForm))
numwidth++; // .
if(padtrailing0s > 0 && (!g || (formatter.Flags & AlternateForm)))
numwidth += padtrailing0s;
}
else if(expon >= 0)
{
// expon < ndigits is true here
if(expon < ndigits - 1 || !g || (formatter.Flags & AlternateForm))
numwidth++; // .
if(g && (formatter.Flags & AlwaysDecimal))
numwidth += 2; // .0
if(padtrailing0s > 0 && (!g || (formatter.Flags & AlternateForm)))
numwidth += padtrailing0s;
}
else // if(expon < 0)
{
numwidth += 2; // 0.;
numwidth += (-1 - expon); // 0s before digits
if(!g || (formatter.Flags & AlternateForm))
numwidth += padtrailing0s;
}
int padlen = 0;
// calculate padding and print it (0s or ' 's) with the sign character
if(formatter.Width != FormatterParams::NoWidth && formatter.Width > numwidth)
padlen = formatter.Width - numwidth;
if(formatter.Flags & PadZeroes)
{
if(prepend)
addchar(output, actualsize, end, prepend);
addchars(output, actualsize, end, size_t(padlen), '0');
}
else if(padlen > 0 && (formatter.Flags & LeftJustify) == 0)
{
addchars(output, actualsize, end, size_t(padlen), ' ');
if(prepend)
addchar(output, actualsize, end, prepend);
}
else
{
if(prepend)
addchar(output, actualsize, end, prepend);
}
// if the exponent is greater than 0 we have to handle padding,
// placing it correctly, whether to show the decimal place or not, etc
if(expon >= 0)
{
// print the digits, adding the . at the right column, as long as it's not
// after the last column AND we are in %g that's not alternate form (ie.
// trailing 0s and . are stripped)
for(int i = 0; i < ndigits; i++)
{
addchar(output, actualsize, end, digits[i]);
if(i == expon)
{
if(i < ndigits - 1 || !g || (formatter.Flags & AlternateForm))
addchar(output, actualsize, end, '.');
}
}
// handle printing trailing 0s here as well as a trailing. if it
// wasn't printed above, and is needed for the print form.
if(expon == ndigits)
{
addchar(output, actualsize, end, '0');
if(g && (formatter.Flags & AlternateForm))
{
addchar(output, actualsize, end, '.');
if(padtrailing0s > 1)
addchars(output, actualsize, end, size_t(padtrailing0s - 1), '0');
}
else if(!g)
{
if(padtrailing0s > 0 || (formatter.Flags & AlternateForm))
addchar(output, actualsize, end, '.');
if(padtrailing0s > 0)
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
}
else if(formatter.Flags & AlwaysDecimal)
{
addchar(output, actualsize, end, '.');
addchar(output, actualsize, end, '0');
}
}
else if(expon > ndigits)
{
addchars(output, actualsize, end, size_t(expon + 1 - ndigits), '0');
if(!g || (formatter.Flags & AlternateForm))
addchar(output, actualsize, end, '.');
if(padtrailing0s > 0 && (!g || (formatter.Flags & AlternateForm)))
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
if(g && (formatter.Flags & AlwaysDecimal))
{
addchar(output, actualsize, end, '.');
addchar(output, actualsize, end, '0');
}
}
else
{
if(padtrailing0s > 0 && (!g || (formatter.Flags & AlternateForm)))
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
if(ndigits - 1 <= expon && g && (formatter.Flags & AlwaysDecimal))
{
addchar(output, actualsize, end, '.');
addchar(output, actualsize, end, '0');
}
}
}
// if exponent is less than 0 it's much easier - just print the number as
// digits at the right column, then any trailing 0s necessary
else
{
appendstring(output, actualsize, end, "0.");
addchars(output, actualsize, end, size_t(-1 - expon), '0');
appendstring(output, actualsize, end, digits, size_t(ndigits));
if(padtrailing0s > 0 && (!g || (formatter.Flags & AlternateForm)))
addchars(output, actualsize, end, size_t(padtrailing0s), '0');
}
if(padlen > 0 && (formatter.Flags & LeftJustify))
{
addchars(output, actualsize, end, size_t(padlen), ' ');
}
}
}
}