mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[poincare] Integer are allocated on the TreePool instead of using their
own buffer. Short Integers are kept in the handle as an optimization.
This commit is contained in:
committed by
LeaNumworks
parent
79f0834f4e
commit
f4d63a2160
@@ -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 << "\"";
|
||||
}
|
||||
|
||||
@@ -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<typename T> 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<IntegerNode *>(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 {
|
||||
|
||||
@@ -12,9 +12,6 @@ void Init() {
|
||||
}
|
||||
|
||||
void Tidy() {
|
||||
// Clean Integer
|
||||
Integer::TidyIntegerBuffer();
|
||||
|
||||
// Clean Expression (reset the SymbolReplacementsLock)
|
||||
Expression::Tidy();
|
||||
}
|
||||
|
||||
@@ -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<IntegerNode>(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<typename T>
|
||||
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<T>::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<T>::maxExponent()-IEEE754<T>::exponentOffset()) {
|
||||
assert(numberOfDigits() > 0);
|
||||
if (((int)numberOfDigits()-1)*32+numberOfBitsInLastDigit-1> IEEE754<T>::maxExponent()-IEEE754<T>::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<T>::size()) {
|
||||
lastDigit = digit(m_numberOfDigits-digitIndex);
|
||||
while (numberOfDigits() >= digitIndex && numberOfBits < IEEE754<T>::size()) {
|
||||
lastDigit = digit(numberOfDigits()-digitIndex);
|
||||
numberOfBits += 32;
|
||||
if (IEEE754<T>::size() > numberOfBits) {
|
||||
assert(IEEE754<T>::size()-numberOfBits > 0 && IEEE754<T>::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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -256,6 +256,7 @@ template MatrixNode * Poincare::TreePool::createTreeNode<MatrixNode>(size_t size
|
||||
template FloatNode<double> * Poincare::TreePool::createTreeNode<FloatNode<double> >(size_t size);
|
||||
template GreatCommonDivisorNode * Poincare::TreePool::createTreeNode<GreatCommonDivisorNode>(size_t size);
|
||||
template ImaginaryPartNode * Poincare::TreePool::createTreeNode<ImaginaryPartNode>(size_t size);
|
||||
template IntegerNode * Poincare::TreePool::createTreeNode<IntegerNode>(size_t size);
|
||||
template IntegralNode * Poincare::TreePool::createTreeNode<IntegralNode>(size_t size);
|
||||
template LeastCommonMultipleNode * Poincare::TreePool::createTreeNode<LeastCommonMultipleNode>(size_t size);
|
||||
template MatrixDimensionNode * Poincare::TreePool::createTreeNode<MatrixDimensionNode>(size_t size);
|
||||
|
||||
Reference in New Issue
Block a user