I'm doing a real-to-complex FFT with the org.apache.commons.math3.transform library as following:
private Complex[] fft(double[] values) {
FastFourierTransformer ffTransformer = new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] result = ffTransformer.transform(values, TransformType.FORWARD);
return result;
}
This gives me a org.apache.commons.math3.complex array with the result. This works fine.
Now I want to perform exactly the same with the JCufft library. I tried to do to it as following:
private Complex[] fft(double[] values) {
double inputJCufft[] = values.clone();
double outputJCufft[] = new double[values.length * 2];
cufftHandle plan = new cufftHandle();
JCufft.cufftPlan1d(plan, values.length, cufftType.CUFFT_D2Z, 1);
JCufft.cufftExecD2Z(plan, inputJCufft, outputJCufft);
JCufft.cufftDestroy(plan);
Complex[] result = BaseHelper.getComplexArray(outputJCufft);
return result;
}
public static Complex[] getComplexArray(double[] input) {
List<Complex> result = new ArrayList<Complex>();
for (int i = 0; i < input.length - 1; i = i + 2) {
result.add(new Complex(input[i], input[i + 1]));
}
return result.toArray(new Complex[result.size()]);
}
However, when I'm comparing the results, they differ from each other. What I have not taken into account, what am I doing wrong?
Thanks for your help.
Ok, it was my lack of understanding the FFT...
I changed the getComplexArray method to the following and now it works fine:
public static Complex[] getComplexArray(double[] input) {
Deque<Complex> deque = new LinkedList<Complex>();
int size = (input.length / 4 + 1) * 2;
for (int i = 0; i < size; i = i + 2) {
deque.add(new Complex(input[i], input[i + 1]));
}
List<Complex> result = new ArrayList<Complex>(deque);
deque.removeLast();
while (deque.size() > 1) {
result.add(deque.removeLast().conjugate());
}
return result.toArray(new Complex[result.size()]);
}
Related
this is a continuation of this post. I must calculate many times some statistics(Max, mean, min, median and std dev) of arrays and I have a performance issue given the sort of my arrays in the method calcMaxMinMedian.
Given, I could not improve much further the summary statistics of an array performance. I am trying now to understand strategies and work arounds to parallelize my upper calls or any other smart thoughts.
I have seen this doc but I am not familiar
As well as this (post)[https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible/20375622].
I tried using parallel streams, however probably given my SharedResource, the actual performance using the for loop was worse.
Time (s) functionUsingForLoop173
Time (s) functionUsingParallelStream194
Do anyone have an idea of what could I try to parallelize or any other thoughts on how to improve the overrall performance?
Here is what I tried:
public class MaxMinMedianArrayUtils {
int[] sharedStaticResource={1,5,5};//Shared resource across
/**
* Return an array with summary statistics. Max, mean,std dev,median,min.
* Throw an IllegalArgumentException if array is empty.
*
* #param a array.
* #return array returning Max(0), mean(1),std dev(2),median(3),min(4) in
* respective
* positions.
*/
public static double[] getSummaryStatistics(double[] a) {
double[] summary = new double[5];
if (a.length == 0) {
throw new IllegalArgumentException(
"Array is empty, please " + "verify" + " the values.");
} else if (a.length == 1) {
summary[0] = a[0];
summary[1] = a[0];
summary[2] = 0;
summary[3] = a[0];
summary[4] = a[0];
} else {
double[] meandStd = calcMeanSDSample(a);
summary[1] = meandStd[0];//Mean
summary[2] = meandStd[1];//Standard Deviation
double[] maxMinMedian = calcMaxMinMedian(a);
summary[0] = maxMinMedian[0];//Max
summary[4] = maxMinMedian[1];//Min
summary[3] = maxMinMedian[2];//Median
}
return summary;
}
public static double[] calcMeanSDSample(double numArray[]) {
int length = numArray.length;
double[] meanStd = new double[2];
if (length == 0) {
throw new IllegalArgumentException(
"Array is empty, please " + "verify" + " the values.");
} else if (length == 1) {
meanStd[0] = numArray[0];
meanStd[1] = 0.0;
} else {
double sum = 0.0, standardDeviation = 0.0;
for (double num : numArray) {
sum += num;
}
meanStd[0] = sum / length;
for (double num : numArray) {
standardDeviation += Math.pow(num - meanStd[0], 2);
}
meanStd[1] =
Math.sqrt(standardDeviation / ((double) length - 1.0));//-1
// because it is
// for sample
}
return meanStd;
}
public static double[] calcMaxMinMedian(double[] a) {
double[] maxMinMedian = new double[3];
if (a.length == 0) {
throw new IllegalArgumentException(
"Array is empty, please " + "verify" + " the values.");
} else if (a.length == 1) {
for (int i = 0; i < 3; i++) {
maxMinMedian[i] = a[0];
}
} else {
Arrays.sort(a);
maxMinMedian[0] = a[a.length - 1];
maxMinMedian[1] = a[0];
maxMinMedian[2] = (a.length % 2 != 0) ? (double) (a[a.length / 2]) :
(double) ((a[(a.length - 1) / 2] + a[a.length / 2]) / 2.0);
}
return maxMinMedian;
}
public static void main(String[] args) {
int numVals = 1000;
// double[] ar = new double[numVals];
int numCalculations = 2 * 1000 * 1 * 1000;
// int numCalculations = 2 * 1000;
MaxMinMedianArrayUtils maxMinMedianArrayUtils=
new MaxMinMedianArrayUtils();
Instant start = Instant.now();
double[][] statsPerCalculation=
maxMinMedianArrayUtils.functionUsingForLoop(numVals,
numCalculations);
Instant end = Instant.now();
long totalTime = Duration.between(start, end).toSeconds();
System.out.println("Time (s) functionUsingForLoop" + totalTime);
Instant start3 = Instant.now();
double[][] statsPerCalculation3=
maxMinMedianArrayUtils.functionUsingParallelStream(numVals,
numCalculations);
Instant end3 = Instant.now();
long totalTime3 = Duration.between(start3, end3).toSeconds();
System.out.println("Time (s) functionUsingParallelStream" + totalTime3);
}
private double[][] functionUsingForLoop(int numVals,
int numCalculations) {
// calculations that is used to get some values, but is not modified.
double[][] statsPerCalculation= new double[numCalculations][5];//Each
// line
// stores
// the stats of the array generated in the numCalculations loop
for (int i = 0; i < numCalculations; i++) {//Complete independent
// calculations that I want to parallelize
double[]array=functionSimulateCalculations(numVals);
double[] stats = getSummaryStatistics(array);
for(int s = 0; s < stats.length; s++) {//Copy
statsPerCalculation[i][s] = stats[s];
}
}
return statsPerCalculation;
}
private double[][] functionUsingParallelStream(int numVals,
int numCalculations) {
// calculations that is used to get some values, but is not modified.
double[][] statsPerCalculation= new double[numCalculations][5];//Each
// line
// stores
// the stats of the array generated in the numCalculations loop
double[][] finalStatsPerCalculation = statsPerCalculation;
IntStream.range(0,numCalculations).parallel().forEach((i)->{
double[] array=functionSimulateCalculations(numVals);
double[] stats = getSummaryStatistics(array);
for(int s = 0; s < stats.length; s++) {
finalStatsPerCalculation[i][s] = stats[s];
}
}
);
return statsPerCalculation;
}
private double[] functionSimulateCalculations(int numVals) {
double[] ar=new double[numVals];
for (int k = 0; k < numVals; k++) {//To simulate the
// actual function of my
// use case
ar[k] = Math.random()*sharedStaticResource[0];
}
return ar;
}
} // Utility
Part of your issue is that you are computing your randomised the data samples inside the tests, but have contention with the singleton random number generation in parallel threads. Also this means that you have no means of validating that the parallel algorithm matches the serial results.
Refactor your tests so that inputs are pre-computed once - you don't care about timing this step:
private double[][] generateInputData(int numVals, int numCalculations) {
// calculations that is used to get some values, but is not modified.
double[][] inputs = new double[numCalculations][];// Each
for (int i = 0; i < numCalculations; i++) {
inputs[i] = functionSimulateCalculations(numVals);
}
return inputs;
}
Then you can run both tests on same inputs:
private double[][] functionUsingForLoop(double[][]arrays) {
// calculations that is used to get some values, but is not modified.
int numCalculations = arrays.length;
double[][] statsPerCalculation = new double[numCalculations][5];// Each
for (int i = 0; i < numCalculations; i++) {
double[] stats = getSummaryStatistics(arrays[i]);
for (int s = 0; s < stats.length; s++) {
statsPerCalculation[i][s] = stats[s];
}
}
return statsPerCalculation;
}
private double[][] functionUsingParallelStream(double[][]arrays) {
int numCalculations = arrays.length;
double[][] statsPerCalculation = new double[numCalculations][5];// Each
double[][] finalStatsPerCalculation = statsPerCalculation;
IntStream.range(0, numCalculations).parallel().forEach((i) -> {
double[] stats = getSummaryStatistics(arrays[i]);
for (int s = 0; s < stats.length; s++) {
finalStatsPerCalculation[i][s] = stats[s];
}
});
return statsPerCalculation;
}
Finally make your main() do some warmups, initialise the arrays, time each section and compare the results:
for (int numCalculations : new int[] { 1, 2, 8, 8, 2 * 1000, 2* 10000, 2*1000*1*1000 } ) {
double[][] arrays = maxMinMedianArrayUtils.generateInputData(numVals, numCalculations);
// ...
double[][] statsPerCalculation= maxMinMedianArrayUtils.functionUsingForLoop(arrays);
// ...
double[][] statsPerCalculation3= maxMinMedianArrayUtils.functionUsingParallelStream(arrays);
// ...
// COMPARE the results
if (statsPerCalculation3.length != statsPerCalculation.length)
throw new RuntimeException("Results not same!");
for (int i = statsPerCalculation3.length - 1; i >= 0; i--) {
// System.out.println("statsPerCalculation ["+i+"]="+Arrays.toString(statsPerCalculation[i]));
// System.out.println("statsPerCalculation3["+i+"]="+Arrays.toString(statsPerCalculation3[i]));
for (int v = statsPerCalculation3[i].length - 1; v >= 0; v--) {
if (Math.abs(statsPerCalculation3[i][v]-statsPerCalculation[i][v]) > 0.0000000000001)
throw new RuntimeException("Results not same at ["+i+"]["+v+"]");
}
}
}
At this point, you'll see quite different trend in the results, parallel stream version a lot quicker than non-parallel.
I recently came across a problem where given a l and r you need to find out the sum of all x such that l <= x <= r (mod10^9 + 7).
And,
1 <= l <= r <= 10^18
Let sum(x) be the sum of fibonacci numbers upto x and let fibo(x) be the xth fibonacci number. It is known that
sum(x) = fibo(x+2) - 1
Using this I used this post to calculate the nth fibonacci term in O(logn) time.
I was wondering if it can be done any faster than this. Below is my implementation
public class FastFibonacci {
private static Map<BigInteger, BigInteger> map;
private static BigInteger mod = BigInteger.valueOf(1000000007);
public static BigInteger nthFibonacci(BigInteger num) {
if (num.compareTo(BigInteger.valueOf(2)) <= 0) return BigInteger.ONE;
return solve(num.subtract(BigInteger.ONE)).mod(BigInteger.valueOf(10000));
}
public static BigInteger solve(BigInteger num) {
if (map.get(num) != null) {
return map.get(num);
} else {
BigInteger k = num.divide(BigInteger.valueOf(2));
if (num.mod(BigInteger.valueOf(2)).compareTo(BigInteger.ZERO) == 0) {
// f(2*k)
map.put(num, (solve(k).multiply(solve(k)).mod(mod).add(solve(k.subtract(BigInteger.ONE)).multiply(solve(k.subtract(BigInteger.ONE))).mod(mod)).mod(mod)));
return map.get(num);
} else {
// f(2*k + 1)
map.put(num, (solve(k).multiply(solve(k.add( BigInteger.ONE))).mod(mod).add(solve(k).multiply(solve(k.subtract(BigInteger.ONE))).mod(mod))).mod(mod));
return map.get(num);
}
}
}
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
map = new HashMap<>();
map.put(BigInteger.ZERO, BigInteger.ONE);
map.put(BigInteger.ONE, BigInteger.ONE);
int test = in.nextInt();
BigInteger[] ls = new BigInteger[test];
BigInteger[] rs = new BigInteger[test];
for (int i = 0; i < test; i++) {
ls[i] = new BigInteger(in.readString());
rs[i] = new BigInteger(in.readString());
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < test; i++) {
BigInteger sumUptoL = nthFibonacci(ls[i]).subtract(BigInteger.ONE);
BigInteger sumUptoR = nthFibonacci(rs[i].add(BigInteger.valueOf(1))).subtract(BigInteger.ONE);
sb.append(sumUptoR.subtract(sumUptoL));
sb.append("\n");
}
System.out.print(sb.toString());
}
}
Assuming that for a given number N you only want to know fib(N+2)-1 and you don't really need to show all the sequence, you can use a non-recursive approach. The following function uses double, but you can refactor it to BigInteger to accept bigger values:
public double getFibonacci(int n) {
double f1 = Math.pow(((1 + Math.sqrt(5)) / 2.0), n);
double f2 = Math.pow(((1 - Math.sqrt(5)) / 2.0), n);
return Math.floor((f1 - f2) / Math.sqrt(5));
}
I have implemented a recursive radix-2 DIT FFT in Java, and a regular DFT to verify my results from the FFT, but the results from the two differ and I cannot seem to figure it out. Both are fed the entire array with the apply()-methods, start and stop index is 0 and data.length respectively. The DFT version looks correct with a nice peak at bin 50 while the FFT one is full of garbage. What am I doing wrong?
This is the FFT implementation (adapted from http://www.engineeringproductivitytools.com/stuff/T0001/PT04.HTM "A Recursive DIT FFT Routine.", I verified by comparing to the pseudo code at https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm#Pseudocode):
public class DITFFT2 extends Transform {
public float[] apply(float[] data, int startIndex, int stopIndex) throws IllegalArgumentException {
int N;
float[] filteredData;
Complex[] complexData;
Complex[] filteredComplexData;
if (stopIndex < startIndex) {
throw new IllegalArgumentException("stopIndex cannot be lower than startIndex!");
}
if (stopIndex < 0 || startIndex < 0) {
throw new IllegalArgumentException("Index cannot be negative!");
}
N = stopIndex - startIndex;
filteredData = new float[N];
complexData = new Complex[N];
for (int i = startIndex; i < stopIndex; i++) {
complexData[i-startIndex] = new Complex(data[i], 0.0f);
}
filteredComplexData = transform(complexData, N);
for (int i = 0; i < N; i++) {
filteredData[i] = filteredComplexData[i].abs();
}
return filteredData;
}
public Complex[] transform(Complex[] data, int N) {
Complex x;
Complex[] result = new Complex[N];
if (N == 1) {
result[0] = data[0];
} else {
Complex[] fe = new Complex[N/2];
Complex[] fo = new Complex[N/2];
for (int i = 0; i < N/2; i++) {
fe[i] = data[2*i];
fo[i] = data[2*i+1];
}
Complex[] Fe = transform(fe, N / 2);
Complex[] Fo = transform(fo, N / 2);
for (int k = 0; k < N/2; k++) {
x = Fo[k].copy();
x.mul(getTwiddleFactor(k, N));
result[k] = Fe[k].copy();
result[k].add(x);
result[k+N/2] = Fe[k].copy();
result[k+N/2].sub(x);
}
}
return result;
}
private Complex getTwiddleFactor(int k, int N) {
return new Complex(1.0f, (float)(-2.0f * Math.PI * k / (float)N));
}
}
And this is the DFT implementation:
public class DFT extends Transform {
public float[] apply(float[] data, int startIndex, int stopIndex) throws IllegalArgumentException {
int N;
float[] filteredData;
Complex[] complexData;
Complex[] filteredComplexData;
if (stopIndex < startIndex) {
throw new IllegalArgumentException("stopIndex cannot be lower than startIndex!");
}
if (stopIndex < 0 || startIndex < 0) {
throw new IllegalArgumentException("Index cannot be negative!");
}
N = stopIndex - startIndex;
filteredData = new float[N];
complexData = new Complex[N];
filteredComplexData = new Complex[N];
for (int i = startIndex; i < stopIndex; i++) {
complexData[i-startIndex] = new Complex(data[i], 0.0f);
filteredComplexData[i-startIndex] = new Complex(0.0f, 0.0f);
}
for (int k = 0; k < N; k++) {
for (int n = 0; n < N; n++) {
Complex c = complexData[n].copy();
filteredComplexData[k].add(c.mul(new Complex(1.0f, (float)(-2*Math.PI*n*k/(float)N))));
}
}
for (int i = 0; i < N; i++) {
filteredData[i] = filteredComplexData[i].abs();
}
return filteredData;
}
}
Now, both seems to give the correct answer for [8.0, 4.0, 8.0, 0.0], which is [20.0, 4.0j, 12.0, -4.0j]. But if I feed them a sine produced by:
mBuffer = new float[1024];
float sampleRate = 1000.0f;
float frequency = 50.0f;
for (int i = 0; i < mBuffer.length; i++) {
mBuffer[i] = (float)(0.5*Math.sin(2*Math.PI*i*frequency/sampleRate));
}
The implementation of Complex for reference:
public final class Complex {
public float mR, mTheta;
public Complex() {
mR = 0.0f;
mTheta = 0.0f;
}
public Complex(float r, float theta) {
mR = r;
mTheta = theta;
}
public Complex copy() {
return new Complex(mR, mTheta);
}
public Complex add(Complex c) {
float real, imag;
real = (float)(mR * Math.cos(mTheta) + c.mR * Math.cos(c.mTheta));
imag = (float)(mR * Math.sin(mTheta) + c.mR * Math.sin(c.mTheta));
mR = (float)Math.sqrt(Math.pow(real, 2) + Math.pow(imag, 2));
if (real != 0.0f) {
mTheta = (float)Math.atan(imag / real);
} else {
mTheta = (float)(imag > 0.0f ? Math.PI/2.0f : Math.PI*3.0f/2.0f);
}
return this;
}
public Complex sub(Complex c) {
float real, imag;
real = (float)(mR * Math.cos(mTheta) - c.mR * Math.cos(c.mTheta));
imag = (float)(mR * Math.sin(mTheta) - c.mR * Math.sin(c.mTheta));
mR = (float)Math.sqrt(Math.pow(real, 2) + Math.pow(imag, 2));
if (real != 0.0f) {
mTheta = (float)Math.atan(imag / real);
} else {
mTheta = (float)(imag > 0.0f ? Math.PI/2.0f : Math.PI*3.0f/2.0f);
}
return this;
}
public Complex mul(Complex c) {
mR = mR * c.mR;
mTheta = mTheta + c.mTheta;
return this;
}
public Complex div(Complex c) {
mR = mR / c.mR;
mTheta = mTheta - c.mTheta;
return this;
}
public Complex pow(float exp) {
mTheta = mTheta * exp;
mR = (float)Math.pow(mR, exp);
return this;
}
public float abs() {
return mR;
}
public float getRealPart() {
return (float)(mR * Math.cos(mTheta));
}
public float getImagPart() {
return (float)(mR * Math.sin(mTheta));
}
public String toStringRectangular() {
float real, imag;
StringBuilder sb = new StringBuilder();
real = (float)(mR * Math.cos(mTheta));
imag = (float)(mR * Math.sin(mTheta));
sb.append(real);
if (imag >= 0) {
sb.append(" + ");
} else {
sb.append(" - ");
}
sb.append(Math.abs(imag));
sb.append("i");
return sb.toString();
}
public String toStringExponential() {
StringBuilder sb = new StringBuilder();
sb.append(mR);
sb.append(" * e ^ ");
sb.append(mTheta);
sb.append("i");
return sb.toString();
}
public String toString() {
return toStringExponential() + " [ " + toStringRectangular() + " ] ";
}
public static Complex[] getInitializedArray(int size) {
Complex[] arr = new Complex[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = new Complex(0.0f, 0.0f);
}
return arr;
}
}
Your FFT implementation seems reasonable. However there is an issue with the use of Math.atan (which return a value within the [-pi/2,pi/2], instead of the whole [-pi,pi] range) in Complex's add and sub.
To resolve this issue you should be using:
mTheta = (float)Math.atan2(imag, real);
Hi guys I´m new in java.
I'm trying to convert an octave function in to Java(using JBlas) but I´m not sure how to do this line:
OCTAVE: Thetas{i} = rand(sizes(i+1), sizes(i) + 1)*2*EPSILON-EPSILON;
My code in Java:
public class InitializeThetas {
public static DoubleMatrix InitializeThetas(DoubleMatrix sizes, double epsilon)
{
int L= sizes.length;
epsilon = 0.03;
DoubleMatrix Thetas = new DoubleMatrix(new double[]{});
Random r = new Random();
for (int i = 1; i <= L - 1; i++)
{
//Thetas{i} = rand(sizes(i+1), sizes(i) + 1)*2*EPSILON-EPSILON;
Thetas.data[i]= r.nextInt() * 2 * epsilon - epsilon;
}
return Thetas;
}
}
Is this close to what you want?
public class InitializeThetas {
public static Collection<DoubleMatrix> InitializeThetas(DoubleMatrix sizes, double epsilon)
{
int L= sizes.length;
epsilon = 0.03;
Collection<DoubleMatrix> Thetas = new ArrayList<DoubleMatrix>();
for (int i = 0; i < L - 1; i++)
{
Thetas.add(DoubleMatrix.rand(Double.valueOf(sizes.get(i + 1)).intValue(), Double.valueOf(sizes.get(i)).intValue() + 1).mul(2).mul(epsilon).sub(epsilon));
}
return Thetas;
}
public static void main(String[] args) {
DoubleMatrix soze = new DoubleMatrix(10);
for(int i = 0;i<10;i++){
soze.put(i,i+1);
}
System.out.println(InitializeThetas(soze,1.1));
}
}
Could any help me start?
Using a class that I created before, I need to make a new class that specifically deals with QuadPoly. I think I have the constructors made correctly but i'm not a hundred percent sure.
public class Poly {
private float[] coefficients;
public static void main (String[] args){
float[] fa = {3, 2, 4};
Poly test = new Poly(fa);
}
public Poly() {
coefficients = new float[1];
coefficients[0] = 0;
}
public Poly(int degree) {
coefficients = new float[degree+1];
for (int i = 0; i <= degree; i++)
coefficients[i] = 0;
}
public Poly(float[] a) {
coefficients = new float[a.length];
for (int i = 0; i < a.length; i++)
coefficients[i] = a[i];
}
public int getDegree() {
return coefficients.length-1;
}
public float getCoefficient(int i) {
return coefficients[i];
}
public void setCoefficient(int i, float value) {
coefficients[i] = value;
}
public Poly add(Poly p) {
int n = getDegree();
int m = p.getDegree();
Poly result = new Poly(Poly.max(n, m));
int i;
for (i = 0; i <= Poly.min(n, m); i++)
result.setCoefficient(i, coefficients[i] + p.getCoefficient(i));
if (i <= n) {
//we have to copy the remaining coefficients from this object
for ( ; i <= n; i++)
result.setCoefficient(i, coefficients[i]);
} else {
// we have to copy the remaining coefficients from p
for ( ; i <= m; i++)
result.setCoefficient(i, p.getCoefficient(i));
}
return result;
}
public void displayPoly () {
for (int i=0; i < coefficients.length; i++)
System.out.print(" "+coefficients[i]);
System.out.println();
}
private static int max (int n, int m) {
if (n > m)
return n;
return m;
}
private static int min (int n, int m) {
if (n > m)
return m;
return n;
}
public Poly multiplyCon (double c){
int n = getDegree();
Poly results = new Poly(n);
for (int i =0; i <= n; i++){ // can work when multiplying only 1 coefficient
results.setCoefficient(i, (float)(coefficients[i] * c)); // errors ArrayIndexOutOfBounds for setCoefficient
}
return results;
}
public Poly multiplyPoly (Poly p){
int n = getDegree();
int m = p.getDegree();
Poly result = null;
for (int i = 0; i <= n; i++){
Poly tmpResult = p.multiByConstantWithDegree(coefficients[i], i); //Calls new method
if (result == null){
result = tmpResult;
} else {
result = result.add(tmpResult);
}
}
return result;
}
public void leadingZero() {
int degree = getDegree();
if ( degree == 0 ) return;
if ( coefficients[degree] != 0 ) return;
// find the last highest degree with non-zero cofficient
int highestDegree = degree;
for ( int i = degree; i <= 0; i--) {
if ( coefficients[i] == 0 ) {
highestDegree = i -1;
} else {
// if the value is non-zero
break;
}
}
float[] newCoefficients = new float[highestDegree + 1];
for ( int i=0; i<= highestDegree; i++ ) {
newCoefficients[i] = coefficients[i];
}
coefficients = newCoefficients;
}
public Poly differentiate(){
int n = getDegree();
Poly newResult = new Poly(n);
if (n>0){ //checking if it has a degree
for (int i = 1; i<= n; i++){
newResult.coefficients[i-1]= coefficients[i] * (i); // shift degree by 1 and multiplies
}
return newResult;
} else {
return new Poly(); //empty
}
}
public Poly multiByConstantWithDegree(double c, int degree){ //used specifically for multiply poly
int oldPolyDegree = this.getDegree();
int newPolyDegree = oldPolyDegree + degree;
Poly newResult = new Poly(newPolyDegree);
//set all coeff to zero
for (int i = 0; i<= newPolyDegree; i++){
newResult.coefficients[i] = 0;
}
//shift by n degree
for (int j = 0; j <= oldPolyDegree; j++){
newResult.coefficients[j+degree] = coefficients[j] * (float)c;
}
return newResult;
}
}
Out of this, I need to create a method that factors a Quadratic in two factors (if it has real roots), or in a constant ”1” polynomial factor and itself, if there are no real roots. The method should return an array of two QuadPoly objects, containing each factor.
public class QuadPoly extends Poly
{
private float [] quadcoefficients;
public QuadPoly() {
super(2);
}
public QuadPoly(float [] a) {
quadcoefficients = new float[a.length];
for (int i = 0; i <a.length; i ++){
quadcoefficients[i] = a[i];
if (quadcoefficients.length > 2){
throw new IllegalArgumentException ("Must be Quadratic");
}
}
}
public QuadPoly(Poly p){
if (quadcoefficients.length > 2){
throw new IllegalArgumentException ("Must be Quadratic");
}
}
public QuadPoly addQuad (QuadPoly p){
return new QuadPoly(super.add(p));
}
public Poly multiplyQuadPoly (Poly p){
if (quadcoefficients.length > 2){
throw new IllegalArgumentException ("Must be Quadratic");
}
Poly newResult = null;
new Result = multiplyPoly(p);
}
}
}
Edit:
Sorry. This is what I have going on for the factoring so far. The big problem with it is that I'm not too sure how to get the inheritance to work properly.
This is my New Factoring. It doesn't work. Can anyone give me some hints to get on the right path? I understand that I need to return Poly so i'm replacing the arrays there as you can tell by the first if statement but it won't let me progress as its says it requires (int, float). I've casted it but it still won't allow me. Thanks
public QuadPoly factor(){
double a = (double) getCoefficient(0);
double b = (double) getCoefficient(1);
double c = (double) getCoefficient(2);
QuadPoly newCoefficients = new QuadPoly(4);
double equa = Math.sqrt((b*b) - (4*a*c));
if (equa > 0){
newCoefficients.setCoefficient(0, (float) (-b + equa)/(2*a));
newCoefficients.setCoefficient(1, (float) (-b - equa)/(2*a));
}
if (equa ==0){
newCoefficients[0] = 1;
newCoefficients[1] = (-b + equa)/(2*a);
}
if (equa < 0){
newCoefficients[0] = 0;
newCoefficients[1] = 1;
}
return (QuadPoly) newCoefficients;
}
OK you have made a reasonable attempt. Inheritance is simple here, all you need is the constructors:
class QuadPoly extends Poly{
public QuadPoly(){ super(2); }
public QuadPoly(float[] f){
super(f);
if(coefficients.length!=2) throw new IllegalArgumentException("not quad");
}
}
and that's pretty much all! I hope you can see, that the same code as Poly is used for everything else, and the same field coefficients does all the same work as it did before.
Now, in the factorisation
you have dimmed your double[] newCoefficients as size 1. too small!
you have tried to square-root your discriminant without knowing that it is positive!
you are returning an array of 2 doubles as your answer. you need two Polys. You haven't provided a method return type for factor
I suggest you use
public QuadPoly[] factor(){
}
as the signature. The rest is just maths!
The idea of subclassing Poly into QuadPoly is so that you can reuse as many of the old Poly methods as possible. Now, all your old methods use the array float[] coefficients, and your new QuadPoly inherits this field.
Why have you created a new field quadcoefficients[] ? It suffices to check in any constructor that there are only 3 members in the array, but to still harness the existing field coefficients[].
If you do this, all your old methods will still work! Only, they will return generic Poly. Since the QuadPoly must conform to the contract of a Poly, this is probably OK. The method multiplyCon is the only one that could be guaranteed to return another QuadPoly anyway.
You don't seem to have attempted a factorisation yet. Do you have any ideas? Well, here's a clue: you'll need to use something like
if (DISCRIMINANT >= 0) {
} else{
}