Need to do a java calculator which works with batches. It must take an operation and then, for the next ones, just use the result of the previous operation as the first value of its new operation.
public class Calculator {
/**
* Public constructor of the calculator.
*/
**public Calculator () {/*...*/}**
/**
* Clean the internal state of the calculator
*/
**public void cleanOperations () { /*...*/ }**
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
**public void addOperation(String operation , float ... values) { /*...*/ }**
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
**public float executeOperations () { /*...*/ }**
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
* #return String of the internal state of the calculator
*/
#Override
public String toString () { /* ... */ }
}
SOME TEST IT SHOULD PASS:
// Add operations, calculate internal state representation (string pattern) and execute them as a single batch
calculator.addOperation("+", 4.5f, 6.8f);
calculator.addOperation("-", 3.1f);
calculator.addOperation("/", 6f);
assertEquals("[STATE:[+]4.5_6.8[-]3.1[/]6.0]", calculator.toString());
result = calculator.executeOperations();
assertEquals("[STATE:]", calculator.toString()); // state is restored
assertEquals(1.366f, result, EPSILON);//EPSILON = 0.01f
As you can see it must work by doing the first operation with 2 values but the next ones using the value stores from the one before and then execute with the operator and the value, the new operation.
Are you looking for this?
public class Calculator {
private String operation;
private float[] values;
private float answer;
/**
* Public constructor of the calculator.
*/
public Calculator() {
}
/**
* Clean the internal state of the calculator
*/
public void cleanOperations() {
operation = null;
values = null;
answer = 0;
}
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
public void addOperation(String operation, float... values) {
if (!(operation.equals("+") || operation.equals("-") || operation.equals("*") || operation.equals("/"))) {
throw new IllegalArgumentException(operation + " is not a valid operator. ( '+', '-', '*', '/')");
}
this.operation = operation;
this.values = values;
}
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
*
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
public float executeOperations() {
switch (operation) {
case "+":
if (values.length == 1) {
answer += values[0];
} else {
for (float value : values) {
answer += value;
}
}
break;
case "-":
if (values.length == 1) {
answer -= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer -= values[i];
}
}
break;
case "*":
if (values.length == 1) {
answer *= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer *= values[i];
}
}
break;
case "/":
if (values.length == 1) {
if (values[0] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[0]);
}
answer /= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[i]);
}
answer /= values[i];
}
}
break;
}
return answer;
}
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
*
* #return String of the internal state of the calculator
*/
#Override
public String toString() {
StringBuilder string = new StringBuilder("values: [");
for (float value: values) {
string.append(value)
.append(" ")
.append(operation)
.append(" ");
}
string.append("] answer = ").append(answer);
return string.toString();
}
}
Related
Question
Create a class named KeepSmallArray that uses an array to implement the KeepSmallInterface. Use the program TestKeepSmall to test your implementation.
Basically i have to drop the two smallest scores from the assignement.
Key Points
KeepSmallArray object needs to be told at creation time how many grades (or whatever) it should keep track of.
Hints
helpful if you make the array one space larger than it "needs" to be. For example, if it's remembering 2 grades, make the array size 3.
You need to keep the elements of the array in order. Consider using the insert algorithm.
Error
Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.Comparable; ([Ljava.lang.Object; and [Ljava.lang.Comparable; are in module java.base of loader 'bootstrap')
Attempted Solution
Tried error handling and changed some stuff around but that didnt help
however the problem seems to be in the constructor of the keepSmallArray class.
My code
TestKeepSmall
public class TestKeepSmall {
public static final int NUM_ASGNS = 10;
public static final Scanner kbd = new Scanner(System.in);
public static final Random r = new Random();
public static void main(String[] args) {
for (int numDrops = 2; numDrops < NUM_ASGNS / 2; ++numDrops) {
int numKeeps = NUM_ASGNS - numDrops;
Integer[] grades = new Integer[numKeeps];
int numKept = 0;
System.out.println("\n"
+ "Keeping the best " + numKeeps + " of " + NUM_ASGNS
+ " assignments.");
KeepSmallInterface<Integer> drops = new KeepSmallArray<>(numDrops);
// KeepSmallInterface<Integer> drops = new KeepSmallHeap<>(numDrops);
// test size/capacity/isEmpty
System.out.println(" --> starts with size 0: "
+ (drops.size() == 0 ? "PASS" : "FAIL ***"));
System.out.println(" --> starts with given capacity: "
+ (drops.capacity() == numDrops ? "PASS" : "FAIL ***"));
System.out.println(" --> starts empty: "
+ (drops.isEmpty() ? "PASS" : "FAIL ***"));
// toArray
Object[] dropObjects = drops.toArray();
System.out.println(" --> toArray() returns correct size: "
+ (dropObjects.length == drops.size()
? "PASS" : "FAIL ***"));
Comparable[] dropComps = drops.toArray(new Comparable[3]);
System.out.println(" --> toArray(T[]) returns correct size: "
+ (dropComps.length == 3
? "PASS" : "FAIL ***"));
boolean nulledOut = true;
for (int i = 0; i < dropComps.length; ++i) {
if (dropComps[i] != null) {
nulledOut = false;
}
}
System.out.println(" --> toArray(T[]) nulls unused elements: "
+ (nulledOut ? "PASS" : "FAIL ***"));
pause();
// test add
for (int i = 1; i <= NUM_ASGNS; ++i) {
// get a grade from the user
int grade = randomGrade();
System.out.printf("A%02d grade is %3d.%n", i, grade);
// see if it belongs on the drop list
Integer keeper = drops.add(grade);
// if not, add it to the kept grades array
if (keeper != null) {
grades[numKept] = keeper;
++numKept;
// test get
Integer newMaxDrop = drops.get(drops.size() - 1);
System.out.println(" --> \"bumped out\" largest value: "
+ (newMaxDrop <= keeper ? "PASS" : "FAIL ***"
+ "(dropped " + keeper + " instead of "
+ newMaxDrop + ")"));
}
}
pause();
// toArray
dropObjects = drops.toArray();
System.out.println(" --> toArray() returns correct size: "
+ (dropObjects.length == drops.size()
? "PASS" : "FAIL ***"));
System.out.println("\n"
+ "Your dropped grades are " + Arrays.toString(dropObjects)
+ "\nYour kept grades are " + Arrays.toString(grades));
// toArray(T[])
dropComps = drops.toArray(new Comparable[3]);
System.out.println(" --> toArray(T[]) returns correct size: "
+ (dropComps.length == Math.max(3, drops.size())
? "PASS" : "FAIL ***"));
boolean inOrder = true;
int upperBound = Math.min(dropComps.length, drops.size());
for (int j = 1; j < upperBound; ++j) {
if (dropComps[j - 1].compareTo(dropComps[j]) > 0) {
inOrder = false;
}
}
System.out.println(" --> toArray(T[]) returns ordered array: "
+ (inOrder ? "PASS" : "FAIL ***"));
if (upperBound < dropComps.length) {
nulledOut = true;
for (int i = upperBound; i < dropComps.length; ++i) {
if (dropComps[i] != null) {
nulledOut = false;
}
}
System.out.println(" --> toArray(T[]) nulls unused elements: "
+ (nulledOut ? "PASS" : "FAIL ***"));
}
// contains
Integer in = oneOf(dropObjects);
System.out.println(" --> contains " + in + ": "
+ (drops.contains(in) ? "PASS" : "FAIL ***"));
Integer out = oneNotOf(dropObjects);
System.out.println(" --> !contains " + out + ": "
+ (!drops.contains(out) ? "PASS" : "FAIL ***"));
pause();
}
}
private static void pause() {
System.out.print("\n...press enter...");
kbd.nextLine();
System.out.println();
}
private static int randomGrade() {
return Math.max(r.nextInt(101), r.nextInt(90));
}
private static Integer oneOf(Object[] dropComps) {
int len = dropComps.length;
int n = r.nextInt(len);
return (Integer)dropComps[n];
}
private static Integer oneNotOf(Object[] dropComps) {
int len = dropComps.length;
int result = 0;
boolean ok;
do {
ok = true;
result = r.nextInt(101);
for (int i = 0; ok && i < dropComps.length; ++i) {
if (dropComps[i].equals(result)) {
ok = false;
}
}
} while (!ok);
return result;
}
}
KeepSmallArray
public class KeepSmallArray<T extends Comparable<? super T>>
implements KeepSmallInterface<T> {
private T[] smallArray;
public KeepSmallArray(int len) {
if(len <= 0) {
throw new NullPointerException();
}
smallArray = (T[]) new Object[len + 1];
}
#Override
public int size() {
int count = 0;
for (T item : smallArray) {
if (item != null) {
count++;
} else {
break;
}
}
return count;
}
#Override
public int capacity() {
return smallArray.length;
}
#Override
public boolean isEmpty() {
return size() == 0;
}
#Override
public void clear() {
try{
smallArray = (T[]) new Object[smallArray.length];
}
catch(Exception e){
}
}
#Override
public boolean contains(Object obj) {
for (T item : smallArray) {
if (obj.equals(item)) {
return true;
}
}
return false;
}
#Override
public Object[] toArray() {
return toArray(smallArray);
}
#Override
public Object[] toArray(Object[] array) {
if (array == null) {
throw new NullPointerException("given array is not initialized");
}
return array;
}
#Override
public T add(T newElement) {
if (newElement == null) {
throw new NullPointerException("null cannot be added");
}
return null;
}
#Override
public T get(int index) {
if (index < 0 || index > size() - 1) {
throw new IllegalArgumentException("index out of range");
}
return smallArray[index];
}
}
Keep Interface
/**
* A collection of "small" elements, sorted from smallest to largest.
* The collection contains a limited number of elements (its capacity).
* The client may request that a new element be added, but that element
* will only be added if there is room for it <em>or</em> if it is smaller
* than one of the elements currently stored in this container. In the
* latter case, the largest element in the container will be "bumped out"
* to make room for the new one.
* <p>
* Such a container may be used to keep track of assignment grades to be
* dropped from an average (for example, to track the two smallest of ten
* assignment grades). Alternatively, an appropriately programmed class
* could instead track the eight highest grades from ten (tho' such a class
* might better be called a "KeepBig" container).
*
*
*/
public interface KeepSmallInterface<T extends Comparable<? super T>> {
/**
* The number of elements currently in this container.
*
* #return the number of elements in this container.
*/
public int size();
/**
* The maximum number of elements this container can hold.
*
* #return the number of elements this container can hold.
*/
public int capacity();
/**
* Whether this bag is empty.
*
* #return true if this container has no elements in it; false otherwise.
*/
public boolean isEmpty();
/**
* Remove all the elements from this container.
*/
public void clear();
/**
* Consider the given element for addition to this container.
* If there is space available in this container, then given element
* will be added and <code>null</code> returned. Otherwise the
* largest of the current elements and the given element will be
* "bumped out" and returned. (Note that the given element may be
* the one "bumped out".)
*
* #param newElement the element to add.
* #return the element "bumped out" of this container;
* OR null if no element was "bumped out".
* #throws NullPointerException if <code>newElement</code> is
* <code>null</code>
*/
public T add(T newElement);
/**
* The smallest-but-<tt>i</tt> element in this container. For example,
* <code>get(0)</code> returns the smallest element in this container,
* while <code>get(2)</code> returns the third smallest element
* (<i>i.e.</i> the one with exactly two elements before it in the sorted
* order).
*
* #param index the number of smaller elements than the one requested.
* #return the smallest-but-<tt>index</tt> element in this container;
* OR null if there is none.
* #throws IllegalArgumentException if <tt>index</tt> is not in the range
* <code>0..size()-1</code>
*/
public T get(int index);
/**
* Whether the container contains the given element.
*
* #param obj the element to test for.
* #return true if it's present; false otherwise.
*/
public boolean contains(Object obj);
/**
* An array containing all the elements of this container, in order from
* smallest to largest.
*
* #return a sorted array with all this container's elements.
*/
public Object[] toArray();
/**
* Returns an array containing all of the elements in this container sorted
* from smallest to largest; the runtime type of the returned array is that
* of the given array. If the list fits in the given array, it is returned
* therein. Otherwise, a new array is allocated with the runtime type of
* the specified array and just large enuf to hold all this container's
* elements.
*
* #param <E> The base type of the passed-in array.
* #param array the array to place the elements in.
* #return a sorted array with all this container's elements.
* #throws ArrayStoreException - if the runtime type of the specified
* array is not a supertype of the runtime type of every element in this
* container.
* #throws NullPointerException if the specified array is null.
*/
public <E> E[] toArray(E[] array);
}
So you can't use an array of Object since you are storing Comparable. Instead, you need to use an array of Comparable.
smallArray = (T[]) new Object[len + 1];
should be
smallArray = (T[]) new Comparable[len + 1];
I'm trying to print out a shape of the letter V using recursion only. I have seen some of the codes in this website related to my problem, but the majority use loops instead of recursion.
Here's my code:
public class Pattern {
public static void main(String[] args) {
printPattern(5);
}
public static void Pattern(int count, String s) {
if (count == 0) {
return;
}
System.out.print(s);
Pattern(count - 1, s);
}
public static void upperhalf(int count, int max) {
if (count == 0) {
return;
}
Pattern(max - count, " ");
Pattern(count, "* ");
System.out.println();
upperhalf(count - 1, max);
}
public static void printPattern(int n) {
upperhalf(n, n);
}
}
Output:
* * * * *
* * * *
* * *
* *
*
The output I want:
* *
* *
* *
* *
*
One way of solving it. Replace your two consecutive Pattern calls with this:
Pattern(max - count, " ");
Pattern(1, "* ");
Pattern(count - 2, " ");
Pattern(1, count > 1 ? "* " : "");
(Ie your first Pattern call, then an explicit for a single *, then a few spaces (2 less than in your approach), then the last *).
You also need to change the exit statement slightly:
public static void Pattern(int count, String s) {
if (count <= 0) { // <= instead of ==
return;
}
If your interested, here is one way to do it by by taking successive substrings.
Here are some key points.
The starting size is modified to ensure it is odd. This guarantees the V will be uniform.
The passed string consists of white space followed by an asterisk. The left asterisk is supplied by the recursive method.
The indentation is used to properly position the start of the remaining string.
int size = 10;
String v = " ".repeat((size | 1) - 2) + "*";
V(v,0);
public static void V(String v, int indent) {
System.out.println(" ".repeat(indent)+ "*" + v);
if (v.isEmpty()) {
return;
}
V(v.substring(2),indent+1);
}
I am stuck trying to call a method. No matter what I do, I get an error that it can't find the symbol. I am trying to use the variables total (from the surfaceArea method) and volume (from the volume method).
The problems are in the toString method, where it cannot see the variables no matter what I do. I am sure it is something incredibly basic I a missing, so I hope someone can figure it out.
Here is the Error Log:
Ellipsoid.java:176: error: cannot find symbol
String vout = df.format(volume);
^
symbol: variable volume
location: class Ellipsoid
Ellipsoid.java:177: error: cannot find symbol
String sout = df.format(total);
^
symbol: variable total
location: class Ellipsoid
2 errors
And here is the code itself. I tried to make it as easy to read as possible:
/**
* This program lets the user enter values of and Ellipsoid.
* #version 02/05/2020
*/
public class Ellipsoid {
// fields
private String label;
private double a, b, c;
//public double total, volume;
// constructor
/**
* This constructor creates a ellipsoid and gets its information.
*
* #param labelIn is the label entered by the user.
* #param aIn is the a valuve entered by the user.
* #param bIn is the b valuve entered by the user.
* #param cIn is the c valuve entered by the user.
*/
public Ellipsoid(String labelIn, double aIn, double bIn, double cIn) {
setLabel(labelIn);
setA(aIn);
setB(bIn);
setC(cIn);
}
// methods
/**
* This method gets the label string.
* #return returns the label of the ellipsoid.
*/
public String getLabel() {
return label;
}
/**
* This method sets the label of the ellipsoid.
* #param labelIn is the label entered by the user.
* #return returns true or false depending on user input.
*/
public boolean setLabel(String labelIn) {
if (labelIn == null) {
return false;
}
else {
label = labelIn.trim();
return true;
}
}
/**
* This method gets the a values of the ellipsoid.
* #return returns a values of the ellipsoid.
*/
public double getA() {
return a;
}
/**
* This method sets the a value of the ellipsoid.
* #param aIn is the a value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setA(double aIn)
{
if (aIn > 0)
{
a = aIn;
return true;
}
else
{
return false;
}
}
/**
* This method gets the b value of the ellipsoid.
* #return returns the b value of the ellipsoid.
*/
public double getB()
{
return b;
}
/**
* This method sets the b value of the ellipsoid.
* #param bIn is the b value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setB(double bIn)
{
if (bIn > 0)
{
b = bIn;
return true;
}
else
{
return false;
}
}
/**
* This method gets the c value of the ellipsoid.
* #return returns the c value of the ellipsoid.
*/
public double getC()
{
return c;
}
/**
* This method sets the c value of the ellipsoid.
* #param cIn is the c value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setC(double cIn)
{
if (cIn > 0)
{
c = cIn;
return true;
}
else
{
return false;
}
}
/**
* This method finds the volume of the ellipsoid.
* #return returns the volume of the ellipsoid.
*/
public double volume()
{
double volume = 4 * Math.PI * a * b * c;
volume = volume / 3;
return volume;
}
/**
* This method finds the surface area of the ellipsoid.
* #return returns the surface area.
*/
public double surfaceArea() {
double ab = (a * b);
ab = Math.pow(ab, 1.6);
double ac = a * c;
ac = Math.pow(ac, 1.6);
double bc = b * c;
bc = Math.pow(bc, 1.6);
double top = ab + ac + bc;
double bottom = top / 3;
double full = bottom * 1 / 1.6;
double total = 4 * Math.PI * full;
return total;
}
/**
* This method prints the information of the ellipsoid.
* #return returns the information of the ellipsoid.
*/
public String toString() {
DecimalFormat df = new DecimalFormat("#,##0.0###");
surfaceArea();
volume();
String aout = df.format(a);
String bout = df.format(b);
String cout = df.format(c);
String vout = df.format(volume);
String sout = df.format(total);
String output = "Ellipsoid \"" + label + "\" with axes a = " + aout
+ ", b = " + bout + ", c = " + cout + " units has:\n\tvolume = "
+ vout + " cubic units\n\tsurface area = "
+ sout + " square units";
return output;
}
}
volume and total are local members to volume() and surfaceArea() methods respectively. It is not visible in toString() method. But a, b and c are visible as they are declared class level. Try assigning returned values from those methods to local variables in toString() as below:
public String toString() {
DecimalFormat df = new DecimalFormat("#,##0.0###");
double total = surfaceArea();
double volume = volume();
....
String vout = df.format(volume);
String sout = df.format(total);
....
}
In the Ellipsoid class, you didn't declare the total and volume variables.
They are commented there, try to uncomment this line:
//public double total, volume;
Should help, but if you want to assign the values to those instance fields while calculating, change the double total and double total in the proper methods to this.total and this.volume.
This will allow you to both keep the data inside object and return it through method.
This is somewhat of a loaded question. I'm writing a Lisp evaluator algorithm which takes input expressions written, for example, as:
(+ (- 6) (* 2 3 4) (/ (+ 3) (*) (- 2 3 1)))
The problem is: it throws an EmptyStack error because of the operations
(- 6) and (*)
When I write it as (- 0 6) and (* 1) it compiles correctly with the correct result. I think it is looking to subtract FROM something, and multiply something (can't have no digits). It has something to do with the structure of my operand evaluation. I want to implement this into the program itself, without having to manually add zeros for subtraction and one's for multiplication. Any ideas on how to go doing this?
I've been staring at it all day and can't seem to figure out why my push/pop structure acts up in this way. I tried experimenting with regex, but that did not seem to do the trick.
Program structure:
1) Uses two stacks: expressionStack of type Object, and currentOperationStack of type Double.
2) evaluateCurrentOperation() method evaluates the current operation:
Pops operands from expressionStack and pushes them onto currentOperationStack until it finds an operator.
Uses the operator on the operands on currentOperationStack.
Pushes the result into expressionStack.
3) evaluate() method evaluates the current Lisp expression in inputExpression (using a scanner to read, and case statements for operands) and returns the result.
import java.util.*;
public class LispEvaluator {
/**
* Input expression
*/
private String inputExp;
/**
* Stacks created for the main expression and current operation.
*/
private Stack<Object> expStack;
private Stack<Double> currentOpStack;
/**
* Default constructor initializes input and creates Stack objects.
*/
public LispEvaluator()
{
inputExp = "";
expStack = new Stack<Object>();
currentOpStack = new Stack<Double>();
}
/**
* Constructor sets inputExpr to inputExpression and creates Stack objects.
* #param inputExpression
* #throws LispEvaluatorException
*/
public LispEvaluator(String input_Expression) throws LispEvaluatorException
{
// If there is no expression, throws an exception.
if(input_Expression == null)
{
throw new LispEvaluatorException("Input statement is null.");
}
// Objects created
inputExp = input_Expression;
expStack = new Stack<Object>();
currentOpStack = new Stack<Double>();
}
/**
* evaluateCurrentOperation() method evaluates the current operation:
* - Pops operands from expStack and pushes them onto currentOpStack until it finds an operator.
* - Uses the operator on the operands on currentOpStack.
* - Pushes the result into exprStack.
*/
private void evaluateCurrentOperation()
{
String current_Operation;
boolean numeric = true;
// Do... while statement sets current operation (while it is numeric).
do{
current_Operation = (String.valueOf(expStack.pop()));
try{
Double number = Double.parseDouble(current_Operation);
currentOpStack.push(number);
}catch(NumberFormatException nfe){
numeric = false;
}
} while(numeric);
double result;
switch (current_Operation) {
case "*":
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result *= currentOpStack.pop();
}
break;
case "/":
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result /= currentOpStack.pop();
}
break;
case "+":
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result += currentOpStack.pop();
}
break;
case "-":
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result -= currentOpStack.pop();
}
break;
default:
result = currentOpStack.pop();
break;
}
expStack.push(result);
}
/**
* evaluate() method evaluates the current Lisp expression in inputExpr and returns the result.
* #throws LispEvaluatorException
*/
public double evaluate() throws LispEvaluatorException
{
Scanner inputExprScanner = new Scanner(inputExp);
/**
* Breaks the string into single characters using a delimiter.
*/
inputExprScanner = inputExprScanner.useDelimiter("\\s*");
/**
* Scans the tokens in the string (runs while there is a next token).
*/
while (inputExprScanner.hasNext())
{
/**
* If it has an operand, pushes operand object onto the exprStack.
*/
if (inputExprScanner.hasNextInt())
{
/**
* Scanner gets all of the digits (regular expression \\d+ means any digit).
*/
String dataString = inputExprScanner.findInLine("\\d+");
expStack.push(Double.parseDouble(dataString));
}
else
{
/**
* Gets one character in String token.
*/
String token = inputExprScanner.next();
char item = token.charAt(0);
switch(item)
{
// If "(", next token is an operator (so do nothing).
case '(':
break;
// If ")", it will evaluate that expression since parenthesis are closed.
case ')':
evaluateCurrentOperation();
break;
// If there is an operator "* + / -", then it pushes the operator onto exprStack.
case'*':
expStack.push("*");
break;
case'+':
expStack.push("+");
break;
case'/':
expStack.push("/");
break;
case'-':
expStack.push("-");
break;
/**
* Default throws an error.
*/
default:
throw new LispEvaluatorException(item + " is not a valid operator");
} // end switch
} // end else
} // end while
/**
* If you run out of tokens, the value on the top of exprStack is the result of the expression.
*
*/
return Double.parseDouble(String.valueOf(expStack.pop()));
}
/**
* Reset method sets inputExpr to inputExpression and clears Stack objects.
* #param inputExpression
* #throws LispEvaluatorException
*/
public void reset(String inputExpression) throws LispEvaluatorException
{
if(inputExpression == null)
{
throw new LispEvaluatorException("Input statement is null");
}
inputExp = inputExpression;
expStack.clear();
currentOpStack.clear();
}
/**
* Test method to print the result of the expression evaluator.
* #param s
* #param expr
* #throws LispEvaluatorException
*/
private static void evaluateExprTest(String s, LispEvaluator expr) throws LispEvaluatorException
{
Double result;
System.out.println("Expression: " + s);
expr.reset(s);
result = expr.evaluate();
System.out.printf("Result: %.2f\n", result);
System.out.println("-------");
}
/**
* Main method uses test cases to test the evaluator.
* #param args
* #throws LispEvaluatorException
*/
public static void main (String args[]) throws LispEvaluatorException
{
LispEvaluator expr= new LispEvaluator();
/**
* Expressions are tested.
* Note: For each operation written as (- 6), in order for the Stack to continue,
* it needs to be written as (- 0 6). This way, it is subtracting from a digit.
*/
String test1 = "(+ 5 0 10)";
String test2 = "(+ 5 0 10 (- 7 2))";
String test3 = "(+ (- 0 6) (* 2 3 4) (/ (+ 3) (* 1) (- 2 3 1)))";
String test4 = "(+ (- 0 632) (* 21 3 4) (/ (+ 32) (* 1) (- 21 3 1)))";
String test5 = "(+ 2 6) (* 12 18) (/ (+ 32) (* 1) (- 21 3 1))";
String test6 = "(+ 1 2 (- 5 1) (*4 11 14))";
evaluateExprTest(test1, expr);
evaluateExprTest(test2, expr);
evaluateExprTest(test3, expr);
evaluateExprTest(test4, expr);
evaluateExprTest(test5, expr);
evaluateExprTest(test6, expr);
}
}
Custom exception class:
public class LispEvaluatorException extends Exception{
public LispEvaluatorException(String message) {
super(message);
}
}
The fixes are pretty straightforward: the crashes that you get are because unary operations are distinct features, so you need to code for them explicitly.
Fixing this problem consists of two parts:
Add a check for empty stack prior to the first pop()
Add a check for unary minus - and unary division /, which have separate code paths.
Here is the portion of the code that needs fixing:
switch (current_Operation) {
case "*":
if (currentOpStack.isEmpty()) {
result = 1;
break;
}
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result *= currentOpStack.pop();
}
break;
case "/":
if (currentOpStack.isEmpty()) {
result = 1;
break;
}
result = currentOpStack.pop();
if (currentOpStack.isEmpty()) {
// Unary division
result = 1.0 / result;
break;
}
while(!currentOpStack.isEmpty()){
result /= currentOpStack.pop();
}
break;
case "+":
if (currentOpStack.isEmpty()) {
result = 0;
break;
}
result = currentOpStack.pop();
while(!currentOpStack.isEmpty()){
result += currentOpStack.pop();
}
break;
case "-":
if (currentOpStack.isEmpty()) {
result = 0;
break;
}
result = currentOpStack.pop();
if (currentOpStack.isEmpty()) {
// Unary minus
result = -result;
break;
}
while(!currentOpStack.isEmpty()){
result -= currentOpStack.pop();
}
break;
default:
result = currentOpStack.pop();
break;
}
Demo.
I was given the assignment to "implement and test a language “recognizer” object, provided to you through a Java interface defined at the end of this document. A language recognizer accepts strings of characters and determines whether or not they are in the language."
The language is as follows:
L = {a*b} union {ab*}, or restated in English, L is the set of all strings of either (1) zero or more as (a*) followed by a b, or (2) an a followed by zero or more bs (b*).
I've made some progress, but I'm stuck.
Here's the interface:
/** The Recognizer interface provides a recognizer for the
* language L below.
*
* Let Sigma = {a,b} = the input character set.
*
* Let L = {ab*} union {a*b} be the language (set of
* legal strings) recognized by this recognizer.
*
* Let S = s1s2...sn be the string of n characters already
* input by this recognizer.
*
* Recognizer constructor must ensure: S' = < >
*/
interface Recognizer {
/**
* require: c in Sigma
*
* ensure: S' = S ^ c
*
* param c
*/
public void nextChar(char c);
/**
* Checks if input string S is in language L.
*
* return (S in L)
*/
public boolean isIn();
/**
* ensure: S' = < >
*/
public void reset();
}
Here's my structure:
import java.util.*;
public class LanguageVector implements Recognizer {
int element = 0;
int a = 0;
int b = 0;
Vector<Character> v = new Vector<Character>();
public void nextChar(char c) {
v.add(c);
}
public boolean isIn(){
boolean isTrue = true;
for(int i=0;i<v.size();i++) {
if (v.size() == 1){
if (v.firstElement() == 'a' || v.firstElement() =='b'){
isTrue = true;
}
else
isTrue = false;
}
else if (v.firstElement() == 'a'){
if (v.lastElement() == 'a')
isTrue = false;
else if (v.lastElement() == 'b')
while (v.elementAt(element)== 'a' ){
a++;
element++;
System.out.println(element);
}
while (v.elementAt(element)== 'b'){
b++;
element++;
System.out.println(element);
}
if (v.elementAt(element)!= 'b'){
isTrue = false;
}
else if (a > 1 && b > 1){
isTrue = false;
}
else
isTrue = true;
}
else if (v.firstElement() == 'b'){
isTrue = false;
}
else
isTrue = false;
}
return isTrue;
}
public void reset(){
v.clear();
}
}
And here's my testing class:
import java.util.*;
public class LanguageTester {
/**
* #param args
*/
public static void main(String[] args) {
Recognizer r = new LanguageVector();
r.nextChar('a');
r.nextChar('a');
r.nextChar('a');
r.nextChar('b');
if (r.isIn())
System.out.println("string is in L");
else
System.out.println("string is not in L");
System.out.println("End of test");
r.reset();
}
}
When I run, I get the following output:
1
2
3
Exception in thread "main" 4
java.lang.ArrayIndexOutOfBoundsException: 4 >= 4
at java.util.Vector.elementAt(Unknown Source)
at LanguageVector.isIn(LanguageVector.java:34)
at LanguageTester.main(LanguageTester.java:18)
Why is this happening?
Also, how can I use user input, turn it into a vector, and use that within this structure now?
Forgive me if this question is too lengthy, I wasn't sure how to narrow it down without leaving important details out. Thanks
When it occurs?
Out of bounds exception is occurred when you try to access an array with index that exceeded its length. maximum index of a java array is (length -1)
for example:
String [] stringArray = new String[10];
stringArray[10]
// the code above will produce an out of bounds exception, because the it bigger than length -1, which is 10 - 1 = 9.
If you don't know the size or length of an array, you can know it from stringArray.length.
How to handle it?
You should make sure that your program doesn't access an array with index bigger than length - 1.
example:
for(int i=0;i<stringArray.lenght;i++) {
//write your code here
}
the above code will guarantee that stringArray will never be accessed beyond its maximum index.
Your Case
In your case, 4 >= 4 itself says you are trying to access 5th element i.e. elementAt(4) however size of your Vector of 4.
Array is based on 0 index i.e. if your length is 4 you will have data at as Vector[0], Vector[1], Vector[2], Vector[3].
Also read this for more info...
The problem is in the isIn() method. You're not checking whether the element variable is still below v.size(). You just continue incrementing it so the next time that the application accesses v.elementAt(element); the variable element is bigger than the size of v, so it's an ArrayOutofBounds exception.