[poincare] Integer optimization: small digit doest not allocate anything

This commit is contained in:
Émilie Feral
2018-09-03 14:38:20 +02:00
parent 0a6e2bbf63
commit cde73df38e
5 changed files with 72 additions and 49 deletions

View File

@@ -52,7 +52,7 @@ public:
Integer& operator=(const Integer& other); // C++11 copy assignment operator
// Getters
const native_uint_t * digits() const { return m_digits; }
const native_uint_t * digits() const { return usesImmediateDigit() ? &m_digit : m_digits; }
size_t numberOfDigits() const { return m_numberOfDigits; }
// Serialization
@@ -66,7 +66,7 @@ public:
// Sign
bool isNegative() const { return m_negative; }
void setNegative(bool negative) { if (m_numberOfDigits > 0) { m_negative = negative; } }
void setNegative(bool negative) { m_negative = m_numberOfDigits > 0 ? negative : false; }
// Properties
static int NumberOfBase10DigitsWithoutSign(const Integer & i);
@@ -135,17 +135,21 @@ private:
if (i >= numberOfHalfDigits()) {
return 0;
}
return ((half_native_uint_t *)m_digits)[i];
return (usesImmediateDigit() ? ((half_native_uint_t *)&m_digit)[i] : ((half_native_uint_t *)m_digits)[i]);
}
bool usesImmediateDigit() const { return m_numberOfDigits == 1; }
native_uint_t digit(int i) const {
assert(i >= 0 && i < m_numberOfDigits);
return m_digits[i];
return (usesImmediateDigit() ? m_digit : m_digits[i]);
}
bool m_negative;
size_t m_numberOfDigits; // In base native_uint_t
native_uint_t * m_digits;
union {
native_uint_t * m_digits; // Little-endian
native_uint_t m_digit;
};
};
struct IntegerDivision {

View File

@@ -37,10 +37,10 @@ static inline int8_t sign(bool negative) {
#if POINCARE_INTEGER_LOG
void Integer::log() const {
double d = 0;
double d = 0.0;
double base = 1.0;
for (int i = 0; i < m_numberOfDigits; i++) {
d += m_digits[i]*base;
d += digit(i)*base;
base *= std::pow(2.0,32.0);
}
std::cout << "Integer: " << d << std::endl;
@@ -83,10 +83,15 @@ Integer::Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative,
m_numberOfDigits(!enableOverflow && numberOfDigits > Integer::k_maxNumberOfDigits ? k_maxNumberOfDigits+1 : numberOfDigits),
m_digits(digits)
{
if ((m_numberOfDigits == 0 || (!enableOverflow && m_numberOfDigits > k_maxNumberOfDigitsBase10)) && m_digits) {
if ((m_numberOfDigits <= 1|| (!enableOverflow && m_numberOfDigits > k_maxNumberOfDigitsBase10)) && m_digits) {
freeDigits(m_digits);
m_digits = nullptr;
if (m_numberOfDigits == 1) {
m_digit = digits[0];
} else {
m_digits = nullptr;
}
}
m_negative = m_numberOfDigits == 0 ? false : m_negative;
}
Integer::Integer(native_int_t i) {
@@ -97,9 +102,7 @@ Integer::Integer(native_int_t i) {
return;
}
m_numberOfDigits = 1;
native_uint_t * digits = allocDigits(1);
digits[0] = i > 0 ? i : -i;
m_digits = digits;
m_digit = i > 0 ? i : -i;
m_negative = i < 0;
}
@@ -115,12 +118,14 @@ Integer::Integer(double_native_int_t i) {
native_uint_t leastSignificantDigit = *d;
native_uint_t mostSignificantDigit = *(d+1);
m_numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2;
native_uint_t * digits = allocDigits(m_numberOfDigits);
digits[0] = leastSignificantDigit;
if (m_numberOfDigits > 1) {
if (m_numberOfDigits == 1) {
m_digit = leastSignificantDigit;
} else {
native_uint_t * digits = allocDigits(m_numberOfDigits);
digits[0] = leastSignificantDigit;
digits[1] = mostSignificantDigit;
m_digits = digits;
}
m_digits = digits;
m_negative = i < 0;
}
@@ -145,7 +150,7 @@ Integer::Integer(const char * digits, size_t length, bool negative) :
}
void Integer::releaseDynamicIvars() {
if (m_digits) {
if (!usesImmediateDigit() && m_digits) {
freeDigits(m_digits);
}
}
@@ -156,7 +161,11 @@ Integer::~Integer() {
Integer::Integer(Integer && other) {
// Pilfer other's data
m_digits = other.m_digits;
if (other.usesImmediateDigit()) {
m_digit = other.m_digit;
} else {
m_digits = other.m_digits;
}
m_numberOfDigits = other.m_numberOfDigits;
m_negative = other.m_negative;
@@ -168,11 +177,15 @@ Integer::Integer(Integer && other) {
Integer::Integer(const Integer& other) {
// Copy other's data
native_uint_t * digits = allocDigits(other.m_numberOfDigits);
for (int i=0; i<other.m_numberOfDigits; i++) {
digits[i] = other.m_digits[i];
if (other.usesImmediateDigit()) {
m_digit = other.m_digit;
} else {
native_uint_t * digits = allocDigits(other.m_numberOfDigits);
for (int i=0; i<other.m_numberOfDigits; i++) {
digits[i] = other.m_digits[i];
}
m_digits = digits;
}
m_digits = digits;
m_numberOfDigits = other.m_numberOfDigits;
m_negative = other.m_negative;
}
@@ -181,7 +194,11 @@ Integer& Integer::operator=(Integer && other) {
if (this != &other) {
releaseDynamicIvars();
// Pilfer other's ivars
m_digits = other.m_digits;
if (other.usesImmediateDigit()) {
m_digit = other.m_digit;
} else {
m_digits = other.m_digits;
}
m_numberOfDigits = other.m_numberOfDigits;
m_negative = other.m_negative;
@@ -197,11 +214,15 @@ Integer& Integer::operator=(const Integer& other) {
if (this != &other) {
releaseDynamicIvars();
// Copy other's ivars
native_uint_t * digits = allocDigits(other.m_numberOfDigits);
for (int i=0; i<other.m_numberOfDigits; i++) {
digits[i] = other.m_digits[i];
if (other.usesImmediateDigit()) {
m_digit = other.m_digit;
} else {
native_uint_t * digits = allocDigits(other.m_numberOfDigits);
for (int i=0; i<other.m_numberOfDigits; i++) {
digits[i] = other.m_digits[i];
}
m_digits = digits;
}
m_digits = digits;
m_numberOfDigits = other.m_numberOfDigits;
m_negative = other.m_negative;
}
@@ -522,8 +543,8 @@ Integer Integer::multiplyByPowerOf2(uint8_t pow) const {
native_uint_t * digits = allocDigits(m_numberOfDigits+1);
native_uint_t carry = 0;
for (int i = 0; i < m_numberOfDigits; i++) {
digits[i] = m_digits[i] << pow | carry;
carry = pow == 0 ? 0 : m_digits[i] >> (32-pow);
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);
@@ -534,8 +555,8 @@ Integer Integer::divideByPowerOf2(uint8_t pow) const {
native_uint_t * digits = allocDigits(m_numberOfDigits);
native_uint_t carry = 0;
for (int i = m_numberOfDigits - 1; i >= 0; i--) {
digits[i] = m_digits[i] >> pow | carry;
carry = pow == 0 ? 0 : m_digits[i] << (32-pow);
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);
}

View File

@@ -78,7 +78,7 @@ Expression Opposite::shallowReduce(Context & context, Preferences::AngleUnit ang
#if MATRIX_EXACT_REDUCING
#endif
result = Multiplication(Rational(-1), child);
return result.shallowReduce(context, angleUnit, futureParent);
return result.shallowReduce(context, angleUnit);
}
}

View File

@@ -63,9 +63,9 @@ Expression Subtraction::shallowReduce(Context & context, Preferences::AngleUnit
}
Expression m = Multiplication(Rational(-1), childAtIndex(1));
Addition a = Addition(childAtIndex(0));
m = m.shallowReduce(context, angleUnit, a);
m = m.shallowReduce(context, angleUnit);
a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren());
return a.shallowReduce(context, angleUnit, futureParent);
return a.shallowReduce(context, angleUnit);
}
}

View File

@@ -21,7 +21,7 @@ QUIZ_CASE(poincare_integer_constructor) {
Integer nc(-12314);
Integer d((int64_t)1234567891011121314);
Integer nd((int64_t)(-1234567891011121314));
Integer e = Integer::Overflow();
Integer e = Integer::Overflow(false);
assert_pool_size(initialPoolSize+9);
}
@@ -212,14 +212,6 @@ QUIZ_CASE(poincare_integer_factorial) {
// Simplify
QUIZ_CASE(poincare_integer_simplify) {
/* assert_parsed_expression_simplify_to("1234", "1234");
assert_parsed_expression_simplify_to("12342345698765345678909876545678907655678900987654", "12342345698765345678909876545678907655678900987654");
assert_parsed_expression_simplify_to("12342345698765345678909876545678907655678900987654", "12342345698765345678909876545678907655678900987654");
assert_parsed_expression_simplify_to(MaxIntegerString, MaxIntegerString);
//assert_parsed_expression_simplify_to(OverflowedIntegerString, "inf"); // parse as a Decimal and then simplify to Rational*/
}
template<typename T>
void assert_integer_evals_to(const char * i, T result) {
quiz_assert(Integer(i).approximate<T>() == result);
@@ -267,10 +259,16 @@ QUIZ_CASE(poincare_integer_evaluate) {
//Serialize
QUIZ_CASE(poincare_integer_serialize) {
assert_parsed_expression_serialize_to(Integer(-2), "-2");
assert_parsed_expression_serialize_to(Integer("2345678909876"), "2345678909876");
assert_parsed_expression_serialize_to(Integer("-2345678909876"), "-2345678909876");
assert_parsed_expression_serialize_to(MaxInteger(), MaxIntegerString);
assert_parsed_expression_serialize_to(OverflowedInteger(), "inf");
static inline void assert_integer_serializes_to(const Integer i, const char * serialization) {
char buffer[500];
i.serialize(buffer, 500);
quiz_assert(strcmp(buffer, serialization) == 0);
}
QUIZ_CASE(poincare_integer_serialize) {
assert_integer_serializes_to(Integer(-2), "-2");
assert_integer_serializes_to(Integer("2345678909876"), "2345678909876");
assert_integer_serializes_to(Integer("-2345678909876"), "-2345678909876");
assert_integer_serializes_to(MaxInteger(), MaxIntegerString);
assert_integer_serializes_to(OverflowedInteger(), "inf");
}