mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[poincare] Integer addition and subtraction
This commit is contained in:
@@ -7,6 +7,7 @@ typedef unsigned long uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef char int8_t;
|
||||
typedef long int32_t;
|
||||
typedef long long int64_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,9 @@ class Integer : public Expression {
|
||||
|
||||
// Arithmetic
|
||||
Integer operator+(const Integer &other) const;
|
||||
Integer operator-(const Integer &other) const;
|
||||
Integer operator*(const Integer &other) const;
|
||||
Integer operator/(const Integer &other) const;
|
||||
|
||||
bool operator<(const Integer &other) const;
|
||||
bool operator==(const Integer &other) const;
|
||||
@@ -31,6 +33,9 @@ class Integer : public Expression {
|
||||
virtual ExpressionLayout * createLayout();
|
||||
virtual float approximate();
|
||||
private:
|
||||
int8_t ucmp(const Integer &other) const; // -1, 0, or 1
|
||||
Integer usum(const Integer &other, bool subtract, bool output_negative) const;
|
||||
Integer add(const Integer &other, bool inverse_other_negative) const;
|
||||
/* WARNING: This constructor takes ownership of the bits array and will free it! */
|
||||
Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative);
|
||||
uint16_t m_numberOfDigits; // In base native_uint_max
|
||||
|
||||
@@ -99,40 +99,41 @@ Integer::Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative)
|
||||
m_negative(negative) {
|
||||
}
|
||||
|
||||
// TODO: factor code with "==", they are very similar
|
||||
bool Integer::operator<(const Integer &other) const {
|
||||
if (m_negative && !other.m_negative) {
|
||||
return true;
|
||||
} else if (!m_negative && other.m_negative) {
|
||||
return false;
|
||||
}
|
||||
if (m_numberOfDigits != other.m_numberOfDigits) {
|
||||
return (m_numberOfDigits < other.m_numberOfDigits);
|
||||
int8_t Integer::ucmp(const Integer &other) const {
|
||||
if (m_numberOfDigits < other.m_numberOfDigits) {
|
||||
return -1;
|
||||
} else if (other.m_numberOfDigits < m_numberOfDigits) {
|
||||
return 1;
|
||||
}
|
||||
for (uint16_t i = 0; i < m_numberOfDigits; i++) {
|
||||
// Digits are stored most-significant last
|
||||
native_uint_t digit = m_digits[m_numberOfDigits-i-1];
|
||||
native_uint_t otherDigit = other.m_digits[m_numberOfDigits-i-1];
|
||||
if (digit != otherDigit) {
|
||||
return (digit < otherDigit) != m_negative;
|
||||
if (digit < otherDigit) {
|
||||
return -1;
|
||||
} else if (otherDigit < digit) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int8_t sign(bool negative) {
|
||||
return 1 - 2*(int8_t)negative;
|
||||
}
|
||||
|
||||
bool Integer::operator<(const Integer &other) const {
|
||||
if (m_negative != other.m_negative) {
|
||||
return m_negative;
|
||||
}
|
||||
return (sign(m_negative)*ucmp(other) < 0);
|
||||
}
|
||||
|
||||
bool Integer::operator==(const Integer &other) const {
|
||||
if (other.m_negative != m_negative) {
|
||||
if (m_negative != other.m_negative) {
|
||||
return false;
|
||||
}
|
||||
if (other.m_numberOfDigits != m_numberOfDigits) {
|
||||
return false;
|
||||
}
|
||||
for (uint16_t i=0; i<m_numberOfDigits; i++) {
|
||||
if (m_digits[i] != other.m_digits[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return (ucmp(other) == 0);
|
||||
}
|
||||
|
||||
Integer& Integer::operator=(Integer&& other) {
|
||||
@@ -154,24 +155,53 @@ Integer& Integer::operator=(Integer&& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Integer Integer::add(const Integer &other, bool inverse_other_negative) const {
|
||||
bool other_negative = (inverse_other_negative ? !other.m_negative : other.m_negative);
|
||||
if (m_negative == other_negative) {
|
||||
return usum(other, false, m_negative);
|
||||
} else {
|
||||
/* The signs are different, this is in fact a substraction
|
||||
* s = this+other = (abs(this)-abs(other) OR abs(other)-abs(this))
|
||||
* 1/abs(this)>abs(other) : s = sign*udiff(this, other)
|
||||
* 2/abs(other)>abs(this) : s = sign*udiff(other, this)
|
||||
* sign? sign of the greater! */
|
||||
if (ucmp(other) >= 0) {
|
||||
return usum(other, true, m_negative);
|
||||
} else {
|
||||
return other.usum(*this, true, other_negative);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Integer Integer::operator+(const Integer &other) const {
|
||||
uint16_t sumSize = MAX(other.m_numberOfDigits,m_numberOfDigits)+1;
|
||||
native_uint_t * digits = (native_uint_t *)malloc(sumSize*sizeof(native_uint_t));
|
||||
bool carry = 0;
|
||||
for (uint16_t i = 0; i<sumSize; i++) {
|
||||
return add(other, false);
|
||||
}
|
||||
|
||||
|
||||
Integer Integer::operator-(const Integer &other) const {
|
||||
return add(other, true);
|
||||
}
|
||||
|
||||
Integer Integer::usum(const Integer &other, bool subtract, bool output_negative) const {
|
||||
uint16_t size = MAX(m_numberOfDigits, other.m_numberOfDigits);
|
||||
if (!subtract) {
|
||||
// Addition can overflow
|
||||
size += 1;
|
||||
}
|
||||
native_uint_t * digits = (native_uint_t *)malloc(size*sizeof(native_uint_t));
|
||||
bool carry = false;
|
||||
for (uint16_t i = 0; i<size; i++) {
|
||||
native_uint_t a = (i >= m_numberOfDigits ? 0 : m_digits[i]);
|
||||
native_uint_t b = (i >= other.m_numberOfDigits ? 0 : other.m_digits[i]);
|
||||
native_uint_t sum = a + b + carry; // TODO: Prove it cannot overflow
|
||||
digits[i] = sum;
|
||||
carry = ((a>sum)||(b>sum));
|
||||
native_uint_t result = (subtract ? a - b - carry : a + b + carry);
|
||||
digits[i] = result;
|
||||
carry = (subtract ? (a<result) : ((a>result)||(b>result))); // There's been an underflow or overflow
|
||||
}
|
||||
while (digits[sumSize-1] == 0) {
|
||||
sumSize--;
|
||||
/* At this point we may realloc m_digits to a smaller size.
|
||||
* It might not be worth the trouble though : it won't happen very often
|
||||
* and we're wasting a single native_uint_t. */
|
||||
while (digits[size-1] == 0) {
|
||||
size--;
|
||||
// We could realloc digits to a smaller size. Probably not worth the trouble.
|
||||
}
|
||||
return Integer(digits, sumSize, false);
|
||||
return Integer(digits, size, output_negative);
|
||||
}
|
||||
|
||||
Integer Integer::operator*(const Integer &other) const {
|
||||
@@ -202,7 +232,56 @@ Integer Integer::operator*(const Integer &other) const {
|
||||
/* At this point we could realloc m_digits to a smaller size. */
|
||||
}
|
||||
|
||||
return Integer(digits, productSize);
|
||||
return Integer(digits, productSize, m_negative != other.m_negative);
|
||||
}
|
||||
|
||||
/*
|
||||
Division::Division(const Integer &numerator, const Integer &denominator) :
|
||||
m_quotient(Integer((native_uint_t)0)),
|
||||
m_remainder(Integer((native_uint_t)0)) {
|
||||
// FIXME: First, test if denominator is zero.
|
||||
|
||||
if (numerator < denominator) {
|
||||
m_quotient = Integer((native_uint_t)0);
|
||||
m_remainder = numerator;
|
||||
return;
|
||||
}
|
||||
|
||||
// Recursive case
|
||||
*this = Division(numerator, denominator+denominator);
|
||||
m_quotient = m_quotient + m_quotient;
|
||||
if (!(m_remainder < denominator)) {
|
||||
m_remainder = m_remainder - denominator;
|
||||
m_quotient = m_quotient + 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Integer Integer::operator/(const Integer &other) const {
|
||||
return Integer(2);
|
||||
|
||||
/* We want to compute q so that this = q*other + remainder, with remainder
|
||||
* smaller than other */
|
||||
/*
|
||||
q' = 2*(x/(2*y))
|
||||
|
||||
q' = 2*(this/(2*other))
|
||||
*/
|
||||
|
||||
/* Use recursive algorithm:
|
||||
* Compute q' = 2 * (x/2y)
|
||||
* Fact: q = q' or q'+1
|
||||
***************************************/
|
||||
/* return q and r such that x = q*y + r
|
||||
*
|
||||
* this = x
|
||||
* other =y
|
||||
* q,r -> computed
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -29,6 +29,12 @@ QUIZ_CASE(poincare_integer_add) {
|
||||
assert(Integer("123456789123456789") + Integer(1) == Integer("123456789123456790"));
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_integer_subtract) {
|
||||
assert(Integer(123) - Integer(23) == Integer(100));
|
||||
assert(Integer("123456789123456789") - Integer("9999999999") == Integer("123456779123456790"));
|
||||
assert(Integer(23) - Integer(100) == Integer(-77));
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_integer_multiply) {
|
||||
assert(Integer(12) * Integer(34) == Integer(408));
|
||||
assert(Integer(-12) * Integer(34) == Integer(-408));
|
||||
|
||||
Reference in New Issue
Block a user