1 /* 2 * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.numerical; 17 18 /** 19 * Class to estimate the derivative of a single dimension function at a given 20 * point. 21 * The algorithm used in this implementation is valid for continuous functions 22 * only, otherwise inaccurate results might be obtained. 23 * This implementation is faster although less accurate than 24 * SymmetricDerivativeEstimator. 25 */ 26 public class DerivativeEstimator { 27 28 /** 29 * Constant defining machine precision for this algorithm. 30 */ 31 public static final double EPS = 1e-8; 32 33 /** 34 * Listener to evaluate a single dimension function. 35 */ 36 protected final SingleDimensionFunctionEvaluatorListener listener; 37 38 /** 39 * Constructor 40 * 41 * @param listener listener to evaluate a single dimension function 42 */ 43 public DerivativeEstimator(final SingleDimensionFunctionEvaluatorListener listener) { 44 this.listener = listener; 45 } 46 47 /** 48 * Computes the function derivative at provided point x. 49 * 50 * @param x Point where derivative is estimated 51 * @return Derivative of function at provided point 52 * @throws EvaluationException Raised if function cannot be properly 53 * evaluated 54 */ 55 public double derivative(final double x) throws EvaluationException { 56 final var fold = listener.evaluate(x); 57 58 var h = EPS * Math.abs(x); 59 if (h == 0.0) { 60 // Trick to reduce finite-precision error 61 h = EPS; 62 } 63 final var xh = x + h; 64 h = xh - x; 65 66 final var fh = listener.evaluate(xh); 67 return (fh - fold) / h; 68 } 69 }