[poincare] Implement Integer::Division in Z (relative integers)

Change-Id: I72ccd4afd8188b0389b1f32863ecb1af59581c04
This commit is contained in:
Émilie Feral
2017-09-28 16:17:06 +02:00
parent 4ffa26be2b
commit b5c06fd22b
3 changed files with 52 additions and 14 deletions

View File

@@ -59,6 +59,7 @@ private:
static int8_t ucmp(const Integer & a, const Integer & b); // -1, 0, or 1
static Integer usum(const Integer & a, const Integer & b, bool subtract, bool outputNegative);
static Integer addition(const Integer & a, const Integer & b, bool inverseBNegative);
static IntegerDivision udiv(const Integer & a, const Integer & b);
ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override;
Evaluation<float> * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override;
Evaluation<double> * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override;

View File

@@ -277,22 +277,35 @@ Integer Integer::Multiplication(const Integer & a, const Integer & b) {
}
IntegerDivision Integer::Division(const Integer & numerator, const Integer & denominator) {
// FIXME: First, test if denominator is zero.
if (numerator.isLowerThan(denominator)) {
IntegerDivision div = {.quotient = 0, .remainder = Integer::Addition(numerator, Integer(0))};
// FIXME: This is a ugly way to bypass creating a copy constructor!
return div;
if (!numerator.isNegative() && !denominator.isNegative()) {
return udiv(numerator, denominator);
}
// Recursive case
IntegerDivision div = Division(numerator, Integer::Addition(denominator, denominator));
div.quotient = Integer::Addition(div.quotient, div.quotient);
if (!(div.remainder.isLowerThan(denominator))) {
div.remainder = Integer::Subtraction(div.remainder, denominator);
div.quotient = Integer::Addition(div.quotient, Integer(1));
Integer absNumerator = numerator;
absNumerator.setNegative(false);
Integer absDenominator = denominator;
absDenominator.setNegative(false);
IntegerDivision usignedDiv = udiv(absNumerator, absDenominator);
if (usignedDiv.remainder.isEqualTo(Integer(0))) {
if (!numerator.isNegative() || !denominator.isNegative()) {
usignedDiv.quotient.setNegative(true);
}
return usignedDiv;
}
return div;
if (numerator.isNegative()) {
if (denominator.isNegative()) {
usignedDiv.remainder.setNegative(true);
usignedDiv.quotient = Addition(usignedDiv.quotient, Integer(1));
usignedDiv.remainder = Integer::Subtraction(usignedDiv.remainder, denominator);
} else {
usignedDiv.quotient.setNegative(true);
usignedDiv.quotient = Subtraction(usignedDiv.quotient, Integer(1));
usignedDiv.remainder = Integer::Subtraction(denominator, usignedDiv.remainder);
}
} else {
assert(denominator.isNegative());
usignedDiv.quotient.setNegative(true);
}
return usignedDiv;
}
// Private methods
@@ -379,6 +392,24 @@ Integer Integer::addition(const Integer & a, const Integer & b, bool inverseBNeg
}
}
IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denominator) {
assert(!numerator.isNegative() && !denominator.isNegative());
// FIXME: First, test if denominator is zero.
if (numerator.isLowerThan(denominator)) {
IntegerDivision div = {.quotient = 0, .remainder = numerator};
return div;
}
// Recursive case
IntegerDivision div = Division(numerator, Integer::Addition(denominator, denominator));
div.quotient = Integer::Addition(div.quotient, div.quotient);
if (!(div.remainder.isLowerThan(denominator))) {
div.remainder = Integer::Subtraction(div.remainder, denominator);
div.quotient = Integer::Addition(div.quotient, Integer(1));
}
return div;
}
int Integer::identifier() const {
assert(m_numberOfDigits > 0);
int sign = m_negative ? -1 : 1;

View File

@@ -52,6 +52,12 @@ QUIZ_CASE(poincare_integer_divide) {
assert(Integer::Division(Integer(8), Integer(4)).quotient.isEqualTo(Integer(2)) && Integer::Division(Integer(8), Integer(4)).remainder.isEqualTo(Integer(0)));
assert(Integer::Division(Integer("3293920983030066"), Integer(38928)).quotient.isEqualTo(Integer("84615726033")) && Integer::Division(Integer("3293920983030066"), Integer(38928)).remainder.isEqualTo(Integer(17442)));
assert(Integer::Division(Integer("3293920983030066"), Integer("389282362616")).quotient.isEqualTo(Integer(8461)) && Integer::Division(Integer("3293920983030066"), Integer("389282362616")).remainder.isEqualTo(Integer("202912936090")));
assert(Integer::Division(Integer("-18940566"), Integer("499030")).quotient.isEqualTo(Integer(-38)) && Integer::Division(Integer("-18940566"), Integer("499030")).remainder.isEqualTo(Integer("22574")));
assert(Integer::Division(Integer("234567909876"), Integer("-234567898")).quotient.isEqualTo(Integer(-1000)) && Integer::Division(Integer("234567909876"), Integer("-234567898")).remainder.isEqualTo(Integer("11876")));
assert(Integer::Division(Integer("-567"), Integer("-12")).quotient.isEqualTo(Integer(48)) && Integer::Division(Integer("-567"), Integer("-12")).remainder.isEqualTo(Integer("9")));
assert(Integer::Division(Integer("-576"), Integer("-12")).quotient.isEqualTo(Integer(48)) && Integer::Division(Integer("-576"), Integer("-12")).remainder.isEqualTo(Integer("0")));
assert(Integer::Division(Integer("576"), Integer("-12")).quotient.isEqualTo(Integer(-48)) && Integer::Division(Integer("576"), Integer("-12")).remainder.isEqualTo(Integer("0")));
assert(Integer::Division(Integer("-576"), Integer("12")).quotient.isEqualTo(Integer(-48)) && Integer::Division(Integer("-576"), Integer("12")).remainder.isEqualTo(Integer("0")));
}
template<typename T>