From a61470e84a4044cf8a1cefd94f13629220e802a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 9 Oct 2017 12:03:15 +0200 Subject: [PATCH] [poincare] Fix primeFactorization to factorize any number (no bound anymore) Change-Id: I389124fcca03843aadcae4a6d5db10188f14c194 --- poincare/src/arithmetic.cpp | 15 +++++++++------ poincare/test/arithmetic.cpp | 11 +++++++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/poincare/src/arithmetic.cpp b/poincare/src/arithmetic.cpp index 5fb0f8297..c9c6ceb57 100644 --- a/poincare/src/arithmetic.cpp +++ b/poincare/src/arithmetic.cpp @@ -30,8 +30,9 @@ int primeFactors[Arithmetic::k_numberOfPrimeFactors] = {2, 3, 5, 7, 11, 13, 17, // we can go to 7907*7907 = 62 520 649 void Arithmetic::PrimeFactorization(const Integer * n, Integer * outputFactors, Integer * outputCoefficients, int outputLength) { - // TODO: Find the prime factorization of any number. When k_numberOfPrimeFactors is overflow, try every number as divisor. - assert(n->isLowerThan(Integer(primeFactors[k_numberOfPrimeFactors-1]*primeFactors[k_numberOfPrimeFactors-1]))); + /* First we look for prime divisors in the table primeFactors (to speed up + * the prime factorization for low numbers). When k_numberOfPrimeFactors is + * overflow, try every number as divisor. */ for (int index = 0; index < outputLength; index++) { outputCoefficients[index] = Integer(0); } @@ -42,11 +43,12 @@ void Arithmetic::PrimeFactorization(const Integer * n, Integer * outputFactors, } int t = 0; // n prime factor index int k = 0; // prime factor index - outputFactors[t] = Integer(primeFactors[k]); + Integer testedPrimeFactor = Integer(primeFactors[k]); // prime factor + outputFactors[t] = testedPrimeFactor; IntegerDivision d = {.quotient = 0, .remainder = 0}; bool stopCondition; do { - d = Integer::Division(m, Integer(primeFactors[k])); + d = Integer::Division(m, testedPrimeFactor); stopCondition = outputFactors[t].isLowerThan(d.quotient); // We evaluate the condition here in case we move d.quotient in n if (d.remainder.isEqualTo(Integer(0))) { outputCoefficients[t] = Integer::Addition(outputCoefficients[t], Integer(1)); @@ -56,11 +58,12 @@ void Arithmetic::PrimeFactorization(const Integer * n, Integer * outputFactors, } continue; } - k++; if (!outputCoefficients[t].isEqualTo(Integer(0))) { t++; } - outputFactors[t] = Integer(primeFactors[k]); + k++; + testedPrimeFactor = k < k_numberOfPrimeFactors ? Integer(primeFactors[k]) : Integer::Addition(testedPrimeFactor, Integer(1)); + outputFactors[t] = testedPrimeFactor; } while (stopCondition); outputFactors[t] = std::move(m); outputCoefficients[t] = Integer::Addition(outputCoefficients[t], Integer(1)); diff --git a/poincare/test/arithmetic.cpp b/poincare/test/arithmetic.cpp index 9d7ce3a4f..52d17d7b4 100644 --- a/poincare/test/arithmetic.cpp +++ b/poincare/test/arithmetic.cpp @@ -42,8 +42,12 @@ void assert_prime_factorization_equals_to(Integer a, int * factors, int * coeffi if (outputCoefficients[index].isEqualTo(Integer(0))) { break; } - assert(outputFactors[index].identifier() == factors[index]); // Cheat: instead of comparing to integers, we compare only identifier as we know that prime factors and their coefficients will always be lower than 2^32. - assert(outputCoefficients[index].identifier() == coefficients[index]); + /* Cheat: instead of comparing to integers, we compare their approximations + * (the relation between integers and their approximation is a surjection, + * however different integers are really likely to have different + * approximations... */ + assert(outputFactors[index].approximate(context) == Integer(factors[index]).approximate(context)); + assert(outputCoefficients[index].approximate(context) == Integer(coefficients[index]).approximate(context)); } } @@ -62,4 +66,7 @@ QUIZ_CASE(poincare_arithmetic) { int factors2[3] = {2,5, 7}; int coefficients2[3] = {2,4,2}; assert_prime_factorization_equals_to(Integer(122500), factors2, coefficients2, 3); + int factors3[8] = {3,7,11, 13, 19, 3607, 3803, 52579}; + int coefficients3[8] = {4,2,2,2,2,2,2,2}; + assert_prime_factorization_equals_to(Integer("15241578780673678515622620750190521"), factors3, coefficients3, 8); }