Java tutorial
/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ /* * PolynomialUtils.java * * Created on 17.08.2011, 13:05 */ package geogebra.kernel.implicit; import geogebra.kernel.Kernel; import org.apache.commons.math.analysis.polynomials.PolynomialFunction; public class PolynomialUtils { /** * calculates the quotient of p/d (no calculation of the remainder is done) * @param cp * @param cd * @return quotient of cp/cd */ public static double[] polynomialDivision(double[] cp, double[] cd) { double[] cq; cp = cp.clone(); int degD = cd.length - 1; while (degD >= 0 && Kernel.isZero(cd[degD])) { degD--; } if (degD < 0) { // => division by zero throw new ArithmeticException("divide by zero polynomial"); } if (cp.length - 1 < degD) { return new double[] { 0 }; } else { cq = new double[cp.length - degD]; } double lcd = cd[degD]; int k = cp.length - 1; for (int i = cq.length - 1; i >= 0; i--) { cq[i] = cp[k] / lcd; for (int j = 0; j <= degD - 1; j++) { cp[j + i] = cp[j + i] - cq[i] * cd[j]; } k--; } return cq; } /** * calculates the quotient of p/d (no calculation of the remainder is done) * @param p * @param d * @return quotient of p/d */ public static PolynomialFunction polynomialDivision(PolynomialFunction p, PolynomialFunction d) { return new PolynomialFunction(polynomialDivision(p.getCoefficients(), d.getCoefficients())); } public static int getDegree(PolynomialFunction p) { return getDegree(p.getCoefficients()); } public static int getDegree(double[] c) { for (int i = c.length - 1; i >= 0; i--) { if (!Kernel.isZero(c[i])) return i; } return -1; } public static double getLeadingCoeff(double[] c) { int d = getDegree(c); if (d >= 0) return c[d]; else return 0; } public static double getLeadingCoeff(PolynomialFunction p) { return getDegree(p.getCoefficients()); } public static double eval(double[] c, double x) { if (c.length == 0) return 0; double s = c[c.length - 1]; for (int i = c.length - 2; i >= 0; i--) { s *= x; s += c[i]; } return s; } public static double[][] coeffMinDeg(double[][] coeff) { double[][] newCoeffMinDeg = null; for (int i = coeff.length - 1; i >= 0; i--) { for (int j = coeff[i].length - 1; j >= 0; j--) { if (!Kernel.isZero(coeff[i][j])) { if (newCoeffMinDeg == null) { newCoeffMinDeg = new double[i + 1][]; } if (newCoeffMinDeg[i] == null) { newCoeffMinDeg[i] = new double[j + 1]; } newCoeffMinDeg[i][j] = coeff[i][j]; } } if (newCoeffMinDeg != null && newCoeffMinDeg[i] == null) { newCoeffMinDeg[i] = new double[1]; newCoeffMinDeg[i][0] = 0; } } if (newCoeffMinDeg == null) { newCoeffMinDeg = new double[1][1]; newCoeffMinDeg[0][0] = 0; } return newCoeffMinDeg; } /** * * @param pair starting value for Newton's-Algorithm * @param p1 * @param line defined by line[0]+x*line[1]+y*line[2]=0 * @return whether a common root of the polynomial and the line was found */ public static boolean rootPolishing(double[] pair, GeoImplicitPoly p1, double[] line) { return rootPolishing(pair, p1, null, line); } public static boolean rootPolishing(double[] pair, GeoImplicitPoly p1, GeoImplicitPoly p2) { return rootPolishing(pair, p1, p2, null); } private static boolean rootPolishing(double[] pair, GeoImplicitPoly p1, GeoImplicitPoly p2, double[] line) { double x = pair[0], y = pair[1]; double p, q; if (p1 == null) { return false; } if (p2 == null && (line == null || line.length != 3)) { return false; } p = p1.evalPolyAt(x, y); if (p2 != null) q = p2.evalPolyAt(x, y); else q = line[0] + x * line[1] + y * line[2]; double lastErr = Double.MAX_VALUE; double err = Math.abs(p) + Math.abs(q); while (err < lastErr && err > Kernel.STANDARD_PRECISION) { double px, py; double qx, qy; px = p1.evalDiffXPolyAt(x, y); py = p1.evalDiffYPolyAt(x, y); if (p2 != null) { qx = p2.evalDiffXPolyAt(x, y); qy = p2.evalDiffYPolyAt(x, y); } else { qx = line[1]; qy = line[2]; } double det = px * qy - py * qx; if (Kernel.isZero(det)) { break; } x -= (p * qy - q * py) / det; y -= (q * px - p * qx) / det; lastErr = err; p = p1.evalPolyAt(x, y); if (p2 != null) { q = p2.evalPolyAt(x, y); } else { q = line[0] + x * line[1] + y * line[2]; } err = Math.abs(p) + Math.abs(q); } pair[0] = x; pair[1] = y; return err < Kernel.STANDARD_PRECISION; } }