package ProGAL.math; import static java.lang.Math.sqrt; import static java.lang.Math.abs; import static java.lang.Math.cos; import static java.lang.Math.acos; import static java.lang.Math.PI; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * A representation of a variable sized polynomial. To find the roots of the * parabola f(x) = 2x^2 + 3x - 4, for instance, write * * Polynomial parabola = new Polynomial(new double[]{2,3,4}); * double[] roots = parabola.calcRoots(); * * or simply * * double[] roots = Polynomial.calcRoots(2,3,4); * * Currently this only works for polynomials of degree 2 and 3. * @author rfonseca */ public class Polynomial { public final double[] coeff; private int deg; // private class PairOfPolynomials { // private Polynomial p; // private Polynomial q; // // private PairOfPolynomials(Polynomial p, Polynomial q) { // this.p = p; // this.q = q; // } // } /** * creates a zero polynomial */ Polynomial() { coeff = new double[1]; deg = 0; } /** * creates a polynomal * @param pars */ // Daisy: Made it public from nothing public Polynomial(double[] pars){ coeff = pars; deg = pars.length-1; } /** returns a copy of the polynomial p * @return copy of the polynomial p */ public Polynomial clone() { double[] coefficients = new double[coeff.length]; for (int i = 0; i < coefficients.length; i++) coefficients[i] = coeff[i]; return new Polynomial(coefficients); } /** returns TRUE if this polynomial is a zero polynomial * * @return */ public boolean isZeroPolynomial() { return ((deg == 0) && (coeff[0] == 0.0)); } public boolean dominates(Polynomial p) { if (this.deg > p.deg) return true; if (this.deg < p.deg) return false; for (int i = deg; i >= 0; i--) { if (this.coeff[i] > p.coeff[i]) return true; if (this.coeff[i] < p.coeff[i]) return false; } return false; } public Polynomial leadingTerm() { double[] coefficients = new double[deg+1]; coefficients[deg] = coeff[deg]; return new Polynomial(coefficients); } // Daisy public int getDeg() { return deg; } // returns a + b public Polynomial plus(Polynomial b) { int degree = Math.max(deg, b.deg); while ((degree != -1) && (degree <= deg) && (degree <= b.deg) && (coeff[degree] == -b.coeff[degree])) degree--; if (degree == -1) return new Polynomial(new double[1]); double[] coeff = new double[degree + 1]; for (int i = 0; i <= this.deg; i++) if (i <= degree) coeff[i] = this.coeff[i]; for (int i = 0; i <= b.deg; i++) if (i <= degree) coeff[i] += b.coeff[i]; //Daisys version put in corner for now // double[] coeff = new double[Math.max(deg+1, b.deg+1)]; // for (int i = 0; i <= deg; i++) coeff[i] = this.coeff[i]; // for (int i = 0; i <= b.deg; i++) { // coeff[i] += b.coeff[i]; // if (Math.abs(coeff[i]) <= Constants.EPSILON ) coeff[i] = 0; // } // while ((deg != 0) && (coeff[deg] == 0.0)) deg--; return new Polynomial(coeff); } // returns a - b public Polynomial minus(Polynomial b) { int degree = Math.max(deg, b.deg); while ((degree != -1) && (degree <= deg) && (degree <= b.deg) && (coeff[degree] == b.coeff[degree])) degree--; if (degree == -1) return new Polynomial(new double[1]); double[] coeff = new double[degree + 1]; for (int i = 0; i <= this.deg; i++) if (i <= degree) coeff[i] = this.coeff[i]; for (int i = 0; i <= b.deg; i++) if (i <= degree) coeff[i] -= b.coeff[i]; return new Polynomial(coeff); // Daisys version put in corner // int maxDeg = Math.max(deg, b.deg); // double[] coeff = new double[maxDeg+1]; // for (int i = 0; i <= deg; i++) coeff[i] = this.coeff[i]; // for (int i = 0; i <= b.deg; i++) { // coeff[i] -= b.coeff[i]; // if (Math.abs(coeff[i]) <= Constants.EPSILON ) coeff[i] = 0; // } // int tmpDeg = maxDeg; // while ((tmpDeg != 0) && (coeff[tmpDeg] == 0.0)) { tmpDeg--; } // if (tmpDeg != maxDeg) { // double[] coeff2 = new double[tmpDeg+1]; // for (int i = 0; i <= tmpDeg ; i++) { // coeff2[i] = coeff[i]; // } // return new Polynomial(coeff2); // } else { // return new Polynomial(coeff); // } } // returns a * b public Polynomial times(Polynomial b) { // Pawel put in corner // double[] coeff = new double[deg + b.deg + 1]; double[] coeffZero = {0}; Polynomial zero = new Polynomial(coeffZero); if (this.equal(zero) || b.equal(zero)) return zero; double[] coeff = new double[deg + b.deg+1]; for (int i = 0; i <= deg; i++) for (int j = 0; j <= b.deg; j++) coeff[i+j] += this.coeff[i] * b.coeff[j]; return new Polynomial(coeff); } // Daisy put in corner // /** // * dividing a polynomial by another polynomial of the same or lower degree // * @param d // * @return // */ // public PairOfPolynomials longDivision(Polynomial d) { // if (d.isZeroPolynomial()) throw new IllegalArgumentException("Divisor is a zero polynomial"); // Polynomial q = new Polynomial(); // Polynomial r = clone(); // while (!r.isZeroPolynomial() && (r.deg >= d.deg)) { // double[] coefficients = new double[r.deg - d.deg + 1]; // coefficients[r.deg - d.deg] = r.coeff[r.deg]/d.coeff[d.deg]; // Polynomial t = new Polynomial(coefficients); // q = q.plus(t); // r = r.minus(t.times(d)); // } // return new PairOfPolynomials(q, r); // } // // public Polynomial greatestCommonDivisor(Polynomial b) { // if (b.deg == 0) return this; // if (b.dominates(this)) return this.greatestCommonDivisor(b.longDivision(this).q); // else return b.greatestCommonDivisor(this.longDivision(b).q.toMonic()); // } // // public ArrayList squareFreeFactorizationTH() { // ArrayList p = new ArrayList(); // Polynomial c, cN, d, dN; // c = this.greatestCommonDivisor(this.differentiate()); // d = this.longDivision(c).p; // while (c.deg != 0) { // cN = c.greatestCommonDivisor(c.differentiate()); // dN = c.longDivision(cN).p; // p.add(d.longDivision(dN).p); // c = cN; // d = dN; // } // return p; // } // // public ArrayList squareFreeFactorization() { // Polynomial deriv = this.differentiate(); // deriv.makeMonic(); // ArrayList a = new ArrayList(); // Polynomial b; // Polynomial c; // Polynomial d; // a.add(0, this.greatestCommonDivisor(deriv)); // b = this.longDivision(a.get(0)).p; // c = deriv.longDivision(a.get(0)).p; // d = c.minus(b).differentiate(); // int i = 1; // do { // a.add(i, b.greatestCommonDivisor(d)); // b = b.longDivision(a.get(i)).p; // c = d.longDivision(a.get(i)).p; // d = c.minus(b.differentiate()); // i++; // } while (b.deg != 0); // a.remove(0); // return a; // } // returns a(b(x)) public Polynomial compose(Polynomial b) { double[] coeff = new double[deg + b.deg]; for (int i = deg; i >= 0; i--) { for (int j = b.deg; j >= 0; j--) coeff[i+j] += this.coeff[i]*b.coeff[j]; } return new Polynomial(coeff); } // do a and b represent the same polynomial? public boolean equal(Polynomial b) { if (deg != b.deg) return false; for (int i = deg; i >= 0; i--) if (coeff[i] != b.coeff[i]) return false; return true; } // use Horner's method to compute and return the polynomial evaluated at x public double evaluate(int x) { double p = 0; for (int i = deg; i >= 0; i--) p = coeff[i] + (x * p); return p; } // public void makeMonic() { // for (int i = 0; i <= deg; i++) this.coeff[i] = coeff[i]/coeff[deg]; // } public Polynomial toMonic() { Polynomial p = this.clone(); for (int i = 0; i <= deg; i++) p.coeff[i] = p.coeff[i]/p.coeff[deg]; return p; } // differentiate this polynomial and return it public Polynomial differentiate() { if (deg == 0) return new Polynomial(new double[1]); double[] par = new double[deg]; for (int i = 0; i < deg; i++) { par[i] = (i+1) * coeff[i+1]; // for (int i = 1; i <= deg; i++) { // par[i-1] = i * coeff[i]; } return new Polynomial(par); } // convert to string representation public String toString() { if (deg == 0) return "" + coeff[0]; if (deg == 1) return coeff[1] + "x + " + coeff[0]; String s = coeff[deg] + "x^" + deg; for (int i = deg-1; i >= 0; i--) { if (coeff[i] == 0) continue; else if (coeff[i] > 0) s = s + " + " + ( coeff[i]); else if (coeff[i] < 0) s = s + " - " + (-coeff[i]); if (i == 1) s = s + "x"; else if (i > 1) s = s + "x^" + i; } return s; } /** * Find the roots of the polynomial. The imaginary part is not returned. * @return an array containing the roots of the polynomial */ public double[] calcRoots(){ return calcRoots(coeff); } /** * Find the roots of the polynomial specified by the parameters. The imaginary part is not returned. * @param parameters an array representing the coefficents of the polynomial * @return an array containing the roots of the polynomial */ public static double[] calcRoots(double[] parameters){ if (parameters.length-1 == 2) return solveSecondDegree(parameters); if (parameters.length-1 == 3) return solveThirdDegree(parameters); return null; } /** * Find the roots of a second degree polynomial. The length of the returned array depends on * how many roots the quadratic equation has. In other words: The imaginary part is removed completely. * @param a coefficient of the squared term * @param b coefficient of the linear term * @param c coefficient of the constant * @return an array containing the roots of the polynomial */ public static double[] calcRoots(double a, double b, double c){ return solveSecondDegree(new double[]{a,b,c}); } /** * Find the roots of a third degree polynomial. The length of the returned array depends on * how many roots the cubic equation has. In other words: The imaginary part is removed completely. * @param a coefficient of the cubed term * @param b coefficient of the squared term * @param c coefficient of the linear term * @param d coefficient of the constant term * @return an array containing the roots of the polynomial */ public static double[] calcRoots(double a, double b, double c, double d){ double[] roots = solveThirdDegree(new double[]{a,b,c,d}); if(roots.length<4) return roots; if(roots[3]>Constants.EPSILON) return new double[]{roots[0]}; int l = 1; for(int i=1;i<3;i++) if(!Double.isNaN(roots[i]) && roots[i-1]!=roots[i]) l++; double[] ret = new double[l]; l=0; for(int i=0;i<3;i++) if(!Double.isNaN(roots[i]) && (i==0||roots[i-1]!=roots[i])) ret[l++] = roots[i]; Arrays.sort(ret); return ret; } /* * TODO: Pawel siger .. m___ske ikke f___rdig */ private static double[] solveQuadric(double p2, double p1, double p0) { double b = p1/p2; double c = p0/p2; double D = b*b - 4*c; if (D > 0.0) { double sqrtD = Math.sqrt(D); return new double[]{(sqrtD - b)/2, (-sqrtD - b)/2}; } else { if (D < 0.0) return new double[]{}; else return new double[]{-b/2}; } } // Daisy public Double solveFirstDegree() { return ((-this.coeff[0])/this.coeff[1]); } public Double[] solveSecondDegree() { //Copy of solveSecondDegree(double[] parameters) double a = this.coeff[2]; double b = this.coeff[1]; double c = this.coeff[0]; double p = -0.5*b/a; double D = p*p-c/a; if(D<0) return new Double[]{}; if(D==0) return new Double[]{p}; else { double sqD = Math.sqrt(D); return new Double[]{p-sqD, p+sqD}; } } /** * Solves quadratic equation. * @hops 4 to 5. */ private static double[] solveSecondDegree(double[] parameters){ double a = parameters[2]; double b = parameters[1]; double c = parameters[0]; double p = -0.5*b/a; //2HOps double D = p*p-c/a; //2HOps // double D = b*b-4*a*c; if(D<0) return new double[]{}; // if(D==0) return new double[]{-b/(2*a)}; if(D==0) return new double[]{p}; else { // double aa = 2*a; double sqD = Math.sqrt(D); //1HOp // return new double[]{(-b-sqD)/aa, (-b+sqD)/aa}; return new double[]{p-sqD, p+sqD}; } } /** * Solves cubic equation. * @hops 3 to 35 * Daisy made it public */ public static double[] solveThirdDegree(double[] parameters){ if(parameters[0]==0) return solveSecondDegree(new double[]{parameters[1],parameters[2],parameters[3]}); double a = parameters[1]/parameters[0]; double b = parameters[2]/parameters[0]; double c = parameters[3]/parameters[0]; double Q = (3*b-a*a)/9; double R = (9*a*b-27*c-2*a*a*a)/54; //Polynomial discriminant double D = Q*Q*Q + R*R; double aThirds = a/3;//17HOps so far double root1, root2, root3, im; if(D>=0){ //Complex or duplicate roots double sqrtD = sqrt(D); double S = sign(R+sqrtD)*Math.cbrt(abs(R+sqrtD)); double T = sign(R-sqrtD)*Math.cbrt(abs(R-sqrtD));//22HOps so far root1 = -aThirds + S+T; root2 = -aThirds - (S+T)/2; root3 = root2; im = abs(Constants.SQRT3*(S-T)/2);//24HOps so far }else { double sqrtMQ = sqrt(-Q); double th = acos(R/(-Q*sqrtMQ)); //acos(R/sqrt(-Q*Q*Q));//21HOps so far root1 = 2*sqrtMQ*cos(th/3)-aThirds; root2 = 2*sqrtMQ*cos((th+2*PI)/3)-aThirds; root3 = 2*sqrtMQ*cos((th+4*PI)/3)-aThirds;//35HOps so far im = 0; } return new double[]{root1,root2, root3, im}; } private static double[] depressQuarticEquation(double[] parameters) { double a = parameters[0]; double b = parameters[1]; double c = parameters[2]; double d = parameters[3]; double e = parameters[4]; return new double[]{a, 0, -3*b*b/(8*a) + c, b*b*b/(8*a*a) - b*c/(2*a) + d, -3*b*b*b*b/(256*a*a*a) + b*b*c/(16*a*a) - b*d/(4*a) + e}; } private static double[] solveDepressedQuartic(double[] parameters) { double A = parameters[2]; double B = parameters[3]; double C = parameters[4]; double[] thirdDegree = solveThirdDegree(new double[]{-8, 4*A - 24*Math.sqrt(C), 8*A*Math.sqrt(C) - 16*C, B*B}); return thirdDegree; } private static double[] solveFourthDegree(double[] parameters){ if(parameters[0]==0) return solveThirdDegree(new double[]{parameters[1],parameters[2],parameters[3],parameters[4]}); double a1 = parameters[1]/parameters[0]; double a2 = parameters[2]/parameters[0]; double a3 = parameters[3]/parameters[0]; double a4 = parameters[4]/parameters[0]; double b1 = -a2; double b2 = a1*a3 - 4*a4; double b3 = 4*a2*a4 - a3*a3 - a1*a1*a4; double[] cubicRoots = solveThirdDegree(new double[]{1, b1, b2, b3}); double y1 = cubicRoots[0]; double d1 = Math.sqrt(a1*a1 - 4*a2 + 4*y1); double d2 = Math.sqrt(y1 -4*a4); double c1 = (a1 + d1)/2; double c2 = (y1*y1 - d2)/2; double[] firstPair = solveSecondDegree(new double[]{1, c1, c2}); c1 = (a1 - d1)/2; c2 = (y1*y1 + d2)/2; double[] secondPair = solveSecondDegree(new double[]{1, c1, c2}); return new double[]{firstPair[0], firstPair[1], secondPair[0], secondPair[1]}; } public static Double[] solveQuartic(double[] c) { DecimalFormat newFormat = new DecimalFormat("#.#########"); c[0] = Double.valueOf(newFormat.format(c[0])); c[1] = Double.valueOf(newFormat.format(c[1])); c[2] = Double.valueOf(newFormat.format(c[2])); c[3] = Double.valueOf(newFormat.format(c[3])); c[4] = Double.valueOf(newFormat.format(c[4])); Double[] roots = new Double[4]; double[] coeffs= new double[ 4 ]; double z, u, v, sub; double A, B, C, D; double sq_A, p, q, r; int i, num = 0; // normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 A = c[ 3 ] / c[ 4 ]; B = c[ 2 ] / c[ 4 ]; C = c[ 1 ] / c[ 4 ]; D = c[ 0 ] / c[ 4 ]; // substitute x = y - A/4 to eliminate cubic term: x^4 + px^2 + qx + r = 0 sq_A = A * A; p = - 3.0/8.0 * sq_A + B; q = 1.0/8.0 * sq_A * A - 1.0/2.0 * A * B + C; r = - 3.0/256.0 * sq_A * sq_A + 1.0/16.0 * sq_A * B - 1.0/4.0 * A*C + D; if (Math.abs(r)==0.0) { // no absolute term: y(y^3 + py + q) = 0 coeffs[ 0 ] = q; coeffs[ 1 ] = p; coeffs[ 2 ] = 0; coeffs[ 3 ] = 1; Double[] s = solveCubic(coeffs); int sLen = 0; for (Double d : s) { if (d != null) sLen += 1; } num = sLen; roots[ num++ ] = 0.0; } else { // solve the resolvent cubic coeffs[ 0 ] = 1.0/2.0 * r * p - 1.0/8.0 * q * q; coeffs[ 1 ] = - r; coeffs[ 2 ] = - 1.0/2.0 * p; coeffs[ 3 ] = 1.0; Double[] s = solveCubic(coeffs); // take the one real solution z = s[ 0 ]; // to build two quadric equations u = z * z - r; v = 2 * z - p; if (Math.abs(u)==0.0) { u = 0.0; } else if (u > 0) { u = Math.sqrt(u); } else { return null; } if (Math.abs(v)==0.0) { v = 0; } else if (v > 0) { v = Math.sqrt(v); } else { return null; } coeffs[ 0 ] = z - u; if (q < 0) { coeffs[ 1 ] = -v; } else coeffs[ 1 ] = v; coeffs[ 2 ] = 1; Double[] s1 = solveQuadric(coeffs); coeffs[ 0 ]= z + u; if (q < 0) { coeffs[ 1 ] = v; } else coeffs[ 1 ] = -v; coeffs[ 2 ] = 1; Double[] s2 = solveQuadric(coeffs); int s1Len = 0; int s2Len = 0; if (s1 != null) { for (Double d : s1) { if (d != null) s1Len += 1; } } if (s2 != null) { for (Double d : s2) { if (d != null) s2Len += 1; } } roots = new Double[s1Len+s2Len]; int k = 0; if (s1Len>0) { for (Double d : s1) { if (d==null) break; roots[k] = s1[k]; k += 1; } } if (s2Len>0) { for (Double d : s2) { if (d==null) break; roots[k] = s2[k%2]; k += 1; } } num = s1Len+s2Len; if (num == 0) return null; } // resubstitute sub = 1.0/4.0 * A; for (i = 0; i < num; ++i){ roots[ i ] -= sub; } return roots; } public static Double[] solveCubic(double[] c) { Double[] roots = new Double[3]; int i, num; double sub; double A, B, C; double sq_A, p, q; double cb_p, D; // normal form: x^3 + Ax^2 + Bx + C = 0 A = c[ 2 ] / c[ 3 ]; B = c[ 1 ] / c[ 3 ]; C = c[ 0 ] / c[ 3 ]; // substitute x = y - A/3 to eliminate quadric term: x^3 +px + q = 0 sq_A = A * A; p = 1.0/3.0 * (- 1.0/3.0 * sq_A + B); q = 1.0/2.0 * (2.0/27.0 * A * sq_A - 1.0/3.0 * A * B + C); // use Cardano's formula cb_p = p * p * p; D = q * q + cb_p; if (Math.abs(D)==0.0) { if (Math.abs(q) 0) { double sqrt_D = Math.sqrt(D); roots[ 0 ] = sqrt_D - p; roots[ 1 ] = - sqrt_D - p; return roots; } return null; } private double gcd(double a, double b){ while (b!=0) { double tmp = Math.abs(a) % Math.abs(b); a = Math.abs(b); b = tmp; if (Math.abs(b)<=Constants.EPSILON) b = 0.0; } return a; } public List squareFreeFact() { double gcd1 = gcd(this.coeff[4], this.coeff[3]); double gcd2 = gcd(gcd1, this.coeff[2]); double gcd3 = gcd(gcd2, this.coeff[1]); double gcd4 = gcd(gcd3, this.coeff[0]); System.out.println("GCD = "+gcd4); System.out.println("Old f = "+this.toString()); double[] f_newCoeff = {this.coeff[0]/gcd4, this.coeff[1]/gcd4, this.coeff[2]/gcd4, this.coeff[3]/gcd4, this.coeff[4]/gcd4}; Polynomial f_new = new Polynomial(f_newCoeff); System.out.println("New f = "+f_new.toString()); /* double[] depressedPars = new double[5]; double a = this.coeff[3]/this.coeff[4]; double b = this.coeff[2]/this.coeff[4]; double c = this.coeff[1]/this.coeff[4]; double tmpd = this.coeff[0]/this.coeff[4]; double p = (8*b-3*a*a)/8; double q = (Math.pow(a, 3)-4*a*b+8*c)/8; double r = ((-3)*Math.pow(a, 4)+256*tmpd-64*c*a+16*a*a*b)/256; depressedPars[0] = r; depressedPars[1] = q; depressedPars[2] = p; depressedPars[4] = 1; Polynomial f = new Polynomial(depressedPars); double[] cubicPars = new double[4]; cubicPars[0] = (Math.pow(p, 3)/2)-((p*r)/2)-((q*q)/8); cubicPars[1] = 2*p*p-r; cubicPars[2] = (5/2)*p; cubicPars[3] = 1; // Polynomial cubic = new Polynomial(cubicPars); double[] cubicRoots = solveThirdDegree(cubicPars); double y = 0; for (double root : cubicRoots) { if (p+2*root != 0.0) { y = root; break; } } System.out.println("y = "+y); System.out.println("p = "+p); System.out.println("p = p ?"+(p == (8*this.coeff[2]*this.coeff[4]-3*this.coeff[3]*this.coeff[3])/(8*this.coeff[4]*this.coeff[4]))); System.out.println("q = "+q); System.out.println("r = "+r); double constant = -(this.coeff[3]/(4*this.coeff[4])); double [] xs = new double[4]; xs[0] = constant + (Math.sqrt(p+2*y)+Math.sqrt(-(3*p+2*y+((2*q)/Math.sqrt(p+2*y)))))/2; xs[1] = constant + (-Math.sqrt(p+2*y)+Math.sqrt(-(3*p+2*y-((2*q)/Math.sqrt(p+2*y)))))/2; xs[2] = constant + (Math.sqrt(p+2*y)-Math.sqrt(-(3*p+2*y+((2*q)/Math.sqrt(p+2*y)))))/2; xs[3] = constant + (-Math.sqrt(p+2*y)-Math.sqrt(-(3*p+2*y-((2*q)/Math.sqrt(p+2*y)))))/2; for (int i = 0; i<4; i++) { System.out.println("Root = "+xs[i]); }*/ System.out.println("SquareFree going!"); List ret = new ArrayList(); Polynomial fPrime = this.differentiate(); System.out.println("func' = "+fPrime.toString()); Polynomial d = gcd(this, fPrime); System.out.println("d1 = "+d.toString()); Polynomial e = (this.longDivision(d))[0]; System.out.println("e1 = "+e.toString()); double[] coeffOne = {1}; Polynomial one = new Polynomial(coeffOne); Polynomial dPrime; Polynomial d_new; Polynomial e_new; while (!(d.equal(one))) {//d.deg==0 { dPrime = d.differentiate(); System.out.println("d = "+d.toString()); System.out.println("dPrime = "+dPrime.toString()); d_new = gcd(d, dPrime); System.out.println("d_new = "+d_new.toString()); e_new = (d.longDivision(d_new)[0]); System.out.println("eNew = d/dNew = "+d.toString()+" / "+d_new.toString()); System.out.println("e/eNew = "+e.toString()+" / "+e_new.toString()); System.out.println(" "+(e.longDivision(e_new))[0]); ret.add((e.longDivision(e_new))[0].makeMonic()); if (d_new.equal(one)) { ret.add(d); } /* Polynomial b_new; Polynomial b = fPrime.longDivision(d.minus(e.differentiate()))[0]; while (!(e.equal(one))) { d = gcd(e, b); ret.add(d); e_new = e.longDivision(d)[0]; b_new = b.longDivision(d.minus(e_new.differentiate()))[0]; d_new = gcd(e, d); e_new = e.longDivision(d_new)[0]; ret.add(e_new);*/ d = d_new; e = e_new; double greatCoeff = d.coeff[d.deg]; for (int i = 0 ; i=dDeg) { Polynomial t = leadDiv(r, d); if (t == null) { ret[0] = q; ret[1] = zero; return ret; } System.out.println("t = "+t.toString()); q = q.plus(t); r = r.minus(t.times(d)); // System.out.println("intermediate rest = "+r.toString()); if (r.deg==0) { if (Math.abs(r.coeff[0])= (1.0-Constants.EPSILON)) { System.out.println("rounding : "+monicPars[i]); System.out.println("because "+Math.abs(monicPars[i])+" <= "+(Constants.EPSILON+1.0)); monicPars[i] = 1.0; } } return new Polynomial(monicPars); } private List distinctFact() { List ret = new ArrayList(); Polynomial f = this; double[] coeffOne = new double[]{1}; Polynomial one = new Polynomial(coeffOne); int i = 1; while (f.getDeg() >= (2*i)) { double[] tmpPars = new double[i+1]; tmpPars[i] = 1; tmpPars[1] = -1; Polynomial g = gcd(f, new Polynomial(tmpPars)); if (!g.equal(one)) { ret.add(g); f = f.longDivision(g)[0]; } i += 1; } if (!f.equal(one)) { ret.add(f); } // if (ret == null) { // ret.add(this); // } return ret; } // Daisy ends private static double sign(double n){ return n<0?-1:1; } /* Descarte's Rule of Signs: The number of positive roots is either equal to the number of changes in * signs of the cooefficient (zero coefficient is assumed to have the same sign as its predecessor) or * is less by a multiple of 2 */ public int numberPositiveRoots() { int count = 0; for (int i = 0; i < deg; i++) if (coeff[i]*coeff[i+1] < 0.0) count++; return count; } /* number of negative roots in P(x) is the same as the number of positive roots in P(-x) */ public int numberNegativeRoots() { int count = deg + 1 - numberPositiveRoots(); for (int i = 1; i <= deg; i++) if (coeff[i] == 0.0) count--; return count; } /* polynomium a[n]*x^n + a[n-1]*x^(n-1) + ... + a[1]*x + a[0] */ public static double solveHighDegree(double[] a) { boolean convergence = false; boolean divisionByZero = false; double x = 1; double xNext = 1.0; double[] d = new double[a.length-1]; for (int j = 0; j < d.length; j++) d[j] = (j+1)*a[j+1]; double tolerance = 0.00000001; int maxIterations = 100; double num = 0.0; double denum = 0.0; int i = 0; while ((i < maxIterations) && !convergence && !divisionByZero) { i++; num = a[a.length-2] + x*a[a.length-1]; denum = d[a.length-2]; for (int j = a.length-3; j >= 0; j--) { num = a[j] + x*num; denum = d[j] + x*denum; } if (Math.abs(denum) < Constants.EPSILON) { System.out.println("WARNING: denominator is too small"); divisionByZero = true; } else { xNext = x - num/denum; if (Math.abs(xNext - x) < tolerance) convergence = true; x = xNext; } } if (divisionByZero) System.out.println("WARNING: division by zero"); if (convergence) { if (Math.abs(num) > Constants.EPSILON) System.out.println("WARNING: convergence not to the root"); return xNext; } else { System.out.println("WARNING: solution not within specified tolerance"); return xNext; } } public static void main(String[] args){ double[] solution = Polynomial.solveQuadric(3, -2, -5); double[] depressedQuartic = Polynomial.depressQuarticEquation(new double[] {1,8,12,2*Math.sqrt(30)-16, 4*Math.sqrt(30)-28}); Polynomial.solveDepressedQuartic(depressedQuartic); Polynomial.solveFourthDegree(new double[]{3.0, 6.0, -123.0, -126.0, 1080.0}); /* double[] a = new double[6]; a[0] = 6; a[1] = 5; a[2] = 4; a[3] = 3; a[4] = 2; a[5] = 1; double root = Polynomial.solveHighDegree(a); */ //TODO: Move to test // double[] a = new double[12]; // double[] b = new double[4]; // double[] b2 = new double[4]; // double[] c = new double[5]; // double[] c2 = new double[4]; // double[] d = new double[7]; // /*b[0] = -2.5750749675480734E14; // b[1]= 1.2142986273055004E10; // b[2] = -190866.11854848347; // b[3] = 1;*/ // b[0] = -75; // b[1]= 49; // b[2] = -11; // b[3] = 1; // b2[0] = 1; // b2[1]= -11; // b2[2] = 49; // b2[3] = -75; // //5.71868E-4x^4 + 0.574504513x^3 - 1.867761297x^2 - 0.758281783x - 0.059311159 // c[4] = 5.71868E-4; // c[3]= 0.574504513; // c[2] = - 1.867761297; // c[1] = - 0.758281783; // c[0] = - 0.059311159; // Double[] quarroots = solveQuartic(c); // for (double root : quarroots) { // System.out.println("Qaud root : "+root); // } // // //c[0] = -228.14885350604553; c[1]= 284.5029410954643; c[2] = -31.343804547815083; c[3] = 1; // System.out.println("poly = "+b[3]+"x^3 + "+b[2]+"x^2 + "+b[1]+"x + "+b[0]); // //Complex[] cubroots = solveCubic(b); // Double[] cubroots = solveCubic(b); // for (Double r : cubroots) { // System.out.println("cubroot: "+r.toString()); // } /* double[] pC = new double[3]; pC[2] = 1; pC[1] = -9; pC[0] = -10; double[] qC = new double[2]; qC[1] = -9; qC[0] = -10; Polynomial p = new Polynomial(pC); Polynomial q = new Polynomial(qC); PairOfPolynomials pair = p.longDivision(q); System.out.println("(" + pair.p.toString() +" , " + pair.q + ")"); */ /* double[] pC = new double[3]; pC[2] = 1; pC[1] = 0; pC[0] = 2; double[] qC = new double[3]; qC[2] = 2; qC[1] = 0; qC[0] = 2; Polynomial p = new Polynomial(pC).toMonic(); Polynomial q = new Polynomial(qC).toMonic(); Polynomial gcd = p.greatestCommonDivisor(q); System.out.println(gcd.toString()); */ /* double[] pC = new double[12]; pC[11] = 1; pC[10] = 4; pC[9] = -9; pC[8] = -46; pC[7] = 23; pC[6] = 192; pC[5] = -7; pC[4] = -358; pC[3] = -24; pC[2] = 304; pC[1] = 16; pC[0] = 96; Polynomial p = new Polynomial(pC); ArrayList a = p.squareFreeFactorization(); */ /* double[] pC = new double[9]; pC[8] = 1; pC[7] = 0; pC[6] = 6; pC[5] = 0; pC[4] = 12; pC[3] = 0; pC[2] = 8; pC[1] = 0; pC[0] = 0; Polynomial p = new Polynomial(pC); ArrayList a = p.squareFreeFactorizationTH(); */ } }