in src/CalcManager/Ratpack/conv.cpp [1076:1264]
wstring NumberToString(_Inout_ PNUMBER& pnum, NumberFormat format, uint32_t radix, int32_t precision)
{
stripzeroesnum(pnum, precision + 2);
int32_t length = pnum->cdigit;
int32_t exponent = pnum->exp + length; // Actual number of digits to the left of decimal
NumberFormat oldFormat = format;
if (exponent > precision && format == NumberFormat::Float)
{
// Force scientific mode to prevent user from assuming 33rd digit is exact.
format = NumberFormat::Scientific;
}
// Make length small enough to fit in pret.
if (length > precision)
{
length = precision;
}
// If there is a chance a round has to occur, round.
// - if number is zero no rounding
// - if number of digits is less than the maximum output no rounding
PNUMBER round = nullptr;
if (!zernum(pnum) && (pnum->cdigit >= precision || (length - exponent > precision && exponent >= -MAX_ZEROS_AFTER_DECIMAL)))
{
// Otherwise round.
round = i32tonum(radix, radix);
divnum(&round, num_two, radix, precision);
// Make round number exponent one below the LSD for the number.
if (exponent > 0 || format == NumberFormat::Float)
{
round->exp = pnum->exp + pnum->cdigit - round->cdigit - precision;
}
else
{
round->exp = pnum->exp + pnum->cdigit - round->cdigit - precision - exponent;
length = precision + exponent;
}
round->sign = pnum->sign;
}
if (format == NumberFormat::Float)
{
// Figure out if the exponent will fill more space than the non-exponent field.
if ((length - exponent > precision) || (exponent > precision + 3))
{
if (exponent >= -MAX_ZEROS_AFTER_DECIMAL)
{
round->exp -= exponent;
length = precision + exponent;
}
else
{
// Case where too many zeros are to the right or left of the
// decimal pt. And we are forced to switch to scientific form.
format = NumberFormat::Scientific;
}
}
else if (length + abs(exponent) < precision && round)
{
// Minimum loss of precision occurs with listing leading zeros
// if we need to make room for zeros sacrifice some digits.
round->exp -= exponent;
}
}
if (round != nullptr)
{
addnum(&pnum, round, radix);
int32_t offset = (pnum->cdigit + pnum->exp) - (round->cdigit + round->exp);
destroynum(round);
if (stripzeroesnum(pnum, offset))
{
// WARNING: nesting/recursion, too much has been changed, need to
// re-figure format.
return NumberToString(pnum, oldFormat, radix, precision);
}
}
else
{
stripzeroesnum(pnum, precision);
}
// Set up all the post rounding stuff.
bool useSciForm = false;
int32_t eout = exponent - 1; // Displayed exponent.
MANTTYPE* pmant = pnum->mant + pnum->cdigit - 1;
// Case where too many digits are to the left of the decimal or
// NumberFormat::Scientific or NumberFormat::Engineering was specified.
if ((format == NumberFormat::Scientific) || (format == NumberFormat::Engineering))
{
useSciForm = true;
if (eout != 0)
{
if (format == NumberFormat::Engineering)
{
exponent = (eout % 3);
eout -= exponent;
exponent++;
// Fix the case where 0.02e-3 should really be 2.e-6 etc.
if (exponent < 0)
{
exponent += 3;
eout -= 3;
}
}
else
{
exponent = 1;
}
}
}
else
{
eout = 0;
}
// Begin building the result string
wstring result;
// Make sure negative zeros aren't allowed.
if ((pnum->sign == -1) && (length > 0))
{
result = L'-';
}
if (exponent <= 0 && !useSciForm)
{
result += L'0';
result += g_decimalSeparator;
// Used up a digit unaccounted for.
}
while (exponent < 0)
{
result += L'0';
exponent++;
}
while (length > 0)
{
exponent--;
result += DIGITS[*pmant--];
length--;
// Be more regular in using a decimal point.
if (exponent == 0)
{
result += g_decimalSeparator;
}
}
while (exponent > 0)
{
result += L'0';
exponent--;
// Be more regular in using a decimal point.
if (exponent == 0)
{
result += g_decimalSeparator;
}
}
if (useSciForm)
{
result += (radix == 10 ? L'e' : L'^');
result += (eout < 0 ? L'-' : L'+');
eout = abs(eout);
wstring expString{};
do
{
expString += DIGITS[eout % radix];
eout /= radix;
} while (eout > 0);
result.insert(result.end(), expString.crbegin(), expString.crend());
}
// Remove trailing decimal
if (!result.empty() && result.back() == g_decimalSeparator)
{
result.pop_back();
}
return result;
}