1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.analysis.polynomials;
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.Serializable;
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.util.Arrays;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.NoDataException;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction;
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.analysis.UnivariateRealFunction;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.util.FastMath;
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Immutable representation of a real polynomial function with real coefficients.
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <a href="http://mathworld.wolfram.com/HornersMethod.html">Horner's Method</a>
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *  is used to evaluate the function.</p>
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class PolynomialFunction implements DifferentiableUnivariateRealFunction, Serializable {
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Serialization identifier
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = -7726511984200295583L;
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The coefficients of the polynomial, ordered by degree -- i.e.,
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficients[0] is the constant term and coefficients[n] is the
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficient of x^n where n is the degree of the polynomial.
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private final double coefficients[];
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Construct a polynomial with the given coefficients.  The first element
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * of the coefficients array is the constant term.  Higher degree
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficients follow in sequence.  The degree of the resulting polynomial
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is the index of the last non-null element of the array, or 0 if all elements
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * are null.
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The constructor makes a copy of the input array and assigns the copy to
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the coefficients property.</p>
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param c polynomial coefficients
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if c is null
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NoDataException if c is empty
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction(double c[]) {
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super();
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int n = c.length;
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (n == 0) {
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        while ((n > 1) && (c[n - 1] == 0)) {
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            --n;
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.coefficients = new double[n];
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        System.arraycopy(c, 0, this.coefficients, 0, n);
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Compute the value of the function for the given argument.
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  The value returned is <br>
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *   <code>coefficients[n] * x^n + ... + coefficients[1] * x  + coefficients[0]</code>
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </p>
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param x the argument for which the function value should be computed
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the value of the polynomial at the given point
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see UnivariateRealFunction#value(double)
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double value(double x) {
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       return evaluate(coefficients, x);
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  Returns the degree of the polynomial
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the degree of the polynomial
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int degree() {
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return coefficients.length - 1;
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a copy of the coefficients array.
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Changes made to the returned copy will not affect the coefficients of
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the polynomial.</p>
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  a fresh copy of the coefficients array
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getCoefficients() {
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return coefficients.clone();
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Uses Horner's Method to evaluate the polynomial with the given coefficients at
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the argument.
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param coefficients  the coefficients of the polynomial to evaluate
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param argument  the input value
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  the value of the polynomial
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NoDataException if coefficients is empty
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if coefficients is null
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected static double evaluate(double[] coefficients, double argument) {
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int n = coefficients.length;
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (n == 0) {
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double result = coefficients[n - 1];
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int j = n -2; j >=0; j--) {
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            result = argument * result + coefficients[j];
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return result;
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Add a polynomial to the instance.
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p polynomial to add
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a new polynomial which is the sum of the instance and p
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction add(final PolynomialFunction p) {
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // identify the lowest degree polynomial
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int lowLength  = FastMath.min(coefficients.length, p.coefficients.length);
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int highLength = FastMath.max(coefficients.length, p.coefficients.length);
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // build the coefficients array
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] newCoefficients = new double[highLength];
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < lowLength; ++i) {
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            newCoefficients[i] = coefficients[i] + p.coefficients[i];
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        System.arraycopy((coefficients.length < p.coefficients.length) ?
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                         p.coefficients : coefficients,
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                         lowLength,
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                         newCoefficients, lowLength,
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                         highLength - lowLength);
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new PolynomialFunction(newCoefficients);
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Subtract a polynomial from the instance.
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p polynomial to subtract
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a new polynomial which is the difference the instance minus p
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction subtract(final PolynomialFunction p) {
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // identify the lowest degree polynomial
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int lowLength  = FastMath.min(coefficients.length, p.coefficients.length);
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int highLength = FastMath.max(coefficients.length, p.coefficients.length);
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // build the coefficients array
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] newCoefficients = new double[highLength];
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < lowLength; ++i) {
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            newCoefficients[i] = coefficients[i] - p.coefficients[i];
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (coefficients.length < p.coefficients.length) {
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = lowLength; i < highLength; ++i) {
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                newCoefficients[i] = -p.coefficients[i];
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(coefficients, lowLength, newCoefficients, lowLength,
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             highLength - lowLength);
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new PolynomialFunction(newCoefficients);
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Negate the instance.
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a new polynomial
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction negate() {
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] newCoefficients = new double[coefficients.length];
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < coefficients.length; ++i) {
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            newCoefficients[i] = -coefficients[i];
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new PolynomialFunction(newCoefficients);
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Multiply the instance by a polynomial.
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p polynomial to multiply by
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a new polynomial
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction multiply(final PolynomialFunction p) {
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] newCoefficients = new double[coefficients.length + p.coefficients.length - 1];
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < newCoefficients.length; ++i) {
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            newCoefficients[i] = 0.0;
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = FastMath.max(0, i + 1 - p.coefficients.length);
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                 j < FastMath.min(coefficients.length, i + 1);
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                 ++j) {
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                newCoefficients[i] += coefficients[j] * p.coefficients[i-j];
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new PolynomialFunction(newCoefficients);
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the coefficients of the derivative of the polynomial with the given coefficients.
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param coefficients  the coefficients of the polynomial to differentiate
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the coefficients of the derivative or null if coefficients has length 1.
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NoDataException if coefficients is empty
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if coefficients is null
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected static double[] differentiate(double[] coefficients) {
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int n = coefficients.length;
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (n == 0) {
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (n == 1) {
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new double[]{0};
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] result = new double[n - 1];
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = n - 1; i  > 0; i--) {
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            result[i - 1] = i * coefficients[i];
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return result;
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the derivative as a PolynomialRealFunction
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  the derivative polynomial
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public PolynomialFunction polynomialDerivative() {
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new PolynomialFunction(differentiate(coefficients));
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the derivative as a UnivariateRealFunction
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  the derivative function
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public UnivariateRealFunction derivative() {
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return polynomialDerivative();
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Returns a string representation of the polynomial.
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>The representation is user oriented. Terms are displayed lowest
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * degrees first. The multiplications signs, coefficients equals to
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * one and null terms are not displayed (except if the polynomial is 0,
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * in which case the 0 constant term is displayed). Addition of terms
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * with negative coefficients are replaced by subtraction of terms
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * with positive coefficients except for the first displayed term
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * (i.e. we display <code>-3</code> for a constant negative polynomial,
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * but <code>1 - 3 x + x^2</code> if the negative coefficient is not
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the first one displayed).</p>
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a string representation of the polynomial
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     public String toString() {
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       StringBuilder s = new StringBuilder();
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       if (coefficients[0] == 0.0) {
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         if (coefficients.length == 1) {
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           return "0";
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         }
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       } else {
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         s.append(Double.toString(coefficients[0]));
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       }
292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       for (int i = 1; i < coefficients.length; ++i) {
294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         if (coefficients[i] != 0) {
296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           if (s.length() > 0) {
298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             if (coefficients[i] < 0) {
299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond               s.append(" - ");
300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             } else {
301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond               s.append(" + ");
302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             }
303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           } else {
304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             if (coefficients[i] < 0) {
305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond               s.append("-");
306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             }
307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           }
308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           double absAi = FastMath.abs(coefficients[i]);
310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           if ((absAi - 1) != 0) {
311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             s.append(Double.toString(absAi));
312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             s.append(' ');
313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           }
314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           s.append("x");
316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           if (i > 1) {
317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             s.append('^');
318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             s.append(Integer.toString(i));
319dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond           }
320dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         }
321dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
322dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       }
323dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
324dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond       return s.toString();
325dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
326dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     }
327dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
328dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
329dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
330dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int hashCode() {
331dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int prime = 31;
332dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int result = 1;
333dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        result = prime * result + Arrays.hashCode(coefficients);
334dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return result;
335dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
336dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
337dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
338dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
339dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public boolean equals(Object obj) {
340dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (this == obj)
341dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return true;
342dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!(obj instanceof PolynomialFunction))
343dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return false;
344dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        PolynomialFunction other = (PolynomialFunction) obj;
345dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!Arrays.equals(coefficients, other.coefficients))
346dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return false;
347dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return true;
348dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
349dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
350dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
351