diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index 3bc70229d..0cbb85d3a 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -1,50 +1,78 @@ #ifndef POINCARE_DECIMAL_H #define POINCARE_DECIMAL_H -#include #include namespace Poincare { /* A decimal as 0.01234 is stored that way: - * - m_mantissa = 1234 - * - m_exponent = -2 + * - bool m_negative = false + * - int m_exponent = -2 + * - int m_numberOfDigitsInMantissa = 1 + * - native_uint_t m_mantissa[] = { 1234 } */ -class Decimal : public StaticHierarchy<0> { +class DecimalNode : public NumberNode { public: - static int exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative); - static Integer mantissa(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative); - Decimal(Integer mantissa, int exponent); - template Decimal(T f); - int exponent() const { return m_exponent; } - Integer mantissa() const { return m_mantissa; } - // Expression subclassing - Type type() const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - Sign sign() const override { return m_mantissa.isNegative() ? Sign::Negative : Sign::Positive; } - constexpr static int k_maxExponentLength = 4; -private: - constexpr static double k_biggestMantissaFromDouble = 999999999999999; - constexpr static int k_maxDoubleExponent = 308; - /* Comparison */ + void setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative); + + NaturalIntegerPointer mantissa() const; + + // TreeNode + size_t size() const override { return sizeof(DecimalNode); } +#if TREE_LOG + const char * description() const override { return "Decimal"; } +#endif + + // Properties + Type type() const override { return Type::Decimal; } + Sign sign() const override { return m_negative ? Sign::Negative : Sign::Positive; } + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + + // Comparison int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; - /* Layout */ - bool needsParenthesisWithParent(SerializableNode * parentNode) const override; - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - /* Simplification */ + + // Simplification ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; ExpressionReference shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; - /* Evaluation */ - EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; - int convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const; + // Layout + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; +private: // Worst case is -1.2345678901234E-1000 constexpr static int k_maxBufferSize = PrintFloat::k_numberOfStoredSignificantDigits+1+1+1+1+4+1; - Integer m_mantissa; + int convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const; + template EvaluationReference templatedApproximate() const; + + bool m_negative; int m_exponent; + size_t m_numberOfDigitsInMantissa; + native_uint_t m_mantissa[0]; +}; + +class DecimalReference : public NumberReference { +friend class Number; +public: + static int exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative); + DecimalReference(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent); + constexpr static int k_maxExponentLength = 4; +private: + DecimalReference(TreeNode * n) : NumberReference(n) {} + template DecimalReference(T f); + DecimalReference(IntegerReference m, int e); + DecimalReference(size_t size) : NumberReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(size); + m_identifier = node->identifier(); + } }; } diff --git a/poincare/include/poincare/expression_reference.h b/poincare/include/poincare/expression_reference.h index 56505ae24..cc87dbb55 100644 --- a/poincare/include/poincare/expression_reference.h +++ b/poincare/include/poincare/expression_reference.h @@ -142,4 +142,4 @@ private: } -#endif \ No newline at end of file +#endif diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 1c3b8a72d..1a5de6389 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -9,7 +11,227 @@ namespace Poincare { -int Decimal::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) { +void removeZeroAtTheEnd(IntegerReference * i) { + if (i->isZero()) { + return; + } + IntegerReference base = IntegerReference(10); + IntegerDivisionReference d = IntegerReference::Division(*i, base); + while (d.remainder.isZero()) { + *i = d.quotient; + d = IntegerReference::Division(*i, base); + } +} + +void DecimalNode::setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative) { + m_negative = negative; + m_exponent = exponent; + m_numberOfDigitsInMantissa = mantissaSize; + memcpy(m_mantissa, mantissaDigits, mantissaSize*sizeof(native_uint_t)); +} + +NaturalIntegerPointer DecimalNode::mantissa() const { + return NaturalIntegerPointer((native_uint_t *)m_mantissa, m_numberOfDigitsInMantissa); +} + +int DecimalNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { + assert(e->type() == Type::Decimal); + const DecimalNode * other = static_cast(e); + if (m_negative && !other->m_negative) { + return -1; + } + if (!m_negative && other->m_negative) { + return 1; + } + assert(m_negative == other->m_negative); + int unsignedComparison = 0; + if (m_exponent < other->m_exponent) { + unsignedComparison = -1; + } else if (m_exponent > other->m_exponent) { + unsignedComparison = 1; + } else { + assert(m_exponent == other->m_exponent); + NaturalIntegerPointer m = mantissa(); + NaturalIntegerPointer otherM = other->mantissa(); + unsignedComparison = NaturalIntegerAbstract::ucmp(&m, &otherM); + } + return ((int)sign())*unsignedComparison; +} + +ExpressionReference DecimalNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { + ExpressionReference e = ExpressionNode::shallowReduce(context, angleUnit); + if (e.node() != this) { + return e; + } + ExpressionReference reference(this); + NaturalIntegerPointer m = mantissa(); + IntegerReference numerator(&m); + removeZeroAtTheEnd(&numerator); + int numberOfDigits = IntegerReference::NumberOfBase10Digits(numerator); + IntegerReference denominator(1); + if (m_exponent >= numberOfDigits-1) { + numerator = IntegerReference::Multiplication(numerator, IntegerReference::Power(IntegerReference(10), IntegerReference(m_exponent-numberOfDigits+1))); + } else { + denominator = IntegerReference::Power(IntegerReference(10), IntegerReference(numberOfDigits-1-m_exponent)); + } + // Do not reduce decimal to rational if the exponent is too big or too small. + if (numerator.isInfinity()) { + assert(!denominator.isInfinity()); + return InfinityReference(m_negative); + } + if (denominator.isInfinity()) { + assert(!denominator.isInfinity()); + return RationalReference(0); + } + numerator.setNegative(m_negative); + return RationalReference(numerator, denominator); +} + +ExpressionReference DecimalNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { + ExpressionReference reference(this); + if (m_negative) { + m_negative = false; + return OppositeReference(reference); + } + return reference; +} + +bool DecimalNode::needsParenthesisWithParent(SerializableNode * parentNode) const { + if (!m_negative) { + return false; + } + Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Power, Type::Factorial}; + return static_cast(parentNode)->isOfType(types, 7); +} + +LayoutRef DecimalNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + char buffer[k_maxBufferSize]; + int numberOfChars = convertToText(buffer, k_maxBufferSize, floatDisplayMode, numberOfSignificantDigits); + return LayoutEngine::createStringLayout(buffer, numberOfChars); +} + +int DecimalNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return convertToText(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits); +} + +int DecimalNode::convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int currentChar = 0; + if (currentChar >= bufferSize-1) { return bufferSize-1; } + if (mantissa().isZero()) { + buffer[currentChar++] = '0'; + buffer[currentChar] = 0; + return currentChar; + } + int exponent = m_exponent; + char tempBuffer[PrintFloat::k_numberOfStoredSignificantDigits+1]; + // Round the integer if m_mantissa > 10^numberOfSignificantDigits-1 + NaturalIntegerPointer m = mantissa(); + IntegerReference mantissaRef(&m); + int numberOfDigitsInMantissa = IntegerReference::NumberOfBase10Digits(mantissaRef); + if (numberOfDigitsInMantissa > numberOfSignificantDigits) { + IntegerDivisionReference d = IntegerReference::Division(mantissaRef, IntegerReference((int64_t)std::pow(10.0, numberOfDigitsInMantissa - numberOfSignificantDigits))); + mantissaRef = d.quotient; + if (IntegerReference::NaturalOrder(d.remainder, IntegerReference((int64_t)(5.0*std::pow(10.0, numberOfDigitsInMantissa-numberOfSignificantDigits-1)))) >= 0) { + mantissaRef = IntegerReference::Addition(mantissaRef, IntegerReference(1)); + // if 9999 was rounded to 10000, we need to update exponent and mantissa + if (IntegerReference::NumberOfBase10Digits(mantissaRef) > numberOfSignificantDigits) { + exponent++; + mantissaRef = IntegerReference::Division(mantissaRef, IntegerReference(10)).quotient; + } + } + removeZeroAtTheEnd(&mantissaRef); + } + if (m_negative) { + buffer[currentChar++] = '-'; + if (currentChar >= bufferSize-1) { return bufferSize-1; } + } + int mantissaLength = mantissaRef.writeTextInBuffer(tempBuffer, PrintFloat::k_numberOfStoredSignificantDigits+1, mode, numberOfSignificantDigits); + if (strcmp(tempBuffer, "inf") == 0) { + currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar); + return currentChar; + } + /* We force scientific mode if the number of digits before the dot is superior + * to the number of significant digits (ie with 4 significant digits, + * 12345 -> 1.235E4 or 12340 -> 1.234E4). */ + bool forceScientificMode = mode == Preferences::PrintFloatMode::Scientific || exponent >= numberOfSignificantDigits; + int numberOfRequiredDigits = mantissaLength; + if (!forceScientificMode) { + numberOfRequiredDigits = mantissaLength > exponent ? mantissaLength : exponent; + numberOfRequiredDigits = exponent < 0 ? mantissaLength-exponent : numberOfRequiredDigits; + } + /* Case 0: Scientific mode. Three cases: + * - the user chooses the scientific mode + * - the exponent is too big compared to the number of significant digits, so + * we force the scientific mode to avoid inventing digits + * - the number would be too long if we print it as a natural decimal */ + if (numberOfRequiredDigits > PrintFloat::k_numberOfStoredSignificantDigits || forceScientificMode) { + 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); + buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition]; + buffer[decimalMarkerPosition] = '.'; + } + if (exponent == 0) { + return currentChar; + } + if (currentChar >= bufferSize-1) { return bufferSize-1; } + buffer[currentChar++] = Ion::Charset::Exponent; + currentChar += IntegerReference(exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, mode, numberOfSignificantDigits); + return currentChar; + } + /* Case 1: Decimal mode */ + int deltaCharMantissa = exponent < 0 ? -exponent+1 : 0; + strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar); + if (exponent < 0) { + for (int i = 0; i <= -exponent; i++) { + if (currentChar >= bufferSize-1) { return bufferSize-1; } + if (i == 1) { + buffer[currentChar++] = '.'; + continue; + } + buffer[currentChar++] = '0'; + } + } + currentChar += mantissaLength; + if (exponent >= 0 && exponent < mantissaLength-1) { + if (currentChar+1 >= bufferSize-1) { return bufferSize-1; } + int decimalMarkerPosition = m_negative ? exponent + 1 : exponent; + for (int i = currentChar-1; i > decimalMarkerPosition; i--) { + buffer[i+1] = buffer[i]; + } + if (currentChar >= bufferSize-1) { return bufferSize-1; } + buffer[decimalMarkerPosition+1] = '.'; + currentChar++; + } + if (exponent >= 0 && exponent > mantissaLength-1) { + int endMarkerPosition = m_negative ? exponent+1 : exponent; + for (int i = currentChar-1; i < endMarkerPosition; i++) { + if (currentChar+1 >= bufferSize-1) { return bufferSize-1; } + buffer[currentChar++] = '0'; + } + } + if (currentChar >= bufferSize-1) { return bufferSize-1; } + buffer[currentChar] = 0; + return currentChar; +} + +template EvaluationReference DecimalNode::templatedApproximate() const { + NaturalIntegerPointer m = mantissa(); + T f = m.approximate(); + int numberOfDigits = NaturalIntegerAbstract::NumberOfBase10Digits(&m); + T result = f*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1)); + return ComplexReference(m_negative ? -result : result); +} + +int DecimalReference::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) { int base = 10; int exp = 0; for (int i = 0; i < exponentLength; i++) { @@ -42,238 +264,39 @@ int Decimal::exponent(const char * integralPart, int integralPartLength, const c return exp; } -void removeZeroAtTheEnd(Integer & i) { - if (i.isZero()) { - return; - } - Integer base = Integer(10); - IntegerDivision d = Integer::Division(i, base); - while (d.remainder.isZero()) { - i = d.quotient; - d = Integer::Division(i, base); - } -} - -Integer Decimal::mantissa(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative) { - Integer zero = Integer(0); - Integer base = Integer(10); - Integer numerator = Integer(integralPart, negative); +DecimalReference::DecimalReference(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent) { + IntegerReference zero(0); + IntegerReference base(10); + IntegerReference numerator(integralPart, integralPartLength, negative); for (int i = 0; i < fractionalPartLength; i++) { - numerator = Integer::Multiplication(numerator, base); - numerator = Integer::Addition(numerator, Integer(*fractionalPart-'0')); + numerator = IntegerReference::Multiplication(numerator, base); + numerator = IntegerReference::Addition(numerator, IntegerReference(*fractionalPart-'0')); fractionalPart++; } - return numerator; -} - -Decimal::Decimal(Integer mantissa, int exponent) : - m_mantissa(mantissa), - m_exponent(exponent) -{ + *this = DecimalReference(numerator, exponent); } template -Decimal::Decimal(T f) { - m_exponent = IEEE754::exponentBase10(f); - int64_t mantissaf = std::round((double)f * std::pow((double)10.0, (double)(-m_exponent+PrintFloat::k_numberOfStoredSignificantDigits+1))); - m_mantissa = Integer(mantissaf); +DecimalReference::DecimalReference(T f) { + assert(!std::isnan(f) && !std::isinf(f)); + int exp = IEEE754::exponentBase10(f); + int64_t mantissaf = std::round((double)f * std::pow((double)10.0, (double)(-exp+PrintFloat::k_numberOfStoredSignificantDigits+1))); + IntegerReference m(mantissaf); + *this= DecimalReference(IntegerReference(mantissaf), exp); } -Expression::Type Decimal::type() const { - return Type::Decimal; +DecimalReference::DecimalReference(IntegerReference m, int e) { + if (m.isAllocationFailure()) { + *this = DecimalReference(ExpressionNode::FailedAllocationStaticNode()); + return; + } + *this = DecimalReference(sizeof(DecimalNode)+sizeof(native_uint_t)*m.numberOfDigits()); + if (!node()->isAllocationFailure()) { + static_cast(node())->setValue(m.typedNode()->digits(), m.typedNode()->numberOfDigits(), e, m.isNegative()); + } } -Expression * Decimal::clone() const { - return new Decimal(m_mantissa, m_exponent); -} - -template EvaluationReference Decimal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - T m = m_mantissa.approximate(); - int numberOfDigits = Integer::numberOfDigitsWithoutSign(m_mantissa); - return new Complex(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1))); -} - -int Decimal::convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - int currentChar = 0; - if (currentChar >= bufferSize-1) { return bufferSize-1; } - if (m_mantissa.isZero()) { - buffer[currentChar++] = '0'; - buffer[currentChar] = 0; - return currentChar; - } - int exponent = m_exponent; - char tempBuffer[PrintFloat::k_numberOfStoredSignificantDigits+1]; - // Round the integer if m_mantissa > 10^numberOfSignificantDigits-1 - Integer absMantissa = m_mantissa; - absMantissa.setNegative(false); - int numberOfDigitsInMantissa = Integer::numberOfDigitsWithoutSign(m_mantissa); - if (numberOfDigitsInMantissa > numberOfSignificantDigits) { - IntegerDivision d = Integer::Division(absMantissa, Integer((int64_t)std::pow(10.0, numberOfDigitsInMantissa - numberOfSignificantDigits))); - absMantissa = d.quotient; - if (Integer::NaturalOrder(d.remainder, Integer((int64_t)(5.0*std::pow(10.0, numberOfDigitsInMantissa-numberOfSignificantDigits-1)))) >= 0) { - absMantissa = Integer::Addition(absMantissa, Integer(1)); - // if 9999 was rounded to 10000, we need to update exponent and mantissa - if (Integer::numberOfDigitsWithoutSign(absMantissa) > numberOfSignificantDigits) { - exponent++; - absMantissa = Integer::Division(absMantissa, Integer(10)).quotient; - } - } - removeZeroAtTheEnd(absMantissa); - } - int mantissaLength = absMantissa.writeTextInBuffer(tempBuffer, PrintFloat::k_numberOfStoredSignificantDigits+1); - if (strcmp(tempBuffer, "undef") == 0) { - currentChar = strlcpy(buffer, tempBuffer, bufferSize); - return currentChar; - } - /* We force scientific mode if the number of digits before the dot is superior - * to the number of significant digits (ie with 4 significant digits, - * 12345 -> 1.235E4 or 12340 -> 1.234E4). */ - bool forceScientificMode = mode == Preferences::PrintFloatMode::Scientific || exponent >= numberOfSignificantDigits; - int numberOfRequiredDigits = mantissaLength; - if (!forceScientificMode) { - numberOfRequiredDigits = mantissaLength > exponent ? mantissaLength : exponent; - numberOfRequiredDigits = exponent < 0 ? mantissaLength-exponent : numberOfRequiredDigits; - } - if (currentChar >= bufferSize-1) { return bufferSize-1; } - if (m_mantissa.isNegative()) { - buffer[currentChar++] = '-'; - if (currentChar >= bufferSize-1) { return bufferSize-1; } - } - /* Case 0: Scientific mode. Three cases: - * - the user chooses the scientific mode - * - the exponent is too big compared to the number of significant digits, so - * we force the scientific mode to avoid inventing digits - * - the number would be too long if we print it as a natural decimal */ - if (numberOfRequiredDigits > PrintFloat::k_numberOfStoredSignificantDigits || forceScientificMode) { - 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); - buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition]; - buffer[decimalMarkerPosition] = '.'; - } - if (exponent == 0) { - return currentChar; - } - if (currentChar >= bufferSize-1) { return bufferSize-1; } - buffer[currentChar++] = Ion::Charset::Exponent; - currentChar += Integer(exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar); - return currentChar; - } - /* Case 1: Decimal mode */ - int deltaCharMantissa = exponent < 0 ? -exponent+1 : 0; - strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar); - if (exponent < 0) { - for (int i = 0; i <= -exponent; i++) { - if (currentChar >= bufferSize-1) { return bufferSize-1; } - if (i == 1) { - buffer[currentChar++] = '.'; - continue; - } - buffer[currentChar++] = '0'; - } - } - currentChar += mantissaLength; - if (exponent >= 0 && exponent < mantissaLength-1) { - if (currentChar+1 >= bufferSize-1) { return bufferSize-1; } - int decimalMarkerPosition = m_mantissa.isNegative() ? exponent + 1 : exponent; - for (int i = currentChar-1; i > decimalMarkerPosition; i--) { - buffer[i+1] = buffer[i]; - } - if (currentChar >= bufferSize-1) { return bufferSize-1; } - buffer[decimalMarkerPosition+1] = '.'; - currentChar++; - } - if (exponent >= 0 && exponent > mantissaLength-1) { - int endMarkerPosition = m_mantissa.isNegative() ? exponent+1 : exponent; - for (int i = currentChar-1; i < endMarkerPosition; i++) { - if (currentChar+1 >= bufferSize-1) { return bufferSize-1; } - buffer[currentChar++] = '0'; - } - } - if (currentChar >= bufferSize-1) { return bufferSize-1; } - buffer[currentChar] = 0; - return currentChar; -} - -int Decimal::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return convertToText(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits); -} - -bool Decimal::needParenthesisWithParent(const Expression * e) const { - if (sign() == Sign::Positive) { - return false; - } - Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Power, Type::Factorial}; - return e->isOfType(types, 7); -} - -LayoutRef Decimal::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - char buffer[k_maxBufferSize]; - int numberOfChars = convertToText(buffer, k_maxBufferSize, floatDisplayMode, numberOfSignificantDigits); - return LayoutEngine::createStringLayout(buffer, numberOfChars); -} - -ExpressionReference Decimal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - Expression * e = Expression::shallowReduce(context, angleUnit); - if (e != this) { - return e; - } - // Do not reduce decimal to rational if the exponent is too big or too small. - if (m_exponent > k_maxDoubleExponent || m_exponent < -k_maxDoubleExponent) { - return this; // TODO: return new Infinite() ? RationalReference(0) ? - } - Integer numerator = m_mantissa; - removeZeroAtTheEnd(numerator); - int numberOfDigits = Integer::numberOfDigitsWithoutSign(numerator); - Integer denominator = Integer(1); - if (m_exponent >= numberOfDigits-1) { - numerator = Integer::Multiplication(numerator, Integer::Power(Integer(10), Integer(m_exponent-numberOfDigits+1))); - } else { - denominator = Integer::Power(Integer(10), Integer(numberOfDigits-1-m_exponent)); - } - return replaceWith(new Rational(numerator, denominator), true); -} - -Expression * Decimal::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { - if (m_mantissa.isNegative()) { - m_mantissa.setNegative(false); - Opposite * o = new Opposite(this, true); - return replaceWith(o, true); - } - return this; -} - -int Decimal::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { - assert(e->type() == Type::Decimal); - const Decimal * other = static_cast(e); - if (sign() == Sign::Negative && other->sign() == Sign::Positive) { - return -1; - } - if (sign() == Sign::Positive && other->sign() == Sign::Negative) { - return 1; - } - assert(sign() == other->sign()); - int unsignedComparison = 0; - if (exponent() < other->exponent()) { - unsignedComparison = -1; - } else if (exponent() > other->exponent()) { - unsignedComparison = 1; - } else { - assert(exponent() == other->exponent()); - unsignedComparison = Integer::NaturalOrder(mantissa(), other->mantissa()); - } - return ((int)sign())*unsignedComparison; -} - -template Decimal::Decimal(double); -template Decimal::Decimal(float); +template DecimalReference::DecimalReference(double); +template DecimalReference::DecimalReference(float); }