diff options
Diffstat (limited to 'src/com/softsynth/math/PrimeFactors.java')
-rw-r--r-- | src/com/softsynth/math/PrimeFactors.java | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/com/softsynth/math/PrimeFactors.java b/src/com/softsynth/math/PrimeFactors.java new file mode 100644 index 0000000..5607951 --- /dev/null +++ b/src/com/softsynth/math/PrimeFactors.java @@ -0,0 +1,244 @@ +/* + * Copyright 2011 Phil Burk, Mobileer Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.softsynth.math; + +import java.util.ArrayList; + +/** + * Tool for factoring primes and prime ratios. This class contains a static array of primes + * generated using the Sieve of Eratosthenes. + * + * @author Phil Burk (C) 2011 Mobileer Inc + */ +public class PrimeFactors { + private static final int SIEVE_SIZE = 1000; + private static int[] primes; + private final int[] factors; + + static { + // Use Sieve of Eratosthenes to fill Prime table + boolean[] sieve = new boolean[SIEVE_SIZE]; + ArrayList<Integer> primeList = new ArrayList<Integer>(); + int i = 2; + while (i < (SIEVE_SIZE / 2)) { + if (!sieve[i]) { + primeList.add(i); + int multiple = 2 * i; + while (multiple < SIEVE_SIZE) { + sieve[multiple] = true; + multiple += i; + } + } + i += 1; + } + primes = primeListToArray(primeList); + } + + private static int[] primeListToArray(ArrayList<Integer> primeList) { + int[] primes = new int[primeList.size()]; + for (int i = 0; i < primes.length; i++) { + primes[i] = primeList.get(i); + } + return primes; + } + + public PrimeFactors(int[] factors) { + this.factors = factors; + } + + public PrimeFactors(int numerator, int denominator) { + int[] topFactors = factor(numerator); + int[] bottomFactors = factor(denominator); + factors = subtract(topFactors, bottomFactors); + } + + public PrimeFactors subtract(PrimeFactors pf) { + return new PrimeFactors(subtract(factors, pf.factors)); + } + + public PrimeFactors add(PrimeFactors pf) { + return new PrimeFactors(add(factors, pf.factors)); + } + + public static int[] subtract(int[] factorsA, int[] factorsB) { + int max; + int min; + if (factorsA.length > factorsB.length) { + max = factorsA.length; + min = factorsB.length; + } else { + + min = factorsA.length; + max = factorsB.length; + } + ArrayList<Integer> primeList = new ArrayList<Integer>(); + int i; + for (i = 0; i < min; i++) { + primeList.add(factorsA[i] - factorsB[i]); + } + if (factorsA.length > factorsB.length) { + for (; i < max; i++) { + primeList.add(factorsA[i]); + } + } else { + for (; i < max; i++) { + primeList.add(0 - factorsB[i]); + } + } + trimPrimeList(primeList); + return primeListToArray(primeList); + } + + public static int[] add(int[] factorsA, int[] factorsB) { + int max; + int min; + if (factorsA.length > factorsB.length) { + max = factorsA.length; + min = factorsB.length; + } else { + min = factorsA.length; + max = factorsB.length; + } + ArrayList<Integer> primeList = new ArrayList<Integer>(); + int i; + for (i = 0; i < min; i++) { + primeList.add(factorsA[i] + factorsB[i]); + } + if (factorsA.length > factorsB.length) { + for (; i < max; i++) { + primeList.add(factorsA[i]); + } + } else if (factorsB.length > factorsA.length) { + for (; i < max; i++) { + primeList.add(factorsB[i]); + } + } + trimPrimeList(primeList); + return primeListToArray(primeList); + } + + private static void trimPrimeList(ArrayList<Integer> primeList) { + int i; + // trim zero factors off end. + for (i = primeList.size() - 1; i >= 0; i--) { + if (primeList.get(i) == 0) { + primeList.remove(i); + } else { + break; + } + } + } + + public static int[] factor(int n) { + ArrayList<Integer> primeList = new ArrayList<Integer>(); + int i = 0; + int p = primes[i]; + int exponent = 0; + while (n > 1) { + // does the prime number divide evenly into n? + int d = n / p; + int m = d * p; + if (m == n) { + n = d; + exponent += 1; + } else { + primeList.add(exponent); + exponent = 0; + i += 1; + p = primes[i]; + } + } + if (exponent > 0) { + primeList.add(exponent); + } + return primeListToArray(primeList); + } + + /** + * Get prime from table. + * + * @warning Do not exceed getPrimeCount()-1. + * @param i + * @return Nth prime number, the 0th prime is 2 + */ + public static int getPrime(int i) { + return primes[i]; + } + + /** + * @return the number of primes stored in the table + */ + public static int getPrimeCount() { + return primes.length; + } + + public JustRatio getJustRatio() { + long n = 1; + long d = 1; + for (int i = 0; i < factors.length; i++) { + int exponent = factors[i]; + int p = primes[i]; + if (exponent > 0) { + for (int k = 0; k < exponent; k++) { + n = n * p; + } + } else if (exponent < 0) { + exponent = 0 - exponent; + for (int k = 0; k < exponent; k++) { + d = d * p; + } + } + } + return new JustRatio(n, d); + } + + public int[] getFactors() { + return factors.clone(); + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + printFactors(buffer, 1); + buffer.append("/"); + printFactors(buffer, -1); + return buffer.toString(); + } + + private void printFactors(StringBuffer buffer, int sign) { + boolean gotSome = false; + for (int i = 0; i < factors.length; i++) { + int pf = factors[i] * sign; + if (pf > 0) { + if (gotSome) + buffer.append('*'); + int prime = primes[i]; + if (pf == 1) { + buffer.append("" + prime); + } else if (pf == 2) { + buffer.append(prime + "*" + prime); + } else if (pf > 2) { + buffer.append("(" + prime + "^" + pf + ")"); + } + gotSome = true; + } + } + if (!gotSome) { + buffer.append("1"); + } + } +} |