import java.awt.*; import java.applet.*; import java.util.*; /** * An applet to demostrate central limit theorem of probability. * It utilizes an expression evaluator class by The-Son LAI. *
* The whole program is distributed under the Modified BSD * license with the kind permission from The-Son. See below. *
* Copyright (c) 2001 by Jarno Elonen and The-Son LAI *
* http://iki.fi/elonen/, http://lts.online.fr/java/
*/
public class CentralLimitApplet extends Applet
{
/*
* The distribution licence
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. The name of the author may not
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Start the applet, create panels
*/
public void init()
{
this.setLayout( null );
// Create the parameter panel
Panel p = new Panel();
p.setLayout( new FlowLayout( FlowLayout.LEFT, 0,0 ));
p.add( new Label( "Examine sum of", Label.LEFT ));
p.add( sumOfTF );
p.add( new Label( "occurences of a" ));
p.add( new Label( "phenomenon" ));
p.add( new Label( "whose min =" ));
p.add( minTF );
p.add( new Label( "," ));
p.add( new Label( "max =" ));
p.add( maxTF );
p.add( new Label( "," ));
p.add( new Label( "prob. func. P(x)=" ));
p.add( funcTF );
p.add( new Label( "and repeat it" ));
p.add( repeatTF );
p.add( new Label( "times. " ));
p.add( goButt );
Panel p2 = new Panel( new BorderLayout());
p2.add( BorderLayout.CENTER, p );
Panel p3 = new Panel( new BorderLayout());
p3.add( BorderLayout.CENTER, goButt );
p2.add( BorderLayout.SOUTH, p3 );
add( p2 );
p2.setBounds( 0,0, 100, getSize().height );
myImg = createImage( getSize().width-100, getSize().height );
clearCanvas();
repaint();
}
/**
* Redraw the screen
*/
public void paint( Graphics g )
{
g.drawImage( myImg, 100,0, null );
}
/**
* Listen for button strokes
*/
public boolean action( Event evt, Object what )
{
if ( evt.target == goButt )
{
simulate();
repaint();
return true;
}
return false;
}
/**
* This can be called from Javascript.
* Sets the text fields and simulates a round.
*/
public void simulate( int min, int max, int sum,
int repeat, String func )
{
minTF.setText( "" + min );
maxTF.setText( "" + max );
sumOfTF.setText( "" + sum );
repeatTF.setText( "" + repeat );
funcTF.setText( func );
simulate();
repaint();
}
/**
* Paints the canvas white and draws
* black borders around it
*/
private void clearCanvas()
{
int w = myImg.getWidth(null), h = myImg.getHeight(null);
Graphics g = myImg.getGraphics();
g.setColor( Color.white );
g.fillRect( 0,0, 99999, 99999 );
g.setColor( Color.black );
g.drawRect( 0,0, w-1,h-1 );
}
/**
* Runs a simulation with given parameters
* and draws the result as a histogram to the screen.
*/
private void simulate()
{
try
{
int min = getLimited( minTF, "Min", -9999, 9999 );
int max = getLimited( maxTF, "Max", -9999, 9999 );
int sumOf = getLimited( sumOfTF, "Sum", 1, 1000 );
int repeat = getLimited( repeatTF, "Repeat count", 1, 10000000 );
if ( min >= max )
throw new Exception( "Min must be < Max." );
int totalMin = (min*sumOf);
int totalMax = (max*sumOf);
Graphics g = myImg.getGraphics();
int w = myImg.getWidth(null), h = myImg.getHeight(null);
clearCanvas();
repaint();
// Draw the scale
g.setColor( Color.black );
g.drawString( "" + totalMin, 2,h-8 );
String maxStr = "" + totalMax;
g.drawString( maxStr, w-g.getFontMetrics().stringWidth( maxStr )-2, h-8 );
String avgStr = "" + (totalMin+totalMax)/2;
g.drawString( avgStr, w/2-g.getFontMetrics().stringWidth( avgStr )/2-2, h-8 );
myEval.setExpression( funcTF.getText());
int range = max-min+1;
int totalRange = totalMax-totalMin+1;
// Calculate propabilities from the function
double fTotal = 0;
double prob[] = new double[ range ];
for ( int i=0; i
*
* When the getValue() is called, a Double object is returned. If it returns null, an error occured.
* Sample:
* MathEvaluator m = new MathEvaluator("-5-6/(-2) + sqr(15+x)");
* m.addVariable("x", 15.1d);
* System.out.println( m.getValue() );
*
* Refactored slightly for smaller size by Jarno Elonen
* @version 1.1
* @author The-Son LAI, Lts@writeme.com
* @date April 2001
**/
public static class MathEvaluator
{
protected static Operator[] operators = null;
private Node node = null;
private String expression = null;
private Hashtable variables = new Hashtable();
/***
* adds a variable and its value in the MathEvaluator
*/
public void addVariable(String v, double val)
{
variables.put(v, new Double(val));
}
/***
* sets the expression
*/
public void setExpression(String s)
{
if ( operators == null )
initializeOperators();
expression = s;
}
/***
* evaluates and returns the value of the expression
*/
public Double getValue()
{
if (expression == null) return null;
try
{
node = new Node(expression);
return evaluate(node);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
private static Double evaluate(Node n)
{
if ( n.hasOperator() && n.hasChild() )
{
if ( n.nOperator.getType() == 1 )
n.nValue = evaluateExpression( n.nOperator, evaluate( n.nLeft ), null );
else if ( n.nOperator.getType() == 2 )
n.nValue = evaluateExpression( n.nOperator, evaluate( n.nLeft ), evaluate( n.nRight ) );
}
return n.nValue;
}
private static Double evaluateExpression(Operator o, Double f1, Double f2)
{
String op = o.getOperator();
Double res = null;
if ( "+".equals(op) ) res = new Double( f1.doubleValue() + f2.doubleValue() );
else if ( "-".equals(op) ) res = new Double( f1.doubleValue() - f2.doubleValue() );
else if ( "*".equals(op) ) res = new Double( f1.doubleValue() * f2.doubleValue() );
else if ( "/".equals(op) ) res = new Double( f1.doubleValue() / f2.doubleValue() );
else if ( "^".equals(op) ) res = new Double( Math.pow(f1.doubleValue(), f2.doubleValue()) );
else if ( "%".equals(op) ) res = new Double( f1.doubleValue() % f2.doubleValue() );
else if ( "&".equals(op) ) res = new Double( f1.doubleValue() + f2.doubleValue() ); // todo
else if ( "|".equals(op) ) res = new Double( f1.doubleValue() + f2.doubleValue() ); // todo
else if ( "cos".equals(op) ) res = new Double( Math.cos(f1.doubleValue()) );
else if ( "sin".equals(op) ) res = new Double( Math.sin(f1.doubleValue()) );
else if ( "tan".equals(op) ) res = new Double( Math.tan(f1.doubleValue()) );
else if ( "acos".equals(op) ) res = new Double( Math.acos(f1.doubleValue()) );
else if ( "asin".equals(op) ) res = new Double( Math.asin(f1.doubleValue()) );
else if ( "atan".equals(op) ) res = new Double( Math.atan(f1.doubleValue()) );
else if ( "sqr".equals(op) ) res = new Double( f1.doubleValue() * f1.doubleValue() );
else if ( "sqrt".equals(op) ) res = new Double( Math.sqrt(f1.doubleValue()) );
else if ( "log".equals(op) ) res = new Double( Math.log(f1.doubleValue()) );
else if ( "min".equals(op) ) res = new Double( Math.min(f1.doubleValue(), f2.doubleValue()) );
else if ( "max".equals(op) ) res = new Double( Math.max(f1.doubleValue(), f2.doubleValue()) );
else if ( "exp".equals(op) ) res = new Double( Math.exp(f1.doubleValue()) );
else if ( "floor".equals(op) ) res = new Double( Math.floor(f1.doubleValue()) );
else if ( "ceil".equals(op) ) res = new Double( Math.ceil(f1.doubleValue()) );
else if ( "abs".equals(op) ) res = new Double( Math.abs(f1.doubleValue()) );
else if ( "neg".equals(op) ) res = new Double( - f1.doubleValue() );
else if ( "rnd".equals(op) ) res = new Double( Math.random() * f1.doubleValue() );
return res;
}
private void initializeOperators()
{
operators = new Operator[25];
operators[0] = new Operator("+" , 2, 0);
operators[1] = new Operator("-" , 2, 0);
operators[2] = new Operator("*" , 2, 10);
operators[3] = new Operator("/" , 2, 10);
operators[4] = new Operator("^" , 2, 10);
operators[5] = new Operator("%" , 2, 10);
operators[6] = new Operator("&" , 2, 0);
operators[7] = new Operator("|" , 2, 0);
operators[8] = new Operator("cos" , 1, 20);
operators[9] = new Operator("sin" , 1, 20);
operators[10] = new Operator("tan" , 1, 20);
operators[11] = new Operator("acos" , 1, 20);
operators[12] = new Operator("asin" , 1, 20);
operators[13] = new Operator("atan" , 1, 20);
operators[14] = new Operator("sqrt" , 1, 20);
operators[15] = new Operator("sqr" , 1, 20);
operators[16] = new Operator("log" , 1, 20);
operators[17] = new Operator("min" , 2, 0);
operators[18] = new Operator("max" , 2, 0);
operators[19] = new Operator("exp" , 1, 20);
operators[20] = new Operator("floor", 1, 20);
operators[21] = new Operator("ceil" , 1, 20);
operators[22] = new Operator("abs" , 1, 20);
operators[23] = new Operator("neg" , 1, 20);
operators[24] = new Operator("rnd" , 1, 20);
}
private Double getDouble(String s)
{
if ( s == null ) return null;
Double res = null;
try {
res = Double.valueOf( s );
}
catch(Exception e) {
return (Double) variables.get(s);
}
return res;
}
protected class Operator
{
private String op;
private int type;
private int priority;
public Operator(String o, int t, int p)
{
op = o;
type = t;
priority = p;
}
public String getOperator() {
return op;
}
public void setOperator(String o) {
op = o;
}
public int getType() {
return type;
}
public int getPriority() {
return priority;
}
}
protected class Node
{
public String nString = null;
public Operator nOperator = null;
public Node nLeft = null;
public Node nRight = null;
public Node nParent = null;
public int nLevel = 0;
public Double nValue = null;
public Node(String s) throws Exception
{
init(null, s, 0);
}
public Node(Node parent, String s, int level) throws Exception
{
init(parent, s, level);
}
private void init(Node parent, String s, int level) throws Exception
{
s = removeIllegalCharacters(s);
s = removeBrackets(s);
s = addZero(s);
if ( checkBrackets(s) != 0 ) throw new Exception("Wrong number of brackets in [" + s + "]");
nParent = parent;
nString = s;
nValue = getDouble(s);
nLevel = level;
int sLength = s.length();
int inBrackets = 0;
int startOperator = 0;
for (int i=0; i