/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.numerics; import java.text.DecimalFormat; /** * A utility class for numerical analysis. * This class cannot be subclassed or instantiated because all methods are static. * * @author Wolfgang Christian * @version 1.0 */ public final class Util { public static final double SQRT2PI = Math.sqrt(2*Math.PI); public static final double LOG10 = Math.log(10); /** The default precision for numerical analysis. */ public static final double defaultNumericalPrecision = Math.sqrt(Double.MIN_VALUE); /** Parser for simple arithmetic expressions. */ private static SuryonoParser parser = new SuryonoParser(0); // parser without variables // standard output formats static DecimalFormat format2 = new DecimalFormat("#0.00"); //$NON-NLS-1$ static DecimalFormat format3 = new DecimalFormat("#0.000"); //$NON-NLS-1$ static DecimalFormat format4 = new DecimalFormat("#0.0000"); //$NON-NLS-1$ static DecimalFormat format_E2 = new DecimalFormat("0.00E0"); //$NON-NLS-1$ static DecimalFormat format_E3 = new DecimalFormat("0.000E0"); //$NON-NLS-1$ static DecimalFormat format_E4 = new DecimalFormat("0.0000E0"); //$NON-NLS-1$ private Util() {} // prohibit instantiation because all methods are static /** * Convert a double to a string, printing two decimal places. * @param d Input double */ static public String f2(double d) { return format2.format(d); } /** * Convert a double to a string, printing three decimal places. * @param d Input double */ static public String f3(double d) { return format3.format(d); } /** * Convert a double to a string, printing four decimal places. * @param d Input double */ static public String f4(double d) { return format4.format(d); } /** * Computes the relativePrecision except near zero where the absolute precision is returned. * * @param epsilon the absolute error * @param result the result * * @return the relative error */ public static double relativePrecision(final double epsilon, final double result) { return(result>defaultNumericalPrecision) ? epsilon/result : epsilon; } /** * Checks if an array is sorted. * Returns: * Positive integer if array is sorted in increasing value. * Negative integer if array is sorted in decreasing value. * Zero if array is not sorted. * * @param array double[] * @return int 1,0,-1 based on sorting */ public static int checkSorting(double[] array) { int sign = (array[0]<=array[array.length-1]) ? 1 : -1; for(int i = 1, n = array.length; i<n; i++) { switch(sign) { case -1 : if(array[i-1]<array[i]) { return 0; // not sorted } break; case 1 : if(array[i-1]>array[i]) { return 0; // not sorted } } } return sign; } /** * Gets the approximate range of a function within the given domain. * * The range is deterermiend by evaluating the function at n points and finding the minimum and maximum values. * * @param f Function * @param a double * @param b double * @param n int * @return double[] */ public static double[] getRange(Function f, double a, double b, int n) { double min = f.evaluate(a); double max = f.evaluate(a); double x = a, dx = (b-a)/(n-1); for(int i = 1; i<n; i++) { double y = f.evaluate(x); min = Math.min(min, y); max = Math.max(max, y); x += dx; } return new double[] {min, max}; } /** * Fills the given double[2][n] array with x and f(x) values on interval [start, stop]. * * @param f Function * @param start double * @param stop double * @param data double[][] * @return double[][] */ static public double[][] functionFill(Function f, double start, double stop, double[][] data) { double dx = 1; int n = data[0].length; if(n>1) { dx = (stop-start)/(n-1); } double x = start; for(int i = 0; i<n; i++) { data[0][i] = x; data[1][i] = f.evaluate(x); x += dx; } return data; } /** * Fills the given double[n] array with f(x) on the interval [start, stop]. * * @param f Function * @param start double starting value of x * @param stop double stopping value of x * @param data double[] * @return double[] */ static public double[] functionFill(Function f, double start, double stop, double[] data) { double dx = 1; int n = data.length; if(n>1) { dx = (stop-start)/(n-1); } double x = start; for(int i = 0; i<n; i++) { data[i] = f.evaluate(x); x += dx; } return data; } /** * Computes the average value of a subset of an array. * * @param array the data to be averaged * @param start the index of the first point to be averaged * @param num the total number of points to be averaged * @return */ public static double computeAverage(double[] array, int start, int num) { double sum = 0; for(int i = start, stop = start+num; i<stop; i++) { sum += array[i]; } return sum/num; } /** * Creates a function having a constant value. * @param c * @return */ public static Function constantFunction(final double c) { return new Function() { public double evaluate(final double x) { return c; } }; } /** * Creates a linear function with the given slope and intercept. * * @param m double slope * @param b double intercept * @return Function */ public static Function linearFunction(final double m, final double b) { return new Function() { public double evaluate(final double x) { return m*x+b; } }; } /** * Creates a Guassian (normal) distribution function. * * The distribution is normalized. * The full width at half maximum is 2*sigma*Math.sqrt(2 Math.log(2)) ~ 2.3548*sigma * * @param x0 double center of the distribution * @param sigma double width of the distributuon * @return Function */ public static Function gaussian(final double x0, final double sigma) { final double s2 = 2*sigma*sigma; return new Function() { public double evaluate(double x) { return Math.exp(-(x-x0)*(x-x0)/s2)/sigma/SQRT2PI; } }; } /** * Evalautes a mathematical expression without variables. * @param str String * @return double */ public static synchronized double evalMath(String str) { try { parser.parse(str); return parser.evaluate(); } catch(ParserException ex) {} return Double.NaN; } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */