diff --git a/src/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java b/src/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java index 2db950700..a515b8736 100644 --- a/src/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java +++ b/src/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java @@ -32,25 +32,26 @@ import org.apache.commons.math.analysis.UnivariateRealFunction; public class PolynomialFunction implements DifferentiableUnivariateRealFunction, Serializable { /** Serializable version identifier */ - private static final long serialVersionUID = 3322454535052136809L; - + private static final long serialVersionUID = -7726511984200295583L; + /** * The coefficients of the polynomial, ordered by degree -- i.e., * coefficients[0] is the constant term and coefficients[n] is the * coefficient of x^n where n is the degree of the polynomial. */ - private double coefficients[]; + private final double coefficients[]; /** * Construct a polynomial with the given coefficients. The first element * of the coefficients array is the constant term. Higher degree * coefficients follow in sequence. The degree of the resulting polynomial - * is the length of the array minus 1. + * is the index of the last non-null element of the array, or 0 if all elements + * are null. *

* The constructor makes a copy of the input array and assigns the copy to * the coefficients property.

* - * @param c polynominal coefficients + * @param c polynomial coefficients * @throws NullPointerException if c is null * @throws IllegalArgumentException if c is empty */ @@ -59,8 +60,12 @@ public class PolynomialFunction implements DifferentiableUnivariateRealFunction, if (c.length < 1) { throw new IllegalArgumentException("Polynomial coefficient array must have postive length."); } - this.coefficients = new double[c.length]; - System.arraycopy(c, 0, this.coefficients, 0, c.length); + int l = c.length; + while ((l > 1) && (c[l - 1] == 0)) { + --l; + } + this.coefficients = new double[l]; + System.arraycopy(c, 0, this.coefficients, 0, l); } /** @@ -97,9 +102,7 @@ public class PolynomialFunction implements DifferentiableUnivariateRealFunction, * @return a fresh copy of the coefficients array */ public double[] getCoefficients() { - double[] out = new double[coefficients.length]; - System.arraycopy(coefficients,0, out, 0, coefficients.length); - return out; + return coefficients.clone(); } /** @@ -123,7 +126,96 @@ public class PolynomialFunction implements DifferentiableUnivariateRealFunction, } return result; } - + + /** + * Add a polynomial to the instance. + * @param p polynomial to add + * @return a new polynomial which is the sum of the instance and p + */ + public PolynomialFunction add(final PolynomialFunction p) { + + // identify the lowest degree polynomial + final int lowLength = Math.min(coefficients.length, p.coefficients.length); + final int highLength = Math.max(coefficients.length, p.coefficients.length); + + // build the coefficients array + double[] newCoefficients = new double[highLength]; + for (int i = 0; i < lowLength; ++i) { + newCoefficients[i] = coefficients[i] + p.coefficients[i]; + } + System.arraycopy((coefficients.length < p.coefficients.length) ? + p.coefficients : coefficients, + lowLength, + newCoefficients, lowLength, + highLength - lowLength); + + return new PolynomialFunction(newCoefficients); + + } + + /** + * Subtract a polynomial from the instance. + * @param p polynomial to subtract + * @return a new polynomial which is the difference the instance minus p + */ + public PolynomialFunction subtract(final PolynomialFunction p) { + + // identify the lowest degree polynomial + int lowLength = Math.min(coefficients.length, p.coefficients.length); + int highLength = Math.max(coefficients.length, p.coefficients.length); + + // build the coefficients array + double[] newCoefficients = new double[highLength]; + for (int i = 0; i < lowLength; ++i) { + newCoefficients[i] = coefficients[i] - p.coefficients[i]; + } + if (coefficients.length < p.coefficients.length) { + for (int i = lowLength; i < highLength; ++i) { + newCoefficients[i] = -p.coefficients[i]; + } + } else { + System.arraycopy(coefficients, lowLength, newCoefficients, lowLength, + highLength - lowLength); + } + + return new PolynomialFunction(newCoefficients); + + } + + /** + * Negate the instance. + * @return a new polynomial + */ + public PolynomialFunction negate() { + double[] newCoefficients = new double[coefficients.length]; + for (int i = 0; i < coefficients.length; ++i) { + newCoefficients[i] = -coefficients[i]; + } + return new PolynomialFunction(newCoefficients); + } + + /** + * Multiply the instance by a polynomial. + * @param p polynomial to multiply by + * @return a new polynomial + */ + public PolynomialFunction multiply(final PolynomialFunction p) { + + double[] newCoefficients = new double[coefficients.length + p.coefficients.length - 1]; + + for (int i = 0; i < newCoefficients.length; ++i) { + newCoefficients[i] = 0.0; + for (int j = Math.max(0, i + 1 - p.coefficients.length); + j < Math.min(coefficients.length, i + 1); + ++j) { + newCoefficients[i] += coefficients[j] * p.coefficients[i-j]; + } + } + + return new PolynomialFunction(newCoefficients); + + } + /** * Returns the coefficients of the derivative of the polynomial with the given coefficients. * @@ -164,5 +256,66 @@ public class PolynomialFunction implements DifferentiableUnivariateRealFunction, public UnivariateRealFunction derivative() { return polynomialDerivative(); } - + + /** Returns a string representation of the polynomial. + + *

The representation is user oriented. Terms are displayed lowest + * degrees first. The multiplications signs, coefficients equals to + * one and null terms are not displayed (except if the polynomial is 0, + * in which case the 0 constant term is displayed). Addition of terms + * with negative coefficients are replaced by subtraction of terms + * with positive coefficients except for the first displayed term + * (i.e. we display -3 for a constant negative polynomial, + * but 1 - 3 x + x^2 if the negative coefficient is not + * the first one displayed).

+ + * @return a string representation of the polynomial + + */ + public String toString() { + + StringBuffer s = new StringBuffer(); + if (coefficients[0] == 0.0) { + if (coefficients.length == 1) { + return "0"; + } + } else { + s.append(Double.toString(coefficients[0])); + } + + for (int i = 1; i < coefficients.length; ++i) { + + if (coefficients[i] != 0) { + + if (s.length() > 0) { + if (coefficients[i] < 0) { + s.append(" - "); + } else { + s.append(" + "); + } + } else { + if (coefficients[i] < 0) { + s.append("-"); + } + } + + double absAi = Math.abs(coefficients[i]); + if ((absAi - 1) != 0) { + s.append(Double.toString(absAi)); + s.append(' '); + } + + s.append("x"); + if (i > 1) { + s.append('^'); + s.append(Integer.toString(i)); + } + } + + } + + return s.toString(); + + } + } diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index 11eaa2819..f189b53b1 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,6 +39,9 @@ The type attribute can be add,update,fix,remove. + + Added add, subtract, negate, multiply and toString methods to PolynomialFunction. + Changed FractionFormat to extend NumberFormat. diff --git a/src/test/org/apache/commons/math/analysis/polynomials/PolynomialFunctionTest.java b/src/test/org/apache/commons/math/analysis/polynomials/PolynomialFunctionTest.java index 343ad1dce..25997c4b9 100644 --- a/src/test/org/apache/commons/math/analysis/polynomials/PolynomialFunctionTest.java +++ b/src/test/org/apache/commons/math/analysis/polynomials/PolynomialFunctionTest.java @@ -160,4 +160,80 @@ public final class PolynomialFunctionTest extends TestCase { } + public void testString() { + PolynomialFunction p = new PolynomialFunction(new double[] { -5.0, 3.0, 1.0 }); + checkPolynomial(p, "-5.0 + 3.0 x + x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 0.0, -2.0, 3.0 }), + "-2.0 x + 3.0 x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 1.0, -2.0, 3.0 }), + "1.0 - 2.0 x + 3.0 x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 0.0, 2.0, 3.0 }), + "2.0 x + 3.0 x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 1.0, 2.0, 3.0 }), + "1.0 + 2.0 x + 3.0 x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 1.0, 0.0, 3.0 }), + "1.0 + 3.0 x^2"); + checkPolynomial(new PolynomialFunction(new double[] { 0.0 }), + "0"); + } + + public void testAddition() { + + PolynomialFunction p1 = new PolynomialFunction(new double[] { -2.0, 1.0 }); + PolynomialFunction p2 = new PolynomialFunction(new double[] { 2.0, -1.0, 0.0 }); + checkNullPolynomial(p1.add(p2)); + + p2 = p1.add(p1); + checkPolynomial(p2, "-4.0 + 2.0 x"); + + p1 = new PolynomialFunction(new double[] { 1.0, -4.0, 2.0 }); + p2 = new PolynomialFunction(new double[] { -1.0, 3.0, -2.0 }); + p1 = p1.add(p2); + assertEquals(1, p1.degree()); + checkPolynomial(p1, "-x"); + + } + + public void testSubtraction() { + + PolynomialFunction p1 = new PolynomialFunction(new double[] { -2.0, 1.0 }); + checkNullPolynomial(p1.subtract(p1)); + + PolynomialFunction p2 = new PolynomialFunction(new double[] { -2.0, 6.0 }); + p2 = p2.subtract(p1); + checkPolynomial(p2, "5.0 x"); + + p1 = new PolynomialFunction(new double[] { 1.0, -4.0, 2.0 }); + p2 = new PolynomialFunction(new double[] { -1.0, 3.0, 2.0 }); + p1 = p1.subtract(p2); + assertEquals(1, p1.degree()); + checkPolynomial(p1, "2.0 - 7.0 x"); + + } + + public void testMultiplication() { + + PolynomialFunction p1 = new PolynomialFunction(new double[] { -3.0, 2.0 }); + PolynomialFunction p2 = new PolynomialFunction(new double[] { 3.0, 2.0, 1.0 }); + checkPolynomial(p1.multiply(p2), "-9.0 + x^2 + 2.0 x^3"); + + p1 = new PolynomialFunction(new double[] { 0.0, 1.0 }); + p2 = p1; + for (int i = 2; i < 10; ++i) { + p2 = p2.multiply(p1); + checkPolynomial(p2, "x^" + i); + } + + } + + public void checkPolynomial(PolynomialFunction p, String reference) { + assertEquals(reference, p.toString()); + } + + private void checkNullPolynomial(PolynomialFunction p) { + for (double coefficient : p.getCoefficients()) { + assertEquals(0.0, coefficient, 1.0e-15); + } + } + }