```
// Riemann sums, coded by David Protas, c.2004
// Any corrections or suggestions for improvement of this code will be
// appreciated and should be sent to david.protas@csun.edu
// Latest revision: April 28, 2004

/*********************
* Document: RS.java
*********************/

import java.applet.*;
import java.awt.*;
import expr.*;

public class RS extends Applet {

final int K = 400; // Number of points used to draw graph
final int MaxN = 100; //Maximum number of subintervals
double aD, bD, ymin, ymax, h, sum, total;
int nI;
boolean firstApprox;
String functionString, partitionChoice, testPtChoice;
double[] xarray = new double[K+1];
double[] yarray = new double[K+1];
double[] xArray = new double[MaxN+1];
double[] yArray = new double[MaxN+1];
double[] tArray = new double[MaxN+1];
Panel pan2, bottom, subpan, pan4, pan6;
Label functionLabel, aLabel, bLabel, nLabel, partitionLabel, testPtLabel, message;
TextField functionField, aField, bField, nField;
Choice  partition, testPt;
TextArea results;
Button plot, compute;
RSGraph graph;
Color babyBlue;

public void init() {
setLayout(new BorderLayout(4,1));
bottom = new Panel();
bottom.setLayout(new GridLayout(2,1));
pan2 = new Panel();
pan2.setLayout(new FlowLayout(1,8,2));
pan4 = new Panel();
pan4.setLayout(new FlowLayout(1,8,2));
subpan = new Panel();
pan6 = new Panel();
pan6.setLayout(new GridLayout(2,1));
functionLabel = new Label("f(x) = ");
functionField = new TextField(20);
aLabel = new Label("  a = ");
bLabel = new Label("  b = ");
nLabel = new Label("  n = ");
partitionLabel = new Label(" Partition: ");
testPtLabel = new Label(" Test Pts: ");
aField = new TextField(5);
bField = new TextField(5);
nField = new TextField(5);
partition = new Choice();
testPt = new Choice();
plot = new Button("Plot");
compute = new Button("Compute");
results = new TextArea("                                  ", 6, 50);
results.setEditable(false);
message = new Label("                                                  " +
"                               ");
graph = new RSGraph();
babyBlue = new Color(204,255,255);

setBackground(babyBlue);
pan2.setBackground(babyBlue);
pan4.setBackground(babyBlue);
subpan.setBackground(babyBlue);
pan6.setBackground(babyBlue);
message.setForeground(Color.red);
message.setBackground(babyBlue);
results.setBackground(babyBlue);
results.setFont(new Font("Courier",Font.PLAIN,10));
}

public boolean action(Event evt, Object arg) {
Variable x = null;
Expr function = null, aInput = null, bInput = null;
if (evt.target == plot) {

message.setText("");
firstApprox = true;
try {
x = Variable.make ("x");
function = Parser.parse (functionField.getText());
aInput = Parser.parse(aField.getText());
bInput = Parser.parse(bField.getText());
}
catch (Syntax_error e) {
message.setText("" + e);
}
Variable.make ("pi").set_value (Math.PI);
Variable.make ("e").set_value (Math.E);
functionString = functionField.getText();
bD = bInput.value();
results.setText(" f(x) = " + functionString + ", a = " + aD + ", b = " + bD);
graph.bD = bD;
ymin = -.0000001;
ymax = .0000001;
for (int i = 0; i <= K; i++) {
x.set_value(xarray[i]);
yarray[i] = function.value();    //Array of y values
graph.xarray[i] = xarray[i];
graph.yarray[i] = yarray[i];
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.ymin = ymin;
graph.ymax = ymax;
graph.phase = 0;
graph.repaint();
} //end of if aD < bD
else
message.setText("Need a < b. Try again.");
return true;
} //end of evt.target == plot
if (evt.target == compute) {
sum = 0;
try {
x = Variable.make ("x");
function = Parser.parse (functionField.getText());
}
catch (Syntax_error e) {
message.setText("" + e);
}
graph.phase = 1;
if (entryValid(nField.getText()) == false)
message.setText("n needs to be an integer. Try again.");
else {
nI = intFromString(nField.getText());
if (nI < 1)
message.setText("n needs to be positive. Try again.");
else if (nI > MaxN)
message.setText("Applet requires n <= " + MaxN + ". Try again.");
else {               // if n is OK
message.setText("");
graph.nI = nI;
partitionChoice = partition.getSelectedItem();
if (partitionChoice == " regular ") {
for (int i = 0; i <= nI; i++) {
graph.xArray[i] = xArray[i];
}
}
else {
total = 0;
for (int i = 1; i <= nI; i++) {
xArray[i] = Math.random();   // length of interval i
total = total + xArray[i];
}
graph.xArray[0] = xArray[0];
for (int i = 1; i < nI; i++) {
xArray[i] = xArray[i-1] + xArray[i]*(bD - aD)/total;
graph.xArray[i] = xArray[i];  // rt endpt of interval i
}
xArray[nI] = bD;
graph.xArray[nI] = xArray[nI];
}                               // end of setting up partition
testPtChoice = testPt.getSelectedItem();
if (testPtChoice == "left endpt ") {
for (int i = 1; i <= nI; i++) {
tArray[i] = xArray[i-1];
x.set_value(tArray[i]);  // sets argument = tArray[i]
yArray[i] = function.value();   //computes f(t)
graph.yArray[i] = yArray[i];
sum = sum + yArray[i]*(xArray[i] - xArray[i-1]);
}
}
else if (testPtChoice == "right endpt") {
for (int i = 1; i <= nI; i++) {
tArray[i] = xArray[i];
x.set_value(tArray[i]);
yArray[i] = function.value();
graph.yArray[i] = yArray[i];
sum = sum + yArray[i]*(xArray[i] - xArray[i-1]);
}
}
if (testPtChoice == " midpoint  ") {
for (int i = 1; i <= nI; i++) {
tArray[i] = (xArray[i-1] + xArray[i])/2;
x.set_value(tArray[i]);
yArray[i] = function.value();
graph.yArray[i] = yArray[i];
sum = sum + yArray[i]*(xArray[i] - xArray[i-1]);
}
}
if (testPtChoice == " irregular ") {
for (int i = 1; i <= nI; i++) {
tArray[i] = xArray[i-1] + Math.random()*(xArray[i] - xArray[i-1]);
x.set_value(tArray[i]);
yArray[i] = function.value();
graph.yArray[i] = yArray[i];
sum = sum + yArray[i]*(xArray[i] - xArray[i-1]);
}
}
if (firstApprox == true) {
results.appendText("\n" +"  n    partition    testpoints       Riemann sum");
}
if (nI < 10) {
results.appendText("\n" +"  "+ nI + "    " + partitionChoice  + "    " +
testPtChoice + "   " + rndOff(sum));
}
else {
results.appendText("\n" +" "+ nI + "    " + partitionChoice  + "    " +
testPtChoice + "   " + rndOff(sum));
}
graph.repaint();
firstApprox = false;
} //end of else nI > MaxN, i.e. "if n is OK"
} //end of else entryValid
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;
}

}

/**************************
* Document: RSGraph.java
**************************/

import java.awt.*;

public class RSGraph extends Canvas {

final int K = 400;  //number of steps used to draw graph
final int MaxN = 100; //Maximum number of subintervals

Dimension d;
double[] xarray = new double[K+1];
double[] yarray = new double[K+1];
double[] xArray = new double[MaxN+1];
double[] yArray = new double[MaxN+1];
double[] tArray = new double[MaxN+1];
int phase = -1, tick, deltaTick, nI;

public void paint(Graphics g) {
if (phase == 1) {
g.setColor(Color.pink);
for (int i = 1; i <= nI; i++) {
if (yArray[i] > 0) {
g.fillRect(xScaler(xArray[i-1]), yScaler(yArray[i]),
xScaler(xArray[i]) - xScaler(xArray[i-1]),
yScaler(0.0) - yScaler(yArray[i]));
}
else {
g.fillRect(xScaler(xArray[i-1]), yScaler(0.0),
xScaler(xArray[i]) - xScaler(xArray[i-1]),
yScaler(yArray[i]) - yScaler(0.0));
}
}
g.setColor(Color.magenta);
for (int i = 1; i <= nI; i++) {
if (yArray[i] > 0) {
g.drawRect(xScaler(xArray[i-1]), yScaler(yArray[i]),
xScaler(xArray[i]) - xScaler(xArray[i-1]),
yScaler(0.0) - yScaler(yArray[i]));
}
else {
g.drawRect(xScaler(xArray[i-1]), yScaler(0.0),
xScaler(xArray[i]) - xScaler(xArray[i-1]),
yScaler(yArray[i]) - yScaler(0.0));
}
}
}  //end of if
if (phase != -1) {
d = this.size();
g.setColor(Color.black);
g.drawLine(0, yScaler(0.0), d.width, yScaler(0.0));   // x-axis
g.drawLine(xScaler(0.0), 0, xScaler(0.0), d.height - 6);  // y-axis
tick = (int)aD;    // start of x-ticks
deltaTick = 1 + (int)(bD - aD)/14;
do {
if (tick != 0) {
g.drawString(tick+"", xScaler(tick) - 4, yScaler(0.0) + 11);
g.drawLine(xScaler(tick), yScaler(0.0) - 2, xScaler(tick), yScaler(0.0));
}
tick = tick + deltaTick;
}
while (tick <= bD);  //end of x-ticks
for (int j = 0; j < K; j++) {                          // y = f(x)
g.drawLine(xScaler(xarray[j]), yScaler(yarray[j]),
xScaler(xarray[j+1]), yScaler(yarray[j+1]));
}
}  //end of if
}

private int xScaler(double x)
{
}

private int yScaler(double y)
{
return (int)((d.height - 11)*(ymax - y)/(ymax - ymin));
}

}

/**************************************
* Folder: expr    Document: Expr.java
**************************************/

// Mathematical expressions.
// Copyright 1996 by Darius Bacon; see the file COPYING.

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

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.

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