diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index 3c86ff89d..22971bb8c 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -39,7 +39,7 @@ public: virtual void logAttributes(std::ostream & stream) const override { stream << " negative=\"" << m_negative << "\""; stream << " mantissa=\""; - this->signedMantissa().log(stream); + this->signedMantissa().logInteger(stream); stream << "\""; stream << " exponent=\"" << m_exponent << "\""; } diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 041cff08e..ec6009b1e 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -29,32 +29,70 @@ static_assert(sizeof(double_native_int_t) == 2*sizeof(native_int_t), "double_nat struct IntegerDivision; -class Integer final { +class IntegerNode final : public TreeNode { +public: + // TreeNode + void initToMatchSize(size_t goalSize) override; + size_t size() const override; + int numberOfChildren() const override { return 0; } +#if POINCARE_TREE_LOG + void log(std::ostream & stream) const; + virtual void logNodeName(std::ostream & stream) const override { + stream << "Integer"; + } + virtual void logAttributes(std::ostream & stream) const override; +#endif + + virtual void setDigits(const native_uint_t * digits, uint8_t numberOfDigits); + const native_uint_t * digits() const { return m_digits; } + uint8_t numberOfDigits() const { return m_numberOfDigits; } +private: + uint8_t m_numberOfDigits; // In base native_uint_t + native_uint_t m_digits[0]; // Little-endian +}; + +class Integer final : public TreeHandle { public: /* Constructors & Destructors */ + static Integer BuildInteger(native_uint_t * digits, uint16_t numberOfDigits, bool negative, bool enableOverflow = false); Integer(native_int_t i = 0); Integer(double_native_int_t i); Integer(const char * digits, size_t length, bool negative); Integer(const char * digits) : Integer(digits, strlen(digits), false) {} - static Integer Overflow(bool negative) { return Integer((native_uint_t *)nullptr, k_maxNumberOfDigits+1, negative); } - static Integer BuildInteger(native_uint_t * digits, uint16_t numberOfDigits, bool negative, bool enableOverflow = false); - ~Integer(); - static void TidyIntegerBuffer(); - + static Integer Overflow(bool negative) { return Integer(OverflowIdentifier, negative); } #if POINCARE_TREE_LOG - void log(std::ostream & stream = std::cout) const; + void logInteger(std::ostream & stream) const { + if (isOverflow()) { + stream << "overflow"; + return; + } else if (usesImmediateDigit()) { + stream << m_digit; + return; + } + node()->log(stream); + } #endif - /* Copy/Move constructors/assignments */ - Integer(Integer&& other); // C++11 move constructor - Integer& operator=(Integer&& other); // C++11 move assignment operator - Integer(const Integer& other); // C++11 copy constructor - Integer& operator=(const Integer& other); // C++11 copy assignment operator - // Getters - const native_uint_t * digits() const { return usesImmediateDigit() ? &m_digit : m_digits; } - uint8_t numberOfDigits() const { return m_numberOfDigits; } + const native_uint_t * digits() const { + if (usesImmediateDigit()) { + return &m_digit; + } else if (isOverflow()) { + return nullptr; + } + return node()->digits(); + } + uint8_t numberOfDigits() const { + if (usesImmediateDigit()) { + return m_digit == 0 ? 0 : 1; + } else if (isOverflow()) { + return k_maxNumberOfDigits+1; + } + return node()->numberOfDigits(); + } + bool isNegative() const { return m_negative; } + void setNegative(bool negative) { m_negative = numberOfDigits() > 0 ? negative : false; } // 0 is always positive // Serialization int serialize(char * buffer, int bufferSize) const; @@ -66,21 +104,19 @@ public: template T approximate() const; // Sign - bool isNegative() const { return m_negative; } - void setNegative(bool negative) { m_negative = m_numberOfDigits > 0 ? negative : false; } // Properties static int NumberOfBase10DigitsWithoutSign(const Integer & i); - bool isOne() const { return (m_numberOfDigits == 1 && digit(0) == 1 && !m_negative); }; - bool isTwo() const { return (m_numberOfDigits == 1 && digit(0) == 2 && !m_negative); }; - bool isTen() const { return (m_numberOfDigits == 1 && digit(0) == 10 && !m_negative); }; - bool isMinusOne() const { return (m_numberOfDigits == 1 && digit(0) == 1 && m_negative); }; - bool isZero() const { return (m_numberOfDigits == 0); }; - bool isInfinity() const { return m_numberOfDigits > k_maxNumberOfDigits; } + bool isOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && !m_negative); }; + bool isTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && !m_negative); }; + bool isTen() const { return (numberOfDigits() == 1 && digit(0) == 10 && !m_negative); }; + bool isMinusOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && m_negative); }; + bool isZero() const { return (numberOfDigits() == 0); }; + bool isInfinity() const { return numberOfDigits() > k_maxNumberOfDigits; } bool isEven() const { return ((digit(0) & 1) == 0); } constexpr static int k_maxExtractableInteger = 0x7FFFFFFF; - int extractedInt() const { assert(m_numberOfDigits == 0 || (m_numberOfDigits <= 1 && digit(0) <= k_maxExtractableInteger)); return m_numberOfDigits == 0 ? 0 : (m_negative ? -digit(0) : digit(0)); } + int extractedInt() const { assert(numberOfDigits() == 0 || (numberOfDigits() <= 1 && digit(0) <= k_maxExtractableInteger)); return numberOfDigits() == 0 ? 0 : (m_negative ? -digit(0) : digit(0)); } // Comparison static int NaturalOrder(const Integer & i, const Integer & j); @@ -100,23 +136,14 @@ public: static Integer Factorial(const Integer & i); constexpr static int k_maxNumberOfDigits = 32; - constexpr static int k_maxNumberOfIntegerSimutaneously = 16; private: constexpr static int k_maxNumberOfDigitsBase10 = 308; // (2^32)^k_maxNumberOfDigits ~ 1E308 - - Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative, bool enableOverflow = false); - - // Dynamic allocation - /* In order to guarantee the potential existence of 16 Integers simutaneously, - * we keep a table uint32_t that can contain up to 16 Integers with the - * maximal numbers of digits. We also give them one extra digit to be able to - * perform complex operations (like division) which involve Integers with one - * additional digit. */ - static native_uint_t * allocDigits(int numberOfDigits); - static void freeDigits(native_uint_t * digits); + static constexpr int OverflowIdentifier = TreeNode::NoNodeIdentifier - 1; // Constructors - void releaseDynamicIvars(); + Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative); + Integer(int identifier, bool negative) : TreeHandle(identifier), m_negative(negative) {} + IntegerNode * node() const { return static_cast(TreeHandle::node()); } // Arithmetic static Integer addition(const Integer & a, const Integer & b, bool inverseBNegative, bool enableOneDigitOverflow = false); @@ -133,36 +160,33 @@ private: // HalfDigits uint16_t numberOfHalfDigits() const { - if (m_numberOfDigits == 0) { return 0; } - native_uint_t d = digit(m_numberOfDigits-1); + if (numberOfDigits() == 0) { return 0; } + native_uint_t d = digit(numberOfDigits()-1); native_uint_t halfBase = 1 << (8*sizeof(half_native_uint_t)); - return (d >= halfBase ? 2*m_numberOfDigits : 2*m_numberOfDigits-1); + return (d >= halfBase ? 2*numberOfDigits() : 2*numberOfDigits()-1); } half_native_uint_t halfDigit(int i) const { assert(i >= 0); if (i >= numberOfHalfDigits()) { return 0; } - return (usesImmediateDigit() ? ((half_native_uint_t *)&m_digit)[i] : ((half_native_uint_t *)m_digits)[i]); + return (usesImmediateDigit() ? ((half_native_uint_t *)&m_digit)[i] : ((half_native_uint_t *)digits())[i]); } - bool usesImmediateDigit() const { return m_numberOfDigits == 1; } native_uint_t digit(uint8_t i) const { - assert(i >= 0 && i < m_numberOfDigits); - return (usesImmediateDigit() ? m_digit : m_digits[i]); + assert(!isOverflow()); + assert(i >= 0 && i < numberOfDigits()); + return (usesImmediateDigit() ? m_digit : digits()[i]); } + bool usesImmediateDigit() const { return m_identifier == TreeNode::NoNodeIdentifier; } /* An integer can have (k_maxNumberOfDigits + 1) digits: either when it is an * overflow, or when we want to have one more digit than usual to compute a * big division. */ - bool isOverflow() const { return m_numberOfDigits == k_maxNumberOfDigits + 1 && m_digits == nullptr; } + bool isOverflow() const { return m_identifier == OverflowIdentifier; } bool m_negative; - uint8_t m_numberOfDigits; // In base native_uint_t - union { - native_uint_t * m_digits; // Little-endian - native_uint_t m_digit; - }; + native_uint_t m_digit; }; struct IntegerDivision { diff --git a/poincare/src/init.cpp b/poincare/src/init.cpp index 0e4b1bbe7..9c9b6141b 100644 --- a/poincare/src/init.cpp +++ b/poincare/src/init.cpp @@ -12,9 +12,6 @@ void Init() { } void Tidy() { - // Clean Integer - Integer::TidyIntegerBuffer(); - // Clean Expression (reset the SymbolReplacementsLock) Expression::Tidy(); } diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index d69cd9617..39e46d8aa 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -34,119 +34,95 @@ static inline int8_t sign(bool negative) { return 1 - 2*(int8_t)negative; } +void IntegerNode::initToMatchSize(size_t goalSize) { + assert(goalSize != sizeof(IntegerNode)); + int digitsSize = goalSize - sizeof(IntegerNode); + assert(digitsSize%sizeof(native_uint_t) == 0); + /* We are initing the Integer to match a specific size. The built integer + * is dummy. */ + m_numberOfDigits = digitsSize/sizeof(native_uint_t); + assert(size() == goalSize); +} + +static size_t IntegerSize(uint8_t numberOfDigits) { + return sizeof(IntegerNode) + sizeof(native_uint_t)*(numberOfDigits); +} + +size_t IntegerNode::size() const { + return IntegerSize(m_numberOfDigits); +} + #if POINCARE_TREE_LOG -void Integer::log(std::ostream & stream) const { - if (m_numberOfDigits > k_maxNumberOfDigits) { - stream << "Integer: overflow"; +void IntegerNode::logAttributes(std::ostream & stream) const { + stream << " value=\""; + log(stream); + stream << "\""; +} + +void IntegerNode::log(std::ostream & stream) const { + if (m_numberOfDigits > Integer::k_maxNumberOfDigits) { + stream << "overflow"; return; } double d = 0.0; double base = 1.0; for (int i = 0; i < m_numberOfDigits; i++) { - d += digit(i)*base; + d += m_digits[i]*base; base *= std::pow(2.0,32.0); } - stream << "Integer: " << d; + stream << d; } #endif -/* new operator */ - -// This bit buffer indicates which cases of the sIntegerBuffer are already allocated -static uint16_t sbusyIntegerBuffer = 0; -static native_uint_t sIntegerBuffer[(Integer::k_maxNumberOfDigits+1)*Integer::k_maxNumberOfIntegerSimutaneously]; - -void Integer::TidyIntegerBuffer() { - sbusyIntegerBuffer = 0; -} - -native_uint_t * Integer::allocDigits(int numberOfDigits) { - assert(numberOfDigits <= k_maxNumberOfDigits+1); - uint16_t bitIndex = 1 << (16-1); - int index = 0; - while (sbusyIntegerBuffer & bitIndex) { - bitIndex >>= 1; - index++; - } - if (bitIndex == 0) { // we overflow the sIntegerBuffer - assert(false); - return nullptr; - } - sbusyIntegerBuffer |= bitIndex; - return sIntegerBuffer+index*(Integer::k_maxNumberOfDigits+1); -} - -void Integer::freeDigits(native_uint_t * digits) { - int index = (digits - sIntegerBuffer)/(Integer::k_maxNumberOfDigits+1); - assert(index < 16); - sbusyIntegerBuffer &= ~((uint16_t)1 << (16-1-index)); +void IntegerNode::setDigits(const native_uint_t * digits, uint8_t numberOfDigits) { + m_numberOfDigits = numberOfDigits; + memcpy(m_digits, digits, numberOfDigits*sizeof(native_uint_t)); } // Constructor Integer Integer::BuildInteger(native_uint_t * digits, uint16_t numberOfDigits, bool negative, bool enableOverflow) { - if ((!digits || !enableOverflow) && numberOfDigits == k_maxNumberOfDigits+1) { + if ((!digits || !enableOverflow) && numberOfDigits >= k_maxNumberOfDigits+1) { return Overflow(negative); } - native_uint_t * newDigits = allocDigits(numberOfDigits); - for (uint8_t i = 0; i < numberOfDigits; i++) { - newDigits[i] = digits[i]; + // 0 can't be negative + negative = numberOfDigits == 0 ? false : negative; + if (numberOfDigits <= 1) { + Integer i(TreeNode::NoNodeIdentifier, negative); + i.m_digit = numberOfDigits == 0 ? 0 : digits[0]; + return i; } - return Integer(newDigits, numberOfDigits, negative, enableOverflow); + return Integer(digits, numberOfDigits, negative); } -/* WARNING: This constructor takes ownership of the digits array! */ -Integer::Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative, bool enableOverflow) : - m_negative(numberOfDigits == 0 ? false : negative), - m_numberOfDigits(!enableOverflow && numberOfDigits > k_maxNumberOfDigits ? k_maxNumberOfDigits+1 : numberOfDigits), - m_digits(digits) +// Private constructor +Integer::Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative) : + TreeHandle(TreePool::sharedPool()->createTreeNode(IntegerSize(numberOfDigits))), + m_negative(negative) { - if ((m_numberOfDigits <= 1 || (!enableOverflow && m_numberOfDigits > k_maxNumberOfDigits)) && m_digits) { - freeDigits(m_digits); - if (m_numberOfDigits == 1) { - m_digit = digits[0]; - } else { - m_digits = nullptr; - } - } - m_negative = m_numberOfDigits == 0 ? false : m_negative; + node()->setDigits(digits, numberOfDigits); } -Integer::Integer(native_int_t i) { - if (i == 0) { - m_digits = nullptr; - m_numberOfDigits = 0; - m_negative = false; - return; - } - m_numberOfDigits = 1; +Integer::Integer(native_int_t i) : TreeHandle(TreeNode::NoNodeIdentifier) { m_digit = i > 0 ? i : -i; m_negative = i < 0; } Integer::Integer(double_native_int_t i) { - if (i == 0) { - m_digits = nullptr; - m_numberOfDigits = 0; - m_negative = false; - return; - } double_native_uint_t j = i < 0 ? -i : i; native_uint_t * d = (native_uint_t *)&j; native_uint_t leastSignificantDigit = *d; native_uint_t mostSignificantDigit = *(d+1); - m_numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2; - if (m_numberOfDigits == 1) { + uint8_t numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2; + if (numberOfDigits == 1) { + m_identifier = TreeNode::NoNodeIdentifier; + m_negative = i < 0; m_digit = leastSignificantDigit; } else { - native_uint_t * digits = allocDigits(m_numberOfDigits); - digits[0] = leastSignificantDigit; - digits[1] = mostSignificantDigit; - m_digits = digits; + new (this) Integer(d, 2, i < 0); } - m_negative = i < 0; } Integer::Integer(const char * digits, size_t length, bool negative) : @@ -165,90 +141,9 @@ Integer::Integer(const char * digits, size_t length, bool negative) : digits++; } } - setNegative(isZero() ? false : negative); } -void Integer::releaseDynamicIvars() { - if (!usesImmediateDigit() && m_digits) { - freeDigits(m_digits); - } -} - -Integer::~Integer() { - releaseDynamicIvars(); -} - -Integer::Integer(Integer && other) { - // Pilfer other's data - if (other.usesImmediateDigit()) { - m_digit = other.m_digit; - } else { - m_digits = other.m_digits; - } - m_numberOfDigits = other.m_numberOfDigits; - m_negative = other.m_negative; - - // Reset other - other.m_digits = nullptr; - other.m_numberOfDigits = 1; - other.m_negative = 0; -} - -Integer::Integer(const Integer& other) { - // Copy other's data - if (other.usesImmediateDigit() || other.isOverflow()) { - m_digit = other.m_digit; - } else { - native_uint_t * newDigits = allocDigits(other.m_numberOfDigits); - for (uint8_t i = 0; i < other.m_numberOfDigits; i++) { - newDigits[i] = other.m_digits[i]; - } - m_digits = newDigits; - } - m_numberOfDigits = other.m_numberOfDigits; - m_negative = other.m_negative; -} - -Integer& Integer::operator=(Integer && other) { - if (this != &other) { - releaseDynamicIvars(); - // Pilfer other's ivars - if (other.usesImmediateDigit()) { - m_digit = other.m_digit; - } else { - m_digits = other.m_digits; - } - m_numberOfDigits = other.m_numberOfDigits; - m_negative = other.m_negative; - - // Reset other - other.m_digits = nullptr; - other.m_numberOfDigits = 1; - other.m_negative = 0; - } - return *this; -} - -Integer& Integer::operator=(const Integer& other) { - if (this != &other) { - releaseDynamicIvars(); - // Copy other's ivars - if (other.usesImmediateDigit() || other.isOverflow()) { - m_digit = other.m_digit; - } else { - native_uint_t * digits = allocDigits(other.m_numberOfDigits); - for (uint8_t i = 0; i < other.m_numberOfDigits; i++) { - digits[i] = other.m_digits[i]; - } - m_digits = digits; - } - m_numberOfDigits = other.m_numberOfDigits; - m_negative = other.m_negative; - } - return *this; -} - // Serialization int Integer::serialize(char * buffer, int bufferSize) const { @@ -306,7 +201,7 @@ HorizontalLayout Integer::createLayout() const { template T Integer::approximate() const { - if (m_numberOfDigits == 0) { + if (numberOfDigits() == 0) { /* This special case for 0 is needed, because the current algorithm assumes * that the big integer is non zero, thus puts the exponent to 126 (integer * area), the issue is that when the mantissa is 0, a "shadow bit" is @@ -326,17 +221,18 @@ T Integer::approximate() const { return m_negative ? -INFINITY : INFINITY; } - native_uint_t lastDigit = m_numberOfDigits > 0 ? digit(m_numberOfDigits-1) : 0; + assert(numberOfDigits() > 0); + native_uint_t lastDigit = digit(numberOfDigits()-1); uint8_t numberOfBitsInLastDigit = log2(lastDigit); bool sign = m_negative; uint16_t exponent = IEEE754::exponentOffset(); /* Escape case if the exponent is too big to be stored */ - assert(m_numberOfDigits > 0); - if (((int)m_numberOfDigits-1)*32+numberOfBitsInLastDigit-1> IEEE754::maxExponent()-IEEE754::exponentOffset()) { + assert(numberOfDigits() > 0); + if (((int)numberOfDigits()-1)*32+numberOfBitsInLastDigit-1> IEEE754::maxExponent()-IEEE754::exponentOffset()) { return m_negative ? -INFINITY : INFINITY; } - exponent += (m_numberOfDigits-1)*32; + exponent += (numberOfDigits()-1)*32; exponent += numberOfBitsInLastDigit-1; uint64_t mantissa = 0; @@ -352,8 +248,8 @@ T Integer::approximate() const { * the mantissa is complete to avoid undefined right shifting (Shift operator * behavior is undefined if the right operand is negative, or greater than or * equal to the length in bits of the promoted left operand). */ - while (m_numberOfDigits >= digitIndex && numberOfBits < IEEE754::size()) { - lastDigit = digit(m_numberOfDigits-digitIndex); + while (numberOfDigits() >= digitIndex && numberOfBits < IEEE754::size()) { + lastDigit = digit(numberOfDigits()-digitIndex); numberOfBits += 32; if (IEEE754::size() > numberOfBits) { assert(IEEE754::size()-numberOfBits > 0 && IEEE754::size()-numberOfBits < 64); @@ -473,16 +369,16 @@ Integer Integer::multiplication(const Integer & a, const Integer & b, bool oneDi return Integer::Overflow(a.m_negative != b.m_negative); } - uint8_t size = min(a.m_numberOfDigits + b.m_numberOfDigits, k_maxNumberOfDigits + oneDigitOverflow); // Enable overflowing of 1 digit + uint8_t size = min(a.numberOfDigits() + b.numberOfDigits(), k_maxNumberOfDigits + oneDigitOverflow); // Enable overflowing of 1 digit - native_uint_t * digits = allocDigits(size); + native_uint_t digits[k_maxNumberOfDigits + 1]; memset(digits, 0, size*sizeof(native_uint_t)); double_native_uint_t carry = 0; - for (uint8_t i = 0; i < a.m_numberOfDigits; i++) { + for (uint8_t i = 0; i < a.numberOfDigits(); i++) { double_native_uint_t aDigit = a.digit(i); carry = 0; - for (uint8_t j = 0; j < b.m_numberOfDigits; j++) { + for (uint8_t j = 0; j < b.numberOfDigits(); j++) { double_native_uint_t bDigit = b.digit(j); /* The fact that aDigit and bDigit are double_native is very important, * otherwise the product might end up being computed on single_native size @@ -494,17 +390,16 @@ Integer Integer::multiplication(const Integer & a, const Integer & b, bool oneDi } else { if (l[0] != 0) { // Overflow the largest Integer - freeDigits(digits); return Integer::Overflow(a.m_negative != b.m_negative); - } } + } + } carry = l[1]; } - if (i+b.m_numberOfDigits < (uint8_t) k_maxNumberOfDigits+oneDigitOverflow) { - digits[i+b.m_numberOfDigits] += carry; + if (i+b.numberOfDigits() < (uint8_t) k_maxNumberOfDigits+oneDigitOverflow) { + digits[i+b.numberOfDigits()] += carry; } else { if (carry != 0) { // Overflow the largest Integer - freeDigits(digits); return Integer::Overflow(a.m_negative != b.m_negative); } } @@ -512,13 +407,13 @@ Integer Integer::multiplication(const Integer & a, const Integer & b, bool oneDi while (size>0 && digits[size-1] == 0) { size--; } - return Integer(digits, size, a.m_negative != b.m_negative, oneDigitOverflow); + return BuildInteger(digits, size, a.m_negative != b.m_negative, oneDigitOverflow); } int8_t Integer::ucmp(const Integer & a, const Integer & b) { - if (a.m_numberOfDigits < b.m_numberOfDigits) { + if (a.numberOfDigits() < b.numberOfDigits()) { return -1; - } else if (a.m_numberOfDigits > b.m_numberOfDigits) { + } else if (a.numberOfDigits() > b.numberOfDigits()) { return 1; } if (a.isOverflow() && b.isOverflow()) { @@ -526,10 +421,10 @@ int8_t Integer::ucmp(const Integer & a, const Integer & b) { } assert(!a.isOverflow()); assert(!b.isOverflow()); - for (uint16_t i = 0; i < a.m_numberOfDigits; i++) { + for (uint16_t i = 0; i < a.numberOfDigits(); i++) { // Digits are stored most-significant last - native_uint_t aDigit = a.digit(a.m_numberOfDigits-i-1); - native_uint_t bDigit = b.digit(b.m_numberOfDigits-i-1); + native_uint_t aDigit = a.digit(a.numberOfDigits()-i-1); + native_uint_t bDigit = b.digit(b.numberOfDigits()-i-1); if (aDigit < bDigit) { return -1; } else if (aDigit > bDigit) { @@ -541,27 +436,26 @@ int8_t Integer::ucmp(const Integer & a, const Integer & b) { Integer Integer::usum(const Integer & a, const Integer & b, bool subtract, bool oneDigitOverflow) { if (a.isOverflow() || b.isOverflow()) { - return Integer::Overflow(a.m_negative != b.m_negative); + return Overflow(a.m_negative != b.m_negative); } - uint8_t size = max(a.m_numberOfDigits, b.m_numberOfDigits); + uint8_t size = max(a.numberOfDigits(), b.numberOfDigits()); if (!subtract) { // Addition can overflow size++; } - native_uint_t * digits = allocDigits(max(size, k_maxNumberOfDigits+oneDigitOverflow)); + native_uint_t digits[k_maxNumberOfDigits+1]; bool carry = false; for (uint8_t i = 0; i < size; i++) { - native_uint_t aDigit = (i >= a.m_numberOfDigits ? 0 : a.digit(i)); - native_uint_t bDigit = (i >= b.m_numberOfDigits ? 0 : b.digit(i)); + native_uint_t aDigit = (i >= a.numberOfDigits() ? 0 : a.digit(i)); + native_uint_t bDigit = (i >= b.numberOfDigits() ? 0 : b.digit(i)); native_uint_t result = (subtract ? aDigit - bDigit - carry : aDigit + bDigit + carry); if (i < (uint8_t) (k_maxNumberOfDigits + oneDigitOverflow)) { digits[i] = result; } else { if (result != 0) { // Overflow the largest Integer - freeDigits(digits); - return Integer::Overflow(false); + return Overflow(false); } } if (subtract) { @@ -574,50 +468,53 @@ Integer Integer::usum(const Integer & a, const Integer & b, bool subtract, bool while (size>0 && digits[size-1] == 0) { size--; } - return Integer(digits, size, false, oneDigitOverflow); + return BuildInteger(digits, size, false, oneDigitOverflow); } Integer Integer::multiplyByPowerOf2(uint8_t pow) const { assert(pow < 32); - native_uint_t * digits = allocDigits(m_numberOfDigits+1); + native_uint_t digits[k_maxNumberOfDigits+1]; native_uint_t carry = 0; - for (uint8_t i = 0; i < m_numberOfDigits; i++) { + for (uint8_t i = 0; i < numberOfDigits(); i++) { digits[i] = digit(i) << pow | carry; carry = pow == 0 ? 0 : digit(i) >> (32-pow); } - digits[m_numberOfDigits] = carry; - return Integer(digits, carry ? m_numberOfDigits + 1 : m_numberOfDigits, false, true); + digits[numberOfDigits()] = carry; + return BuildInteger(digits, carry ? numberOfDigits() + 1 : numberOfDigits(), false, true); } Integer Integer::divideByPowerOf2(uint8_t pow) const { assert(pow < 32); - native_uint_t * digits = allocDigits(m_numberOfDigits); + native_uint_t digits[k_maxNumberOfDigits+1]; native_uint_t carry = 0; - for (int i = m_numberOfDigits - 1; i >= 0; i--) { + for (int i = numberOfDigits() - 1; i >= 0; i--) { digits[i] = digit(i) >> pow | carry; carry = pow == 0 ? 0 : digit(i) << (32-pow); } - return Integer(digits, digits[m_numberOfDigits-1] > 0 ? m_numberOfDigits : m_numberOfDigits-1, false, true); + return BuildInteger(digits, digits[numberOfDigits()-1] > 0 ? numberOfDigits() : numberOfDigits()-1, false, true); } // return this*(2^16)^pow Integer Integer::multiplyByPowerOfBase(uint8_t pow) const { int nbOfHalfDigits = numberOfHalfDigits(); - half_native_uint_t * digits = (half_native_uint_t *)allocDigits(m_numberOfDigits+(pow+1)/2); - memset(digits, 0, sizeof(native_uint_t)*(m_numberOfDigits+(pow+1)/2)); + half_native_uint_t digits[2*(k_maxNumberOfDigits+1)]; + /* The number of half digits of the built integer is nbOfHalfDigits+pow. + * Still, we set an extra half digit to 0 to easily convert half digits to + * digits. */ + memset(digits, 0, sizeof(half_native_uint_t)*(nbOfHalfDigits+pow+1)); for (uint8_t i = 0; i < nbOfHalfDigits; i++) { digits[i+pow] = halfDigit(i); } nbOfHalfDigits += pow; - return Integer((native_uint_t *)digits, nbOfHalfDigits%2 == 1 ? nbOfHalfDigits/2+1 : nbOfHalfDigits/2, false, true); + return BuildInteger((native_uint_t *)digits, nbOfHalfDigits%2 == 1 ? nbOfHalfDigits/2+1 : nbOfHalfDigits/2, false, true); } IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denominator) { if (denominator.isOverflow()) { - return {.quotient = Integer::Overflow(false), .remainder = Integer::Overflow(false)}; + return {.quotient = Overflow(false), .remainder = Integer::Overflow(false)}; } if (numerator.isOverflow()) { - return {.quotient = Integer::Overflow(false), .remainder = Integer::Overflow(false)}; + return {.quotient = Overflow(false), .remainder = Integer::Overflow(false)}; } /* Modern Computer Arithmetic, Richard P. Brent and Paul Zimmermann * (Algorithm 1.6) */ @@ -646,8 +543,9 @@ IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denomin int n = B.numberOfHalfDigits(); int m = A.numberOfHalfDigits()-n; // qDigits is a half_native_uint_t array and enable one digit overflow - half_native_uint_t * qDigits = (half_native_uint_t *)allocDigits(m/2+1); - memset(qDigits, 0, (m/2+1)*sizeof(native_uint_t)); + half_native_uint_t qDigits[2*k_maxNumberOfDigits]; + // The quotient q has at maximum m+1 half digits but we set an extra half digit to 0 to enable to easily convert it from half digits to digits + memset(qDigits, 0, max(m+1+1,2*k_maxNumberOfDigits)*sizeof(half_native_uint_t)); // betaMB = B*beta^m Integer betaMB = B.multiplyByPowerOfBase(m); if (Integer::NaturalOrder(A,betaMB) >= 0) { // A >= B*beta^m @@ -660,10 +558,12 @@ IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denomin half_native_uint_t baseMinus1 = (1 << 16) -1; // beta-1 qDigits[j] = qj2 < (native_uint_t)baseMinus1 ? (half_native_uint_t)qj2 : baseMinus1; // min(qj2, beta -1) A = Integer::addition(A, multiplication(qDigits[j], B.multiplyByPowerOfBase(j), true), true, true); // A-q[j]*beta^j*B - Integer betaJM = B.multiplyByPowerOfBase(j); // betaJM = B*beta^j - while (A.isNegative()) { - qDigits[j] = qDigits[j]-1; // q[j] = q[j]-1 - A = addition(A, betaJM, false, true); // A = B*beta^j+A + if (A.isNegative()) { + Integer betaJM = B.multiplyByPowerOfBase(j); // betaJM = B*beta^j + while (A.isNegative()) { + qDigits[j] = qDigits[j]-1; // q[j] = q[j]-1 + A = addition(A, betaJM, false, true); // A = B*beta^j+A + } } } int qNumberOfDigits = m+1; @@ -671,7 +571,7 @@ IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denomin qNumberOfDigits--; } int qNumberOfDigitsInBase32 = qNumberOfDigits%2 == 1 ? qNumberOfDigits/2+1 : qNumberOfDigits/2; - IntegerDivision div = {.quotient = Integer((native_uint_t *)qDigits, qNumberOfDigitsInBase32, false), .remainder = A}; + IntegerDivision div = {.quotient = BuildInteger((native_uint_t *)qDigits, qNumberOfDigitsInBase32, false), .remainder = A}; if (pow > 0 && !div.remainder.isZero()) { div.remainder = div.remainder.divideByPowerOf2(pow); } diff --git a/poincare/src/rational.cpp b/poincare/src/rational.cpp index 705c5b010..623908d31 100644 --- a/poincare/src/rational.cpp +++ b/poincare/src/rational.cpp @@ -71,10 +71,10 @@ size_t RationalNode::size() const { void RationalNode::logAttributes(std::ostream & stream) const { stream << " negative=\"" << m_negative << "\""; stream << " numerator=\""; - this->signedNumerator().log(stream); + this->signedNumerator().logInteger(stream); stream << "\""; stream << " denominator=\""; - this->denominator().log(stream); + this->denominator().logInteger(stream); stream << "\""; } #endif diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 346768071..56f928125 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -256,6 +256,7 @@ template MatrixNode * Poincare::TreePool::createTreeNode(size_t size template FloatNode * Poincare::TreePool::createTreeNode >(size_t size); template GreatCommonDivisorNode * Poincare::TreePool::createTreeNode(size_t size); template ImaginaryPartNode * Poincare::TreePool::createTreeNode(size_t size); +template IntegerNode * Poincare::TreePool::createTreeNode(size_t size); template IntegralNode * Poincare::TreePool::createTreeNode(size_t size); template LeastCommonMultipleNode * Poincare::TreePool::createTreeNode(size_t size); template MatrixDimensionNode * Poincare::TreePool::createTreeNode(size_t size);