// Wrong place: move to a more appropriate location.
package ket;
import java.util.*;
import ket.math.Token;
import ket.math.Branch;
import ket.math.Argument;
import ket.math.Function;
/**
* Factorize given numbers into a vector of primes, retaining prime numbers
* between calculations as they are required.
*/
public class Factorize {
Vector<Argument> terms;
static final Primes primes = new Primes(); // TODO: Convert to a static, lazy-sequence.
int powersOfTen;
int n;
private Factorize(int n) {
this.terms = new Vector<Argument>();
this.n = n;
this.powersOfTen = 0;
}
/**
* Return a prime integer value or a product of factors. Tens can
* optionally post-multiply the other factors for use in scientific
* notation. Null is returned if n can't be factorized (n<2).
*/
public static Argument factorize(int n, boolean gatherTens) {
if (n<2) {
return null;
} else if (n < Primes.MAX_PRIME) {
primes.calcPrimes(n); // TODO: Should this be n or (int) Math.sqrt(n) ?
}
Factorize factorize = new Factorize(n);
if (gatherTens)
factorize.calcPowersOfTen();
factorize.prependFactors();
if (gatherTens)
factorize.appendTens();
return factorize.termsToBranch();
}
/**
* Return the largest common divisor of the given integer pair
* (defaulting to 1). Integers may be negative as their signs are
* ignored.
*/
public static int findCommonDivisor(int a, int b) {
a = positive(a);
b = positive(b);
for (int i=min(a,b); i>1; i--) {
if (a%i==0 && b%i==0) {
return i;
}
}
return 1;
}
private static int min(int a, int b) {
return a<b ? a : b;
}
private static int positive(int x) {
return x>0 ? x : -x;
}
private void calcPowersOfTen() {
while (n%10==0) {
n /= 10;
powersOfTen += 1;
}
}
// Append terms of ten if the factors exist.
private void appendTens() {
if (powersOfTen>0) {
terms.add(toPower(10, powersOfTen));
}
}
/**
* Find the next factor which can be appended more than once, add it to
* the given list of factors, and return n/fractions.
*/
private int findNextFactor(int n) {
for (int p : primes.getPrimes()) {
int count = 0;
while (n%p==0 && n>1) {
n /= p;
count += 1;
}
if (count>0) {
terms.add( toPower(p, count) );
return n;
}
}
return -1;
}
private void prependFactors() {
if (n<=Primes.MAX_PRIME && primes.isPrime(n)) {
// Look for factors unless it is too large or prime.
while (n>1) {
n = findNextFactor(n);
}
} else {
// Otherwise keep what is left of the number.
terms.add(new Token(n));
}
}
private Argument termsToBranch() {
switch (terms.size()) {
case 0:
return null;
case 1:
return terms.firstElement();
default:
Branch power = new Branch(Function.TIMES);
for (Argument product : terms) {
power.append(product);
}
return power;
}
}
private Argument toPower(int mantissa, int exponent) {
Token m = new Token(mantissa);
if (exponent>1) {
Token e = new Token(exponent);
return new Branch(Function.POWER, m, e);
} else {
return m;
}
}
}