From 0eda414cdfa9ddfb326086e0428eee5aa5f2bdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 9 Aug 2018 10:54:34 +0200 Subject: [PATCH] [poincare] Fix Decimal --- poincare/include/poincare/decimal.h | 44 ++++++--- poincare/src/decimal.cpp | 144 +++++++++++++++------------- 2 files changed, 109 insertions(+), 79 deletions(-) diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index f541c0f83..adecb28f6 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -14,9 +14,19 @@ namespace Poincare { class DecimalNode : public NumberNode { public: - void setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative); + DecimalNode() : + m_negative(false), + m_exponent(0), + m_numberOfDigitsInMantissa(0) {} + + virtual void setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative); + + // Allocation Failure + static DecimalNode * FailedAllocationStaticNode(); + DecimalNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } NaturalIntegerPointer mantissa() const; + int exponent() const { return m_exponent; } // TreeNode size_t size() const override { return sizeof(DecimalNode); } @@ -40,13 +50,15 @@ public: int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; // Simplification - Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; + Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const override; + Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const override; + + // Serialization + bool needsParenthesesWithParent(const SerializationHelperInterface * e) const override; + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; // Layout - bool needsParenthesesWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int serialize(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; @@ -59,20 +71,30 @@ private: native_uint_t m_mantissa[0]; }; -class DecimalReference : public NumberReference { +class AllocationFailureDecimalNode : public AllocationFailureExpressionNode { +public: + void setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative) override {} +}; + +class Decimal : public Number { friend class Number; +friend class DecimalNode; 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); + Decimal(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent); + Decimal(const DecimalNode * node) : Number(node) {} 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() { + DecimalNode * node() const override { return static_cast(Number::node()); } + template Decimal(T f); + Decimal(Integer m, int e); + Decimal(size_t size) : Number(nullptr) { TreeNode * node = TreePool::sharedPool()->createTreeNode(size); m_identifier = node->identifier(); } + // Simplification + Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const; + Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index ebc88be12..a9b4c5ff9 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -11,15 +11,15 @@ namespace Poincare { -void removeZeroAtTheEnd(IntegerReference * i) { +void removeZeroAtTheEnd(Integer * i) { if (i->isZero()) { return; } - IntegerReference base = IntegerReference(10); - IntegerDivisionReference d = IntegerReference::Division(*i, base); + Integer base = Integer(10); + IntegerDivision d = Integer::Division(*i, base); while (d.remainder.isZero()) { *i = d.quotient; - d = IntegerReference::Division(*i, base); + d = Integer::Division(*i, base); } } @@ -30,6 +30,11 @@ void DecimalNode::setValue(native_uint_t * mantissaDigits, size_t mantissaSize, memcpy(m_mantissa, mantissaDigits, mantissaSize*sizeof(native_uint_t)); } +DecimalNode * DecimalNode::FailedAllocationStaticNode() { + static AllocationFailureDecimalNode failure; + return &failure; +} + NaturalIntegerPointer DecimalNode::mantissa() const { return NaturalIntegerPointer((native_uint_t *)m_mantissa, m_numberOfDigitsInMantissa); } @@ -58,50 +63,20 @@ int DecimalNode::simplificationOrderSameType(const ExpressionNode * e, bool canB return ((int)sign())*unsignedComparison; } -Expression DecimalNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - Expression e = ExpressionNode::shallowReduce(context, angleUnit); - if (e.node() != this) { - return e; - } - Expression 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); +Expression DecimalNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + return Decimal(this).shallowReduce(context, angleUnit); } -Expression DecimalNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { - Expression reference(this); - if (m_negative) { - m_negative = false; - return OppositeReference(reference); - } - return reference; +Expression DecimalNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const { + return Decimal(this).shallowBeautify(context, angleUnit); } -bool DecimalNode::needsParenthesesWithParent(SerializableNode * parentNode) const { +bool DecimalNode::needsParenthesesWithParent(const SerializationHelperInterface * e) 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); + return static_cast(e)->isOfType(types, 7); } LayoutRef DecimalNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -130,17 +105,17 @@ int DecimalNode::convertToText(char * buffer, int bufferSize, Preferences::Print 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); + Integer mantissaRef(&m); + int numberOfDigitsInMantissa = Integer::NumberOfBase10Digits(mantissaRef); if (numberOfDigitsInMantissa > numberOfSignificantDigits) { - IntegerDivisionReference d = IntegerReference::Division(mantissaRef, IntegerReference((int64_t)std::pow(10.0, numberOfDigitsInMantissa - numberOfSignificantDigits))); + IntegerDivision d = Integer::Division(mantissaRef, Integer((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 (Integer::NaturalOrder(d.remainder, Integer((int64_t)(5.0*std::pow(10.0, numberOfDigitsInMantissa-numberOfSignificantDigits-1)))) >= 0) { + mantissaRef = Integer::Addition(mantissaRef, Integer(1)); // if 9999 was rounded to 10000, we need to update exponent and mantissa - if (IntegerReference::NumberOfBase10Digits(mantissaRef) > numberOfSignificantDigits) { + if (Integer::NumberOfBase10Digits(mantissaRef) > numberOfSignificantDigits) { exponent++; - mantissaRef = IntegerReference::Division(mantissaRef, IntegerReference(10)).quotient; + mantissaRef = Integer::Division(mantissaRef, Integer(10)).quotient; } } removeZeroAtTheEnd(&mantissaRef); @@ -184,7 +159,7 @@ int DecimalNode::convertToText(char * buffer, int bufferSize, Preferences::Print } if (currentChar >= bufferSize-1) { return bufferSize-1; } buffer[currentChar++] = Ion::Charset::Exponent; - currentChar += IntegerReference(exponent).serialize(buffer+currentChar, bufferSize-currentChar, mode, numberOfSignificantDigits); + currentChar += Integer(exponent).serialize(buffer+currentChar, bufferSize-currentChar, mode, numberOfSignificantDigits); return currentChar; } /* Case 1: Decimal mode */ @@ -231,7 +206,7 @@ template Evaluation DecimalNode::templatedApproximate() const { return Complex(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 Decimal::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++) { @@ -264,39 +239,72 @@ int DecimalReference::exponent(const char * integralPart, int integralPartLength return exp; } -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); +Decimal::Decimal(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent) : Number(nullptr) { + Integer zero(0); + Integer base(10); + Integer numerator(integralPart, integralPartLength, negative); for (int i = 0; i < fractionalPartLength; i++) { - numerator = IntegerReference::Multiplication(numerator, base); - numerator = IntegerReference::Addition(numerator, IntegerReference(*fractionalPart-'0')); + numerator = Integer::Multiplication(numerator, base); + numerator = Integer::Addition(numerator, Integer(*fractionalPart-'0')); fractionalPart++; } - *this = DecimalReference(numerator, exponent); + *this = Decimal(numerator, exponent); } template -DecimalReference::DecimalReference(T f) { +Decimal::Decimal(T f) : Number(nullptr) { 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); + Integer m(mantissaf); + *this= Decimal(Integer(mantissaf), exp); } -DecimalReference::DecimalReference(IntegerReference m, int e) { - if (m.isAllocationFailure()) { - *this = DecimalReference(ExpressionNode::FailedAllocationStaticNode()); - return; +Decimal::Decimal(Integer m, int e) { + *this = Decimal(sizeof(DecimalNode)+sizeof(native_uint_t)*m.numberOfDigits()); + node()->setValue(m.node()->digits(), m.node()->numberOfDigits(), e, m.isNegative()); +} + +Expression Decimal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + Expression e = Expression::shallowReduce(context, angleUnit); + if (e.isUndefinedOrAllocationFailure()) { + return e; } - *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()); + // this = e + bool negative = sign() == ExpressionNode::Sign::Negative; + int exp = node()->exponent(); + NaturalIntegerPointer m = node()->mantissa(); + Integer numerator(&m); + removeZeroAtTheEnd(&numerator); + int numberOfDigits = Integer::NumberOfBase10Digits(numerator); + Integer denominator(1); + if (exp >= numberOfDigits-1) { + numerator = Integer::Multiplication(numerator, Integer::Power(Integer(10), Integer(exp-numberOfDigits+1))); + } else { + denominator = Integer::Power(Integer(10), Integer(numberOfDigits-1-exp)); } + // Do not reduce decimal to rational if the exponent is too big or too small. + if (numerator.isInfinity()) { + assert(!denominator.isInfinity()); + return Infinity(negative); + } + if (denominator.isInfinity()) { + assert(!denominator.isInfinity()); + return Rational(0); + } + numerator.setNegative(negative); + return Rational(numerator, denominator); } -template DecimalReference::DecimalReference(double); -template DecimalReference::DecimalReference(float); +Expression Decimal::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const { + if (sign() == ExpressionNode::Sign::Negative) { + Expression abs = setSign(ExpressionNode::Sign::Positive, context, angleUnit); + return Opposite(abs); + } + return *this; +} + +template Decimal::Decimal(double); +template Decimal::Decimal(float); }