/*
* 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
*/