[poincare] Fix Decimal::convertToText

This commit is contained in:
Émilie Feral
2018-04-20 17:40:24 +02:00
committed by EmilieNumworks
parent bffdb59847
commit 1669bee2f6
3 changed files with 39 additions and 42 deletions

View File

@@ -41,7 +41,9 @@ private:
Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> Expression * templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const;
constexpr static int k_maxLength = 15;
int convertToText(char * buffer, int bufferSize, PrintFloat::Mode mode, int numberOfSignificantDigits) const;
// Worst case is -1.2345678901234E-1000
constexpr static int k_maxBufferSize = PrintFloat::k_numberOfStoredSignificantDigits+1+1+1+1+4+1;
Integer m_mantissa;
int m_exponent;
};

View File

@@ -99,7 +99,7 @@ template<typename T> Expression * Decimal::templatedApproximate(Context& context
return new Complex<T>(Complex<T>::Float(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1))));
}
int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
int Decimal::convertToText(char * buffer, int bufferSize, PrintFloat::Mode mode, int numberOfSignificantDigits) const {
if (bufferSize == 0) {
return -1;
}
@@ -111,28 +111,36 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignif
buffer[currentChar] = 0;
return currentChar;
}
char tempBuffer[200];
int mantissaLength = m_mantissa.writeTextInBuffer(tempBuffer, 200);
char tempBuffer[PrintFloat::k_numberOfStoredSignificantDigits+1];
// truncate the integer if m_mantissa > 10^numberOfSignificantDigits-1
Integer absMantissa = m_mantissa;
absMantissa.setNegative(false);
while (Integer::NaturalOrder(absMantissa, Integer((int64_t)std::pow(10.0, numberOfSignificantDigits))) >= 0) {
absMantissa = Integer::Division(absMantissa, Integer(10)).quotient;
}
int mantissaLength = absMantissa.writeTextInBuffer(tempBuffer, PrintFloat::k_numberOfStoredSignificantDigits+1);
if (strcmp(tempBuffer, "undef") == 0) {
strlcpy(buffer, tempBuffer, bufferSize);
return mantissaLength;
}
int nbOfDigitsInMantissaWithoutSign = numberOfDigitsInMantissaWithoutSign();
int numberOfRequiredDigits = nbOfDigitsInMantissaWithoutSign > m_exponent ? nbOfDigitsInMantissaWithoutSign : m_exponent;
numberOfRequiredDigits = m_exponent < 0 ? 1+nbOfDigitsInMantissaWithoutSign-m_exponent : numberOfRequiredDigits;
int numberOfRequiredDigits = mantissaLength;
if (mode == PrintFloat::Mode::Decimal) {
numberOfRequiredDigits = mantissaLength > m_exponent ? mantissaLength : m_exponent;
numberOfRequiredDigits = m_exponent < 0 ? 1+mantissaLength-m_exponent : numberOfRequiredDigits;
}
if (m_mantissa.isNegative()) {
buffer[currentChar++] = '-';
if (currentChar >= bufferSize-1) { return bufferSize-1; }
}
/* Case 0: the number would be too long if we print it as a natural decimal */
if (numberOfRequiredDigits > k_maxLength) {
if (nbOfDigitsInMantissaWithoutSign == 1) {
currentChar += strlcpy(buffer, tempBuffer, bufferSize);
if (numberOfRequiredDigits > PrintFloat::k_numberOfStoredSignificantDigits || mode == PrintFloat::Mode::Scientific) {
if (mantissaLength == 1) {
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
} else {
currentChar++;
int decimalMarkerPosition = currentChar;
if (currentChar >= bufferSize-1) { return bufferSize-1; }
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
int decimalMarkerPosition = 1;
if (buffer[1] == '-') {
decimalMarkerPosition++;
buffer[0] = buffer[1];
}
buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition];
buffer[decimalMarkerPosition] = '.';
}
@@ -144,12 +152,9 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignif
currentChar += Integer(m_exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar);
return currentChar;
}
/* Case 2: Print a natural decimal number */
/* Case 1: Print a natural decimal number */
int deltaCharMantissa = m_exponent < 0 ? -m_exponent+1 : 0;
strlcpy(buffer+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa);
if (m_mantissa.isNegative()) {
buffer[currentChar++] = '-';
}
strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar);
if (m_exponent < 0) {
for (int i = 0; i <= -m_exponent; i++) {
if (currentChar >= bufferSize-1) { return bufferSize-1; }
@@ -160,33 +165,19 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignif
buffer[currentChar++] = '0';
}
}
/* If mantissa is negative, m_mantissa.writeTextInBuffer is going to add an
* unwanted '-' in place of the temp char. We store it to replace it back
* after calling m_mantissa.writeTextInBuffer. */
char tempChar = 0;
int tempCharPosition = 0;
if (m_mantissa.isNegative()) {
currentChar--;
tempChar = buffer[currentChar];
tempCharPosition = currentChar;
}
currentChar += mantissaLength;
if (m_mantissa.isNegative()) { // replace the temp char back
buffer[tempCharPosition] = tempChar;
}
int currentExponent = m_mantissa.isNegative() ? currentChar-2 : currentChar-1;
if (m_exponent >= 0 && m_exponent < currentExponent) {
if (m_exponent >= 0 && m_exponent < mantissaLength-1) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
int decimalMarkerPosition = m_mantissa.isNegative() ? m_exponent +1 : m_exponent;
int decimalMarkerPosition = m_mantissa.isNegative() ? m_exponent + 1 : m_exponent;
for (int i = currentChar-1; i > decimalMarkerPosition; i--) {
buffer[i+1] = buffer[i];
}
buffer[decimalMarkerPosition+1] = '.';
currentChar++;
}
if (m_exponent >= 0 && m_exponent > currentExponent) {
int decimalMarkerPosition = m_mantissa.isNegative() ? m_exponent+1 : m_exponent;
for (int i = currentChar-1; i < decimalMarkerPosition; i++) {
if (m_exponent >= 0 && m_exponent > mantissaLength-1) {
int endMarkerPosition = m_mantissa.isNegative() ? m_exponent+1 : m_exponent;
for (int i = currentChar-1; i < endMarkerPosition; i++) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar++] = '0';
}
@@ -195,6 +186,10 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignif
return currentChar;
}
int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
return convertToText(buffer, bufferSize, PrintFloat::Mode::Decimal, PrintFloat::k_numberOfStoredSignificantDigits);
}
bool Decimal::needParenthesisWithParent(const Expression * e) const {
if (sign() == Sign::Positive) {
return false;
@@ -204,8 +199,8 @@ bool Decimal::needParenthesisWithParent(const Expression * e) const {
}
ExpressionLayout * Decimal::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const {
char buffer[255];
int numberOfChars = writeTextInBuffer(buffer, 255);
char buffer[k_maxBufferSize];
int numberOfChars = convertToText(buffer, k_maxBufferSize, floatDisplayMode, PrintFloat::k_numberOfStoredSignificantDigits);
return new StringLayout(buffer, numberOfChars);
}

View File

@@ -157,7 +157,7 @@ QUIZ_CASE(poincare_decimal_to_text) {
assert_expression_prints_to(&e10, "0.12345");
Decimal e11(1);
assert_expression_prints_to(&e11, "1");
Decimal e12(0.9999999999999995);
Decimal e12(0.9999999999999996);
assert_expression_prints_to(&e12, "1");
Decimal e13(0.999999999999995);
assert_expression_prints_to(&e13, "9.99999999999995E-1");