// Euler's Method for Systems, coded by David Protas, c.2003
// Any corrections or suggestions for improvement of this code will be
// appreciated and should be sent to david.protas@csun.edu
// Latest revision: November 26, 2003
/*********************
* Document: EuM.java
*********************/
import java.applet.*;
import java.awt.*;
import expr.*;
public class SysEu extends Applet {
final int MaxN = 1000; //Maximum number of subintervals
double t_0D, x_0D, y_0D, bD, xmin, xmax, ymin, ymax, h;
int nI, counter = -1, last;
double[] tArray = new double[MaxN+1];
double[] xArray = new double[MaxN+1];
double[] yArray = new double[MaxN+1];
double[] fArray = new double[MaxN+1];
double[] gArray = new double[MaxN+1];
Panel top, pan1, pan2, pan3, bottom, pan4, pan5;
Label fLabel, gLabel, inputLabelX ,inputLabelY, inputLabelB, inputLabelN, message;
TextField fField, gField, inputFieldX, inputFieldY, inputFieldB, inputFieldN;
TextArea results;
Button enter, approx;
SysEu_G graph;
Color babyBlue;
public void init() {
setLayout(new BorderLayout(4,0));
top = new Panel();
top.setLayout(new GridLayout(3,1));
bottom = new Panel();
bottom.setLayout(new GridLayout(3,1));
pan1 = new Panel();
pan2 = new Panel();
pan3 = new Panel();
pan4 = new Panel();
pan5 = new Panel();
fLabel = new Label("f(t,x,y) = ");
gLabel = new Label("g(t,x,y) = ");
fField = new TextField(20);
gField = new TextField(20);
inputLabelX = new Label(" x_0 =");
inputLabelY = new Label(" y_0 =");
inputLabelB = new Label(" b =");
inputLabelN = new Label(" n =");
inputFieldX = new TextField(5);
inputFieldY = new TextField(5);
inputFieldB = new TextField(5);
inputFieldN = new TextField(5);
enter = new Button("Enter");
approx = new Button("Approximate");
results = new TextArea(" t_n x_n y_n ", 10, 40);
results.setEditable(false);
message = new Label(" " +
" ");
graph = new SysEu_G();
babyBlue = new Color(204,255,255);
pan1.add(fLabel);
pan1.add(fField);
pan1.add(gLabel);
pan1.add(gField);
top.add(pan1);
pan2.add(inputLabelX);
pan2.add(inputFieldX);
pan2.add(inputLabelY);
pan2.add(inputFieldY);
top.add(pan2);
pan3.add(inputLabelB);
pan3.add(inputFieldB);
pan3.add(inputLabelN);
pan3.add(inputFieldN);
pan3.add(enter);
pan3.add(approx);
top.add(pan3);
add("North",top);
add("Center",graph);
add("East",results);
pan5.add(message);
bottom.add(pan5);
add("South",bottom);
setBackground(babyBlue);
pan1.setBackground(babyBlue);
pan2.setBackground(babyBlue);
pan3.setBackground(babyBlue);
pan4.setBackground(babyBlue);
pan5.setBackground(babyBlue);
message.setForeground(Color.red);
message.setBackground(babyBlue);
results.setFont(new Font("Courier",Font.PLAIN,10));
}
public boolean action(Event evt, Object arg) {
Variable t = null;
Variable x = null;
Variable y = null;
Expr f = null, g = null, inputX = null, inputY = null, inputB = null;
if (evt.target == enter) {
counter = 0;
graph.counter = counter;
message.setText("");
try {
t = Variable.make ("t");
x = Variable.make ("x");
y = Variable.make ("y");
f = Parser.parse (fField.getText());
g = Parser.parse (gField.getText());
inputX = Parser.parse(inputFieldX.getText());
inputY = Parser.parse(inputFieldY.getText());
inputB = Parser.parse(inputFieldB.getText());
}
catch (Syntax_error e) {
message.setText("" + e);
}
Variable.make ("pi").set_value (Math.PI);
Variable.make ("e").set_value (Math.E);
x_0D = inputX.value();
y_0D = inputY.value();
bD = inputB.value();
if (entryValid(inputFieldN.getText()) == false)
message.setText("n needs to be an integer. Try again.");
else {
nI = intFromString(inputFieldN.getText());
last = nI;
if((nI < 1) || (nI > MaxN))
message.setText("Applet requires n to be a positive integer <= " + MaxN);
else if (bD > 0) {
h = bD/nI;
graph.h = h;
graph.nI = nI;
if (nI > 10)
approx.setLabel("Run");
else
approx.setLabel("Step");
results.setText(" t_n x_n y_n " + "\n" +
rndOff(0) + " " + rndOff(x_0D) + " " + rndOff(y_0D));
graph.x_0D = x_0D;
graph.y_0D = y_0D;
graph.bD = bD;
tArray[0] = 0;
xArray[0] = x_0D;
yArray[0] = y_0D;
graph.tArray[0] = tArray[0];
graph.xArray[0] = xArray[0];
graph.yArray[0] = yArray[0];
xmin = Math.min(x_0D,-.5);
xmax = Math.max(x_0D,.2);
ymin = Math.min(y_0D,-.5);
ymax = Math.max(y_0D,.2);
for (int i = 1; i <= nI; i++) {
t.set_value(tArray[i-1]);
x.set_value(xArray[i-1]);
y.set_value(yArray[i-1]);
fArray[i-1] = f.value(); //Array of slopes
gArray[i-1] = g.value(); //Array of slopes
if (fArray[i-1] != fArray[i-1]) { //tests whether fArray[i-1] is a number
message.setText("x'(" + rndOff(tArray[i-1]).trim() +
") is undefined. Computation ends there.");
last = i-1;
break;
}
if (gArray[i-1] != gArray[i-1]) { //tests whether gArray[i-1] is a number
message.setText("y'(" + rndOff(tArray[i-1]).trim() +
") is undefined. Computation ends there.");
last = i-1;
break;
}
xArray[i] = xArray[i-1] + h*fArray[i-1]; //Array of x values
yArray[i] = yArray[i-1] + h*gArray[i-1]; //Array of y values
tArray[i] = i*h; //Array of t values
if (xArray[i] < xmin)
xmin = xArray[i]; //find min value of x
if (xArray[i] > xmax)
xmax = xArray[i]; //find max value of x
if (yArray[i] < ymin)
ymin = yArray[i]; //find min value of y
if (yArray[i] > ymax)
ymax = yArray[i]; //find max value of y
}
graph.xmin = xmin;
graph.xmax = xmax;
graph.ymin = ymin;
graph.ymax = ymax;
graph.repaint();
} //end of else if bD > 0
else
message.setText("Need b > 0. Try again.");
} //end of else entry valid
return true;
} //end of evt.target == enter
if (evt.target == approx) {
if (nI > 10) {
graph.counter = last;
for (int i = 1; i <= last; i++) {
graph.tArray[i] = tArray[i];
graph.xArray[i] = xArray[i];
graph.yArray[i] = yArray[i];
results.appendText("\n" + rndOff(tArray[i]) + " " + rndOff(xArray[i])
+ " " + rndOff(yArray[i]));
}
graph.repaint();
}
else {
if (counter < last) {
graph.nI = last;
counter = counter + 1;
results.appendText("\n" + rndOff(tArray[counter]) + " "
+ rndOff(xArray[counter]) + " " + rndOff(yArray[counter]));
graph.counter = counter;
for (int i = 1; i <= counter; i++) {
graph.tArray[i] = tArray[i];
graph.xArray[i] = xArray[i];
graph.yArray[i] = yArray[i];
}
graph.repaint();
}
}
return true;
} //end of evt.target == approx
return false;
} //end of action
public static int intFromString(String str) {
Integer intObj = new Integer(str);
return intObj.intValue();
}
private boolean entryValid(String entry) {
boolean status;
try {
double number = intFromString(entry);
status = true;
}
catch(NumberFormatException e) {
status =false;
}
return status;
}
public static String rndOff(double number) //to 5 places past the decimal
{
String strnum, bigstrnum, substrnum = " 0.00000";
int period, lngth;
long longnum;
if ((number >= 0.001) || (number <= -0.001) || (number != number)) {
number = Math.pow(0.1,5)*Math.round(Math.pow(10,5)*number);
strnum = String.valueOf(number);
bigstrnum = " " + strnum + " ";
period = bigstrnum.indexOf('.');
substrnum = bigstrnum.substring(period -6, period + 6);
if ((number >= 1000000) || (number <= -100000) || (number != number))
substrnum = "big magnitude";
}
else {
longnum = Math.round(Math.pow(10,5)*number);
if (longnum == 0)
substrnum = " 0.00000";
else {
strnum = String.valueOf(longnum);
if (longnum < 0)
strnum = strnum.substring(1);
lngth = strnum.length();
switch (lngth) {
case 1:
substrnum = " 0.0000" + strnum;
break;
case 2:
substrnum = " 0.000" + strnum;
break;
default:
substrnum = " error";
}
if (longnum < 0)
substrnum = " -" + substrnum.substring(5);
}
}
return substrnum;
}
} //end of SysEu
/***********************
* Document: SysEu_G.java
***********************/
import java.awt.*;
public class SysEu_G extends Canvas
{
final int MaxN = 1000; //Maximum number of subintervals
Dimension d;
double[] tArray = new double[MaxN+1];
double[] xArray = new double[MaxN+1];
double[] yArray = new double[MaxN+1];
double x_0D, y_0D, bD, xmin, xmax, ymin, ymax, h, hspan, vspan;
int[] horizCoords = new int[4];
int[] vertCoords = new int[4];
int tick, deltaTick, nI, counter = -1;
Color lightLilac = new Color(204,204,255);
Color lilac = new Color(153,153,204);
Color darkLilac = new Color(102,102,153);
Color lightGreen = new Color(204,255,204);
Color darkGreen = new Color(102,153,102);
public void paint(Graphics gr)
{
if (counter > -1) {
d = this.size();
hspan = 1.25*bD;
vspan = (3*(ymax - ymin) + (xmax - xmin));
gr.setColor(lightGreen); //left plane
horizCoords[0] = horizScaler(0,xmin,ymin);
horizCoords[1] = horizScaler(0,xmax,ymin);
horizCoords[2] = horizScaler(0,xmax,ymax);
horizCoords[3] = horizScaler(0,xmin,ymax);
vertCoords[0] = vertScaler(0,xmin,ymin);
vertCoords[1] = vertScaler(0,xmax,ymin);
vertCoords[2] = vertScaler(0,xmax,ymax);
vertCoords[3] = vertScaler(0,xmin,ymax);
gr.fillPolygon(horizCoords,vertCoords,4);
gr.setColor(Color.lightGray); //bottom plane
horizCoords[0] = horizScaler(0,xmin,ymin);
horizCoords[1] = horizScaler(0,xmax,ymin);
horizCoords[2] = horizScaler(bD,xmax,ymin);
horizCoords[3] = horizScaler(bD,xmin,ymin);
vertCoords[0] = vertScaler(0,xmin,ymin);
vertCoords[1] = vertScaler(0,xmax,ymin);
vertCoords[2] = vertScaler(bD,xmax,ymin);
vertCoords[3] = vertScaler(bD,xmin,ymin);
gr.fillPolygon(horizCoords,vertCoords,4);
gr.setColor(Color.gray);
gr.drawLine(horizScaler(0,0,ymin), vertScaler(0,0,ymin),
horizScaler(bD,0,ymin), vertScaler(bD,0,ymin)); //bottom t-axis
gr.drawLine(horizScaler(0,xmin,ymin), vertScaler(0,xmin,ymin),
horizScaler(0,xmax,ymin), vertScaler(0,xmax,ymin)); //bottom x-axis
gr.setColor(lightLilac); //back plane
horizCoords[0] = horizScaler(0,xmax,ymin);
horizCoords[1] = horizScaler(0,xmax,ymax);
horizCoords[2] = horizScaler(bD,xmax,ymax);
horizCoords[3] = horizScaler(bD,xmax,ymin);
vertCoords[0] = vertScaler(0,xmax,ymin);
vertCoords[1] = vertScaler(0,xmax,ymax);
vertCoords[2] = vertScaler(bD,xmax,ymax);
vertCoords[3] = vertScaler(bD,xmax,ymin);
gr.fillPolygon(horizCoords,vertCoords,4);
gr.setColor(lilac);
gr.drawLine(horizScaler(0,xmax,0), vertScaler(0,xmax,0),
horizScaler(bD,xmax,0), vertScaler(bD,xmax,0)); //back t-axis
gr.drawLine(horizScaler(0,xmax,ymin), vertScaler(0,xmax,ymin),
horizScaler(0,xmax,ymax), vertScaler(0,xmax,ymax)); //back y-axis
gr.setColor(Color.black);
gr.drawLine(horizScaler(0,0,0), vertScaler(0,0,0),
horizScaler(bD,0,0), vertScaler(bD,0,0)); //t-axis
gr.drawString("t", horizScaler(bD,0,0)+2, vertScaler(bD,0,0));
gr.drawLine(horizScaler(0,xmin,0), vertScaler(0,xmin,0),
horizScaler(0,xmax,0), vertScaler(0,xmax,0)); //x-axis
gr.drawString("x", horizScaler(0,xmax,0)+2, vertScaler(0,xmax,0)-2);
gr.drawLine(horizScaler(0,0,ymin), vertScaler(0,0,ymin),
horizScaler(0,0,ymax), vertScaler(0,0,ymax)); //y-axis
gr.drawString("y", horizScaler(0,0,ymax), vertScaler(0,0,ymax)-3);
deltaTick = 1 + (int)(bD - x_0D)/12;
tick = deltaTick;
do {
gr.drawLine(horizScaler(tick,0,0), vertScaler(tick,0,0) - 2,
horizScaler(tick,0,0), vertScaler(tick,0,0));
gr.drawString(tick+"", horizScaler(tick,0,0) - 4, vertScaler(tick,0,0) + 11);
tick = tick + deltaTick;
}
while (tick <= bD); //end of t-ticks
if (counter > 0) {
for (int i = 1; i <= counter; i++) {
gr.setColor(Color.darkGray);
gr.drawLine(horizScaler(tArray[i-1],xArray[i-1],ymin),
vertScaler(tArray[i-1],xArray[i-1],ymin),
horizScaler(tArray[i],xArray[i],ymin),
vertScaler(tArray[i],xArray[i],ymin));
gr.setColor(darkLilac);
gr.drawLine(horizScaler(tArray[i-1],xmax,yArray[i-1]),
vertScaler(tArray[i-1],xmax,yArray[i-1]),
horizScaler(tArray[i],xmax,yArray[i]),
vertScaler(tArray[i],xmax,yArray[i]));
gr.setColor(darkGreen);
gr.drawLine(horizScaler(0,xArray[i-1],yArray[i-1]),
vertScaler(0,xArray[i-1],yArray[i-1]),
horizScaler(0,xArray[i],yArray[i]),
vertScaler(0,xArray[i],yArray[i]));
}
for (int i = 1; i <= counter; i++) {
if (i%2 == 0)
gr.setColor(Color.red);
else
gr.setColor(Color.magenta);
gr.drawLine(horizScaler(tArray[i-1],xArray[i-1],yArray[i-1]),
vertScaler(tArray[i-1],xArray[i-1],yArray[i-1]),
horizScaler(tArray[i],xArray[i],yArray[i]),
vertScaler(tArray[i],xArray[i],yArray[i]));
}
}
}
}
private int horizScaler(double t, double x, double y)
{
return (int)(5 + (d.width - 10)*(0.25*bD*(x - xmin)/(xmax - xmin) + t)/hspan);
}
private int vertScaler(double t, double x, double y)
{
return (int)(5 + (d.height - 16)*(3*(ymax - y) + (xmax - x))/vspan);
}
} //end of SysEu_G
/**************************************
* Folder: expr Document: Expr.java
**************************************/
// Mathematical expressions.
// Copyright 1996 by Darius Bacon; see the file COPYING.
// 14May96: added constant folding
// 6June02: changes made by David Protas indicated by /*DP*/
package expr;
/**
* A mathematical expression, built out of literal numbers, variables,
* arithmetic operators, and elementary functions. The operator names
* are from java.lang.Math.
*/
public abstract class Expr {
/** @return the value given the current variable values */
public abstract double value ();
/** Binary operator. */ public static final int ADD = 0;
/** Binary operator. */ public static final int SUB = 1;
/** Binary operator. */ public static final int MUL = 2;
/** Binary operator. */ public static final int DIV = 3;
/** Binary operator. */ public static final int POW = 4;
/** Unary operator. */ public static final int ABS = 100;
/** Unary operator. */ public static final int ACOS = 101;
/** Unary operator. */ public static final int ASIN = 102;
/** Unary operator. */ public static final int ATAN = 103;
/** Unary operator. */ public static final int CEIL = 104;
/** Unary operator. */ public static final int COS = 105;
/** Unary operator. */ public static final int EXP = 106;
/** Unary operator. */ public static final int FLOOR = 107;
/** Unary operator. */ public static final int LN = 114; /*DP*/
/** Unary operator. */ public static final int LOG = 108;
/** Unary minus operator. */ public static final int NEG = 109;
/** Unary operator. */ public static final int ROUND = 110;
/** Unary operator. */ public static final int SIN = 111;
/** Unary operator. */ public static final int SQRT = 112;
/** Unary operator. */ public static final int TAN = 113;
public static Expr make_literal (double v) {
return new Literal (v);
}
public static Expr make_var_ref (Variable var) {
return new Var_ref (var);
}
/**
* @param rator unary operator
* @param rand operand
*/
public static Expr make_app1 (int rator, Expr rand) {
Expr app = new App1 (rator, rand);
return rand instanceof Literal ? new Literal (app.value ()) : app;
}
/**
* @param rator binary operator
* @param rand0 left operand
* @param rand1 right operand
*/
public static Expr make_app2 (int rator, Expr rand0, Expr rand1) {
Expr app = new App2 (rator, rand0, rand1);
return rand0 instanceof Literal && rand1 instanceof Literal
? new Literal (app.value ())
: app;
}
}
// These classes are all private to this module so that I can get rid
// of them later. For applets you want to use as few classes as
// possible to avoid http connections at load time; it'd be profitable
// to replace all these subtypes with bytecodes for a stack machine,
// or perhaps a type that's the union of all of them (see class Node
// in java/demo/SpreadSheet/SpreadSheet.java).
class Literal extends Expr {
double v;
Literal (double _v) { v = _v; }
public double value () { return v; }
}
class Var_ref extends Expr {
Variable var;
Var_ref (Variable _var) { var = _var; }
public double value () { return var.value (); }
}
class App1 extends Expr {
int rator;
Expr rand;
App1 (int _rator, Expr _rand) { rator = _rator; rand = _rand; }
public double value () {
double arg = rand.value ();
switch (rator) {
case ABS: return Math.abs (arg);
case ACOS: return Math.acos (arg);
case ASIN: return Math.asin (arg);
case ATAN: return Math.atan (arg);
case CEIL: return Math.ceil (arg);
case COS: return Math.cos (arg);
case EXP: return Math.exp (arg);
case FLOOR: return Math.floor (arg);
case LN: return Math.log (arg); /*DP*/
case LOG: return Math.log (arg)/Math.log (10); /*DP*/
case NEG: return -arg;
case ROUND: return Math.round (arg);
case SIN: return Math.sin (arg);
case SQRT: return Math.sqrt (arg);
case TAN: return Math.tan (arg);
default: throw new RuntimeException ("BUG: bad rator");
}
}
}
class App2 extends Expr {
int rator;
Expr rand0, rand1;
App2 (int _rator, Expr _rand0, Expr _rand1) {
rator = _rator; rand0 = _rand0; rand1 = _rand1;
}
public double value () {
double arg0 = rand0.value ();
double arg1 = rand1.value ();
switch (rator) {
case ADD: return arg0 + arg1;
case SUB: return arg0 - arg1;
case MUL: return arg0 * arg1;
case DIV: return arg0 / arg1; // check for division by 0?
case POW: return Math.pow (arg0, arg1);
default: throw new RuntimeException ("BUG: bad rator");
}
}
}
/****************************************
* Folder: expr Document: Parser.java
****************************************/
// Operator-precedence parser.
// Copyright 1996 by Darius Bacon; see the file COPYING.
// 14May96: bugfix.
// StreamTokenizer treated '-' as a numeric token, not a minus
// operator followed by a number. Fix: make '-' an ordinaryChar.
// 12May97: Changed the precedence of unary minus to be lower than
// multiplication, so -y^2 is like -(y^2), not (-y)^2.
package expr;
import java.io.*;
/**
Parses strings representing mathematical formulas with variables.
The following operators, in descending order of precedence, are
defined:
^ (raise to a power)
* /
Unary minus (-x)
+ -
^ associates right-to-left; other operators associate left-to-right.
These functions are defined:
abs, acos, asin, atan,
ceil, cos, exp, floor, (ln added by DP)
log, round, sin, sqrt,
tan. Each requires one argument enclosed in parentheses.
Whitespace outside identifiers is ignored.
The syntax-error messages aren't very informative, unfortunately.
IWBNI it indicated where in the input string the parse failed, but
that'd be kind of a pain since our scanner is a StreamTokenizer. A
hook for that info should've been built into StreamTokenizer.
Examples:
42
2-3
cos(x^2) + sin(x^2)
*/
public class Parser {
static StreamTokenizer tokens;
public static Expr parse (String input) throws Syntax_error {
tokens = new StreamTokenizer (new StringBufferInputStream (input));
tokens.ordinaryChar ('/');
tokens.ordinaryChar ('-');
next ();
Expr expr = parse_expr (0);
if (tokens.ttype != StreamTokenizer.TT_EOF)
throw new Syntax_error ("Incomplete expression: " + input);
return expr;
}
static void next () {
try { tokens.nextToken (); }
catch (IOException e) { throw new RuntimeException ("I/O error: " + e); }
}
static void expect (int ttype) throws Syntax_error {
if (tokens.ttype != ttype)
throw new Syntax_error ("'" + (char) ttype + "' expected");
next ();
}
static Expr parse_expr (int precedence) throws Syntax_error {
Expr expr = parse_factor ();
loop: for (;;) {
int l, r, rator;
// The operator precedence table.
// l = left precedence, r = right precedence, rator = operator.
// Higher precedence values mean tighter binding of arguments.
// To associate left-to-right, let r = l+1;
// to associate right-to-left, let r = l.
switch (tokens.ttype) {
case '+': l = 10; r = 11; rator = Expr.ADD; break;
case '-': l = 10; r = 11; rator = Expr.SUB; break;
case '*': l = 20; r = 21; rator = Expr.MUL; break;
case '/': l = 20; r = 21; rator = Expr.DIV; break;
case '^': l = 30; r = 30; rator = Expr.POW; break;
default: break loop;
}
if (l < precedence)
break loop;
next ();
expr = Expr.make_app2 (rator, expr, parse_expr (r));
}
return expr;
}
static String[] procs = {
"abs", "acos", "asin", "atan",
"ceil", "cos", "exp", "floor", "ln", // ln added by DP
"log", "round", "sin", "sqrt",
"tan"
};
static int[] rators = {
Expr.ABS, Expr.ACOS, Expr.ASIN, Expr.ATAN,
Expr.CEIL, Expr.COS, Expr.EXP, Expr.FLOOR, Expr.LN, // Expr.LN added by DP
Expr.LOG, Expr.ROUND, Expr.SIN, Expr.SQRT,
Expr.TAN
};
static Expr parse_factor () throws Syntax_error {
switch (tokens.ttype) {
case StreamTokenizer.TT_NUMBER: {
Expr lit = Expr.make_literal (tokens.nval);
next ();
return lit;
}
case StreamTokenizer.TT_WORD: {
for (int i = 0; i < procs.length; ++i)
if (procs [i].equals (tokens.sval)) {
next ();
expect ('(');
Expr rand = parse_expr (0);
expect (')');
return Expr.make_app1 (rators [i], rand);
}
Expr var = Expr.make_var_ref (Variable.make (tokens.sval));
next ();
return var;
}
case '(': {
next ();
Expr enclosed = parse_expr (0);
expect (')');
return enclosed;
}
case '-':
next ();
return Expr.make_app1 (Expr.NEG, parse_expr (15));
default:
throw new Syntax_error ("Expected a factor");
}
}
}
/**********************************************
* Folder: expr Document: Syntax_error.java
**********************************************/
// Syntax-error exception.
// Copyright 1996 by Darius Bacon; see the file COPYING.
package expr;
public class Syntax_error extends Exception {
public Syntax_error (String complaint) { super (complaint); }
}
/******************************************
* Folder: expr Document: Variable.java
******************************************/
// Variables associate values with names.
// Copyright 1996 by Darius Bacon; see the file COPYING.
// 01Jun96: made `make' synchronized.
package expr;
import java.util.Hashtable;
/**
* Variables associate values with names.
*/
public class Variable {
static Hashtable variables = new Hashtable ();
/**
* Return the variable named `_name'.
* make (s1) == make (s2) iff s1.equals (s2).
*/
static public synchronized Variable make (String _name) {
Variable result = (Variable) variables.get (_name);
if (result == null)
variables.put (_name, result = new Variable (_name));
return result;
}
String name;
double val;
public Variable (String _name) { name = _name; val = 0; }
public String toString () { return name; }
public double value () { return val; }
public void set_value (double _val) { val = _val; }
}
Back to applet