diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afbdab3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..eeec1b9 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +CalculatorAppProject \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/dictionaries/c4q_john.xml b/.idea/dictionaries/c4q_john.xml new file mode 100644 index 0000000..bc0df54 --- /dev/null +++ b/.idea/dictionaries/c4q_john.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..736c7b5 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6803ec7 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..3b31283 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d36b37c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + 1.7 + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f8fed43 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..def6a6a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Calculator.iml b/Calculator.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/Calculator.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index a94d6b4..e240773 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,67 @@ +<<<<<<< HEAD +# CalculatorAppProject + +### Introduction + +As the name implies, this is a calculator meant to be run on the android platform. Made in android studio as a two-person group project it is our our submission for the unit-1 final assignment. + +### functionality + +- To use the RAD nad DEG functions you must add a '(' after. No need to close them. +- If you press the +/- sign when there is an expression on the screen, this will calculate it for you and return the opposite value. + +## featured +- ans = saves current ans +- c/ans = clears current ans +- log +- log10 +- square root +- sin, cos, tan +- deg +- rad +- exponent +- e +- pi +- phi +- modulus <--works as it would on java, returning the remainded of the operation its called on. +- () +- abs = absolute value +- ce = clear end +- ac = all clear + +###Code + +There are two main layouts: + +- An every day working calculator in vertical mode. +- A scientific calculator when device is horizontal extending the functionality of the regular calculator. + + There is a specified layout XML file for each mode. There is also a specialized themed XML in the drawable folder under res which draws the edges in some of the UI elements. + + To calculate user input we chose to use EvalEx an expression calculator written in java. + For reference see: https://github.com/uklimaschewski/EvalEx + + Our MainActivity class handles user input which we chose to handle through the use of methods called by the OnClick attributes specified for each button in the xml. + + We buit specified methods when necessary while doing our best to keep our code optimized and concise. The Following is a breakdown of the methods used and the division of labor. + + - onCreate: both + - getButtonText: both + - ce: John + - getOperators: Madelyn + - sohcahtoa: Madelyn + - positiveNegativeSwitch: both + - allClear: John + - ans: John + - clearAns: John + - absButton: John + - checkParenthesis: Madelyn + - openCloseParens: Madelyn + - evaluateExpression: both + - onSaveInstanceState: Madelyn + + When it came to the layout, testing and error handling there was an equal division of labor from both of us. +======= # calculator Submit your calculator projects here +>>>>>>> 565fe4086ff5928deb9f232fe32938e1acd9b467 diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..ea83a3a --- /dev/null +++ b/app/app.iml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..e749ab6 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "madelyntav.c4q.nyc.calculator" + minSdkVersion 17 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.1.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..aba9fc6 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/c4q-madelyntavarez/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/madelyntav/c4q/nyc/calculator/ApplicationTest.java b/app/src/androidTest/java/madelyntav/c4q/nyc/calculator/ApplicationTest.java new file mode 100644 index 0000000..957af75 --- /dev/null +++ b/app/src/androidTest/java/madelyntav/c4q/nyc/calculator/ApplicationTest.java @@ -0,0 +1,13 @@ +package madelyntav.c4q.nyc.calculator; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3c4436d --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000..6660261 Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/madelyntav/c4q/nyc/calculator/Expressions.java b/app/src/main/java/madelyntav/c4q/nyc/calculator/Expressions.java new file mode 100644 index 0000000..cac4009 --- /dev/null +++ b/app/src/main/java/madelyntav/c4q/nyc/calculator/Expressions.java @@ -0,0 +1,1133 @@ +package madelyntav.c4q.nyc.calculator; + +/* + * Copyright 2012 Udo Klimaschewski + * + * http://UdoJava.com/ + * http://about.me/udo.klimaschewski + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +import java.util.Iterator; + + import java.math.BigDecimal; + import java.math.BigInteger; + import java.math.MathContext; + import java.math.RoundingMode; + import java.util.ArrayList; + import java.util.HashMap; +import java.util.List; + import java.util.Map; + import java.util.Stack; + +/** + *

EvalEx - Java Expression Evaluator

+ * + *

Introduction

+ * EvalEx is a handy expression evaluator for Java, that allows to evaluate simple mathematical and boolean expressions. + *
+ * Key Features: + * + *
+ *

Examples

+ *
+ *  BigDecimal result = null;
+ *
+ *  Expression expression = new Expression("1+1/3");
+ *  result = expression.eval():
+ *  expression.setPrecision(2);
+ *  result = expression.eval():
+ *
+ *  result = new Expression("(3.4 + -4.1)/2").eval();
+ *
+ *  result = new Expression("SQRT(a^2 + b^2").with("a","2.4").and("b","9.253").eval();
+ *
+ *  BigDecimal a = new BigDecimal("2.4");
+ *  BigDecimal b = new BigDecimal("9.235");
+ *  result = new Expression("SQRT(a^2 + b^2").with("a",a).and("b",b).eval();
+ *
+ *  result = new Expression("2.4/PI").setPrecision(128).setRoundingMode(RoundingMode.UP).eval();
+ *
+ *  result = new Expression("random() > 0.5").eval();
+ *
+ *  result = new Expression("not(x<7 || sqrt(max(x,9)) <= 3))").with("x","22.9").eval();
+ * 
+ *
+ *

Supported Operators

+ * + * + * + * + * + * + * + * + * + *
Mathematical Operators
OperatorDescription
+Additive operator
-Subtraction operator
*Multiplication operator
/Division operator
%Remainder operator (Modulo)
^Power operator
+ *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
Boolean Operators*
OperatorDescription
=Equals
==Equals
!=Not equals
<>Not equals
<Less than
<=Less than or equal to
>Greater than
>=Greater than or equal to
&&Boolean and
||Boolean or
+ * *Boolean operators result always in a BigDecimal value of 1 or 0 (zero). Any non-zero value is treated as a _true_ value. Boolean _not_ is implemented by a function. + *
+ *

Supported Functions

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Function*Description
NOT(expression)Boolean negation, 1 (means true) if the expression is not zero
IF(condition,value_if_true,value_if_false)Returns one value if the condition evaluates to true or the other if it evaluates to false
RANDOM()Produces a random number between 0 and 1
MIN(e1,e2)Returns the smaller of both expressions
MAX(e1,e2)Returns the bigger of both expressions
ABS(expression)Returns the absolute (non-negative) value of the expression
ROUND(expression,precision)Rounds a value to a certain number of digits, uses the current rounding mode
FLOOR(expression)Rounds the value down to the nearest integer
CEILING(expression)Rounds the value up to the nearest integer
LOG(expression)Returns the natural logarithm (base e) of an expression
LOG10(expression)Returns the common logarithm (base 10) of an expression
SQRT(expression)Returns the square root of an expression
SIN(expression)Returns the trigonometric sine of an angle (in degrees)
COS(expression)Returns the trigonometric cosine of an angle (in degrees)
TAN(expression)Returns the trigonometric tangens of an angle (in degrees)
ASIN(expression)Returns the angle of asin (in degrees)
ACOS(expression)Returns the angle of acos (in degrees)
ATAN(expression)Returns the angle of atan (in degrees)
SINH(expression)Returns the hyperbolic sine of a value
COSH(expression)Returns the hyperbolic cosine of a value
TANH(expression)Returns the hyperbolic tangens of a value
RAD(expression)Converts an angle measured in degrees to an approximately equivalent angle measured in radians
DEG(expression)Converts an angle measured in radians to an approximately equivalent angle measured in degrees
+ * *Functions names are case insensitive. + *
+ *

Supported Constants

+ * + * + * + * + * + *
ConstantDescription
PIThe value of PI, exact to 100 digits
TRUEThe value one
FALSEThe value zero
+ * + *

Add Custom Operators

+ * + * Custom operators can be added easily, simply create an instance of `Expression.Operator` and add it to the expression. + * Parameters are the operator string, its precedence and if it is left associative. The operators `eval()` method will be called with the BigDecimal values of the operands. + * All existing operators can also be overridden. + *
+ * For example, add an operator `x >> n`, that moves the decimal point of _x_ _n_ digits to the right: + * + *
+ * Expression e = new Expression("2.1234 >> 2");
+ *
+ * e.addOperator(e.new Operator(">>", 30, true) {
+ *     {@literal @}Override
+ *     public BigDecimal eval(BigDecimal v1, BigDecimal v2) {
+ *         return v1.movePointRight(v2.toBigInteger().intValue());
+ *     }
+ * });
+ *
+ * e.eval(); // returns 212.34
+ * 
+ *
+ *

Add Custom Functions

+ * + * Adding custom functions is as easy as adding custom operators. Create an instance of `Expression.Function`and add it to the expression. + * Parameters are the function name and the count of required parameters. The functions `eval()` method will be called with a list of the BigDecimal parameters. + * All existing functions can also be overridden. + *
+ * For example, add a function `average(a,b,c)`, that will calculate the average value of a, b and c: + *
+ *
+ * Expression e = new Expression("2 * average(12,4,8)");
+ *
+ * e.addFunction(e.new Function("average", 3) {
+ *     {@literal @}Override
+ *     public BigDecimal eval(List parameters) {
+ *         BigDecimal sum = parameters.get(0).add(parameters.get(1)).add(parameters.get(2));
+ *         return sum.divide(new BigDecimal(3));
+ *     }
+ * });
+ *
+ * e.eval(); // returns 16
+ * 
+ * The software is licensed under the MIT Open Source license (see LICENSE file). + *
+ * + * + *@author Udo Klimaschewski (http://about.me/udo.klimaschewski) + */ +public class Expressions { + + /** + * Definition of PI as a constant, can be used in expressions as variable. + */ + public static final BigDecimal PI = new BigDecimal( + "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"); + public static final BigDecimal e = new BigDecimal( + "2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274"); + public static final BigDecimal phi = new BigDecimal( + "1.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374"); + + /** + * The {@link MathContext} to use for calculations. + */ + private MathContext mc = MathContext.DECIMAL32; + + /** + * The original infix expression. + */ + private String expression = null; + + /** + * The cached RPN (Reverse Polish Notation) of the expression. + */ + private List rpn = null; + + /** + * All defined operators with name and implementation. + */ + private Map operators = new HashMap(); + + /** + * All defined functions with name and implementation. + */ + private Map functions = new HashMap(); + + /** + * All defined variables with name and value. + */ + private Map variables = new HashMap(); + + /** + * What character to use for decimal separators. + */ + private final char decimalSeparator = '.'; + + /** + * What character to use for minus sign (negative values). + */ + private final char minusSign = '-'; + + /** + * The expression evaluators exception class. + */ + public class ExpressionException extends RuntimeException { + private static final long serialVersionUID = 1118142866870779047L; + + public ExpressionException(String message) { + super(message); + } + } + + /** + * Abstract definition of a supported expression function. A function is + * defined by a name, the number of parameters and the actual processing + * implementation. + */ + public abstract class Function { + /** + * Name of this function. + */ + private String name; + /** + * Number of parameters expected for this function. + */ + private int numParams; + + /** + * Creates a new function with given name and parameter count. + * + * @param name + * The name of the function. + * @param numParams + * The number of parameters for this function. + */ + public Function(String name, int numParams) { + this.name = name.toUpperCase(); + this.numParams = numParams; + } + + public String getName() { + return name; + } + + public int getNumParams() { + return numParams; + } + + /** + * Implementation for this function. + * + * @param parameters + * Parameters will be passed by the expression evaluator as a + * {@link List} of {@link BigDecimal} values. + * @return The function must return a new {@link BigDecimal} value as a + * computing result. + */ + public abstract BigDecimal eval(List parameters); + } + + /** + * Abstract definition of a supported operator. An operator is defined by + * its name (pattern), precedence and if it is left- or right associative. + */ + public abstract class Operator { + /** + * This operators name (pattern). + */ + private String oper; + /** + * Operators precedence. + */ + private int precedence; + /** + * Operator is left associative. + */ + private boolean leftAssoc; + + /** + * Creates a new operator. + * + * @param oper + * The operator name (pattern). + * @param precedence + * The operators precedence. + * @param leftAssoc + * true if the operator is left associative, + * else false. + */ + public Operator(String oper, int precedence, boolean leftAssoc) { + this.oper = oper; + this.precedence = precedence; + this.leftAssoc = leftAssoc; + } + + public String getOper() { + return oper; + } + + public int getPrecedence() { + return precedence; + } + + public boolean isLeftAssoc() { + return leftAssoc; + } + + /** + * Implementation for this operator. + * + * @param v1 + * Operand 1. + * @param v2 + * Operand 2. + * @return The result of the operation. + */ + public abstract BigDecimal eval(BigDecimal v1, BigDecimal v2); + } + + /** + * Expression tokenizer that allows to iterate over a {@link String} + * expression token by token. Blank characters will be skipped. + */ + private class Tokenizer implements Iterator { + + /** + * Actual position in expression string. + */ + private int pos = 0; + + /** + * The original input expression. + */ + private String input; + /** + * The previous token or null if none. + */ + private String previousToken; + + /** + * Creates a new tokenizer for an expression. + * + * @param input + * The expression string. + */ + public Tokenizer(String input) { + this.input = input.trim(); + } + + @Override + public boolean hasNext() { + return (pos < input.length()); + } + + /** + * Peek at the next character, without advancing the iterator. + * + * @return The next character or character 0, if at end of string. + */ + private char peekNextChar() { + if (pos < (input.length() - 1)) { + return input.charAt(pos + 1); + } else { + return 0; + } + } + + @Override + public String next() { + StringBuilder token = new StringBuilder(); + if (pos >= input.length()) { + return previousToken = null; + } + char ch = input.charAt(pos); + while (Character.isWhitespace(ch) && pos < input.length()) { + ch = input.charAt(++pos); + } + if (Character.isDigit(ch)) { + while ((Character.isDigit(ch) || ch == decimalSeparator) + && (pos < input.length())) { + token.append(input.charAt(pos++)); + ch = pos == input.length() ? 0 : input.charAt(pos); + } + } else if (ch == minusSign + && Character.isDigit(peekNextChar()) + && ("(".equals(previousToken) || ",".equals(previousToken) + || previousToken == null || operators + .containsKey(previousToken))) { + token.append(minusSign); + pos++; + token.append(next()); + } else if (Character.isLetter(ch) || (ch == '_')) { + while ((Character.isLetter(ch) || Character.isDigit(ch) || (ch == '_')) && (pos < input.length())) { + token.append(input.charAt(pos++)); + ch = pos == input.length() ? 0 : input.charAt(pos); + } + } else if (ch == '(' || ch == ')' || ch == ',') { + token.append(ch); + pos++; + } else { + while (!Character.isLetter(ch) && !Character.isDigit(ch) && ch != '_' + && !Character.isWhitespace(ch) && ch != '(' + && ch != ')' && ch != ',' && (pos < input.length())) { + token.append(input.charAt(pos)); + pos++; + ch = pos == input.length() ? 0 : input.charAt(pos); + if (ch == minusSign) { + break; + } + } + if (!operators.containsKey(token.toString())) { + throw new ExpressionException("Unknown operator '" + token + + "' at position " + (pos - token.length() + 1)); + } + } + return previousToken = token.toString(); + } + + @Override + public void remove() { + throw new ExpressionException("remove() not supported"); + } + + /** + * Get the actual character position in the string. + * + * @return The actual character position. + */ + public int getPos() { + return pos; + } + + } + + /** + * Creates a new expression instance from an expression string. + * + * @param expression + * The expression. E.g. "2.4*sin(3)/(2-4)" or + * "sin(y)>0 & max(z, 3)>3" + */ + public Expressions(String expression) { + this.expression = expression; + addOperator(new Operator("+", 20, true) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.add(v2, mc); + } + }); + addOperator(new Operator("-", 20, true) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.subtract(v2, mc); + } + }); + addOperator(new Operator("*", 30, true) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.multiply(v2, mc); + } + }); + addOperator(new Operator("/", 30, true) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.divide(v2, mc); + } + }); + addOperator(new Operator("%", 30, true) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.remainder(v2, mc); + } + }); + addOperator(new Operator("^", 40, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + /*- + * Thanks to Gene Marin: + * http://stackoverflow.com/questions/3579779/how-to-do-a-fractional-power-on-bigdecimal-in-java + */ + int signOf2 = v2.signum(); + double dn1 = v1.doubleValue(); + v2 = v2.multiply(new BigDecimal(signOf2)); // n2 is now positive + BigDecimal remainderOf2 = v2.remainder(BigDecimal.ONE); + BigDecimal n2IntPart = v2.subtract(remainderOf2); + BigDecimal intPow = v1.pow(n2IntPart.intValueExact(), mc); + BigDecimal doublePow = new BigDecimal(Math.pow(dn1, + remainderOf2.doubleValue())); + + BigDecimal result = intPow.multiply(doublePow, mc); + if (signOf2 == -1) { + result = BigDecimal.ONE.divide(result, mc.getPrecision(), + RoundingMode.HALF_UP); + } + return result; + } + }); + addOperator(new Operator("&&", 4, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + boolean b1 = !v1.equals(BigDecimal.ZERO); + boolean b2 = !v2.equals(BigDecimal.ZERO); + return b1 && b2 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addOperator(new Operator("||", 2, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + boolean b1 = !v1.equals(BigDecimal.ZERO); + boolean b2 = !v2.equals(BigDecimal.ZERO); + return b1 || b2 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addOperator(new Operator(">", 10, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) == 1 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addOperator(new Operator(">=", 10, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) >= 0 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addOperator(new Operator("<", 10, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) == -1 ? BigDecimal.ONE + : BigDecimal.ZERO; + } + }); + + addOperator(new Operator("<=", 10, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) <= 0 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addOperator(new Operator("=", 7, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) == 0 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + addOperator(new Operator("==", 7, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return operators.get("=").eval(v1, v2); + } + }); + + addOperator(new Operator("!=", 7, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return v1.compareTo(v2) != 0 ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + addOperator(new Operator("<>", 7, false) { + @Override + public BigDecimal eval(BigDecimal v1, BigDecimal v2) { + return operators.get("!=").eval(v1, v2); + } + }); + + addFunction(new Function("NOT", 1) { + @Override + public BigDecimal eval(List parameters) { + boolean zero = parameters.get(0).compareTo(BigDecimal.ZERO) == 0; + return zero ? BigDecimal.ONE : BigDecimal.ZERO; + } + }); + + addFunction(new Function("IF", 3) { + @Override + public BigDecimal eval(List parameters) { + boolean isTrue = !parameters.get(0).equals(BigDecimal.ZERO); + return isTrue ? parameters.get(1) : parameters.get(2); + } + }); + + addFunction(new Function("RANDOM", 0) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.random(); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("SIN", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.sin(Math.toRadians(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("COS", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.cos(Math.toRadians(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("TAN", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.tan(Math.toRadians(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("ASIN", 1) { // added by av + @Override + public BigDecimal eval(List parameters) { + double d = Math.toDegrees(Math.asin(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("ACOS", 1) { // added by av + @Override + public BigDecimal eval(List parameters) { + double d = Math.toDegrees(Math.acos(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("ATAN", 1) { // added by av + @Override + public BigDecimal eval(List parameters) { + double d = Math.toDegrees(Math.atan(parameters.get(0) + .doubleValue())); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("SINH", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.sinh(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("COSH", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.cosh(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("TANH", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.tanh(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("RAD", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.toRadians(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("DEG", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.toDegrees(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("MAX", 2) { + @Override + public BigDecimal eval(List parameters) { + BigDecimal v1 = parameters.get(0); + BigDecimal v2 = parameters.get(1); + return v1.compareTo(v2) > 0 ? v1 : v2; + } + }); + addFunction(new Function("MIN", 2) { + @Override + public BigDecimal eval(List parameters) { + BigDecimal v1 = parameters.get(0); + BigDecimal v2 = parameters.get(1); + return v1.compareTo(v2) < 0 ? v1 : v2; + } + }); + addFunction(new Function("ABS", 1) { + @Override + public BigDecimal eval(List parameters) { + return parameters.get(0).abs(mc); + } + }); + addFunction(new Function("LOG", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.log(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("LOG10", 1) { + @Override + public BigDecimal eval(List parameters) { + double d = Math.log10(parameters.get(0).doubleValue()); + return new BigDecimal(d, mc); + } + }); + addFunction(new Function("ROUND", 2) { + @Override + public BigDecimal eval(List parameters) { + BigDecimal toRound = parameters.get(0); + int precision = parameters.get(1).intValue(); + return toRound.setScale(precision, mc.getRoundingMode()); + } + }); + addFunction(new Function("FLOOR", 1) { + @Override + public BigDecimal eval(List parameters) { + BigDecimal toRound = parameters.get(0); + return toRound.setScale(0, RoundingMode.FLOOR); + } + }); + addFunction(new Function("CEILING", 1) { + @Override + public BigDecimal eval(List parameters) { + BigDecimal toRound = parameters.get(0); + return toRound.setScale(0, RoundingMode.CEILING); + } + }); + addFunction(new Function("SQRT", 1) { + @Override + public BigDecimal eval(List parameters) { + /* + * From The Java Programmers Guide To numerical Computing + * (Ronald Mak, 2003) + */ + BigDecimal x = parameters.get(0); + if (x.compareTo(BigDecimal.ZERO) == 0) { + return new BigDecimal(0); + } + if (x.signum() < 0) { + throw new ExpressionException( + "Argument to SQRT() function must not be negative"); + } + BigInteger n = x.movePointRight(mc.getPrecision() << 1) + .toBigInteger(); + + int bits = (n.bitLength() + 1) >> 1; + BigInteger ix = n.shiftRight(bits); + BigInteger ixPrev; + + do { + ixPrev = ix; + ix = ix.add(n.divide(ix)).shiftRight(1); + // Give other threads a chance to work; + Thread.yield(); + } while (ix.compareTo(ixPrev) != 0); + + return new BigDecimal(ix, mc.getPrecision()); + } + }); + + variables.put("PI", PI); + variables.put("e", e); + variables.put("phi",phi); + variables.put("TRUE", BigDecimal.ONE); + variables.put("FALSE", BigDecimal.ZERO); + + } + + /** + * Is the string a number? + * + * @param st + * The string. + * @return true, if the input string is a number. + */ + private boolean isNumber(String st) { + if (st.charAt(0) == minusSign && st.length() == 1) + return false; + for (char ch : st.toCharArray()) { + if (!Character.isDigit(ch) && ch != minusSign + && ch != decimalSeparator) + return false; + } + return true; + } + + /** + * Implementation of the Shunting Yard algorithm to transform an + * infix expression to a RPN expression. + * + * @param expression + * The input expression in infx. + * @return A RPN representation of the expression, with each token as a list + * member. + */ + private List shuntingYard(String expression) { + List outputQueue = new ArrayList(); + Stack stack = new Stack(); + + Tokenizer tokenizer = new Tokenizer(expression); + + String lastFunction = null; + String previousToken = null; + while (tokenizer.hasNext()) { + String token = tokenizer.next(); + if (isNumber(token)) { + outputQueue.add(token); + } else if (variables.containsKey(token)) { + outputQueue.add(token); + } else if (functions.containsKey(token.toUpperCase())) { + stack.push(token); + lastFunction = token; + } else if (Character.isLetter(token.charAt(0))) { + stack.push(token); + } else if (",".equals(token)) { + while (!stack.isEmpty() && !"(".equals(stack.peek())) { + outputQueue.add(stack.pop()); + } + if (stack.isEmpty()) { + throw new ExpressionException("Parse error for function '" + + lastFunction + "'"); + } + } else if (operators.containsKey(token)) { + Operator o1 = operators.get(token); + String token2 = stack.isEmpty() ? null : stack.peek(); + while (operators.containsKey(token2) + && ((o1.isLeftAssoc() && o1.getPrecedence() <= operators + .get(token2).getPrecedence()) || (o1 + .getPrecedence() < operators.get(token2) + .getPrecedence()))) { + outputQueue.add(stack.pop()); + token2 = stack.isEmpty() ? null : stack.peek(); + } + stack.push(token); + } else if ("(".equals(token)) { + if (previousToken != null) { + if (isNumber(previousToken)) { + throw new ExpressionException("Missing operator at character position " + tokenizer.getPos()); + } + } + stack.push(token); + } else if (")".equals(token)) { + while (!stack.isEmpty() && !"(".equals(stack.peek())) { + outputQueue.add(stack.pop()); + } + if (stack.isEmpty()) { + throw new RuntimeException("Mismatched parentheses"); + } + stack.pop(); + if (!stack.isEmpty() + && functions.containsKey(stack.peek().toUpperCase())) { + outputQueue.add(stack.pop()); + } + } + previousToken = token; + } + while (!stack.isEmpty()) { + String element = stack.pop(); + if ("(".equals(element) || ")".equals(element)) { + throw new RuntimeException("Mismatched parentheses"); + } + if (!operators.containsKey(element)) { + throw new RuntimeException("Unknown operator or function: " + + element); + } + outputQueue.add(element); + } + return outputQueue; + } + + /** + * Evaluates the expression. + * + * @return The result of the expression. + */ + public BigDecimal eval() { + + Stack stack = new Stack(); + + for (String token : getRPN()) { + if (operators.containsKey(token)) { + BigDecimal v1 = stack.pop(); + BigDecimal v2 = stack.pop(); + stack.push(operators.get(token).eval(v2, v1)); + } else if (variables.containsKey(token)) { + stack.push(variables.get(token).round(mc)); + } else if (functions.containsKey(token.toUpperCase())) { + Function f = functions.get(token.toUpperCase()); + ArrayList p = new ArrayList( + f.getNumParams()); + for (int i = 0; i < f.numParams; i++) { + p.add(0,stack.pop()); + } + BigDecimal fResult = f.eval(p); + stack.push(fResult); + } else { + stack.push(new BigDecimal(token, mc)); + } + } + return stack.pop().stripTrailingZeros(); + } + + /** + * Sets the precision for expression evaluation. + * + * @param precision + * The new precision. + * + * @return The expression, allows to chain methods. + */ + public Expressions setPrecision(int precision) { + this.mc = new MathContext(precision); + return this; + } + + /** + * Sets the rounding mode for expression evaluation. + * + * @param roundingMode + * The new rounding mode. + * @return The expression, allows to chain methods. + */ + public Expressions setRoundingMode(RoundingMode roundingMode) { + this.mc = new MathContext(mc.getPrecision(), roundingMode); + return this; + } + + /** + * Adds an operator to the list of supported operators. + * + * @param operator + * The operator to add. + * @return The previous operator with that name, or null if + * there was none. + */ + public Operator addOperator(Operator operator) { + return operators.put(operator.getOper(), operator); + } + + /** + * Adds a function to the list of supported functions + * + * @param function + * The function to add. + * @return The previous operator with that name, or null if + * there was none. + */ + public Function addFunction(Function function) { + return functions.put(function.getName(), function); + } + + /** + * Sets a variable value. + * + * @param variable + * The variable name. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions setVariable(String variable, BigDecimal value) { + variables.put(variable, value); + return this; + } + + /** + * Sets a variable value. + * + * @param variable + * The variable to set. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions setVariable(String variable, String value) { + if (isNumber(value)) + variables.put(variable, new BigDecimal(value)); + else { + expression = expression.replaceAll("\\b" + variable + "\\b", "(" + value + ")"); + rpn = null; + } + return this; + } + + /** + * Sets a variable value. + * + * @param variable + * The variable to set. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions with(String variable, BigDecimal value) { + return setVariable(variable, value); + } + + /** + * Sets a variable value. + * + * @param variable + * The variable to set. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions and(String variable, String value) { + return setVariable(variable, value); + } + + /** + * Sets a variable value. + * + * @param variable + * The variable to set. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions and(String variable, BigDecimal value) { + return setVariable(variable, value); + } + + /** + * Sets a variable value. + * + * @param variable + * The variable to set. + * @param value + * The variable value. + * @return The expression, allows to chain methods. + */ + public Expressions with(String variable, String value) { + return setVariable(variable, value); + } + + /** + * Get an iterator for this expression, allows iterating over an expression + * token by token. + * + * @return A new iterator instance for this expression. + */ + public Iterator getExpressionTokenizer() { + return new Tokenizer(this.expression); + } + + /** + * Cached access to the RPN notation of this expression, ensures only one + * calculation of the RPN per expression instance. If no cached instance + * exists, a new one will be created and put to the cache. + * + * @return The cached RPN instance. + */ + private List getRPN() { + if (rpn == null) { + rpn = shuntingYard(this.expression); + } + return rpn; + } + + /** + * Get a string representation of the RPN (Reverse Polish Notation) for this + * expression. + * + * @return A string with the RPN representation for this expression. + */ + public String toRPN() { + String result = new String(); + for (String st : getRPN()) { + result = result.isEmpty() ? result : result + " "; + result += st; + } + return result; + } + +} diff --git a/app/src/main/java/madelyntav/c4q/nyc/calculator/MainActivity.java b/app/src/main/java/madelyntav/c4q/nyc/calculator/MainActivity.java new file mode 100644 index 0000000..6914627 --- /dev/null +++ b/app/src/main/java/madelyntav/c4q/nyc/calculator/MainActivity.java @@ -0,0 +1,334 @@ +package madelyntav.c4q.nyc.calculator; + +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import java.math.BigDecimal; +import java.util.EmptyStackException; + + +public class MainActivity extends ActionBarActivity { + private String ans = "";//saved answer. + private TextView ansview;//screen for the saved answer + private String toBeEvaluated = " ";//used for current state of mathematical expression + private String showOnScreen = " ";//shown on main screen + private TextView calcScreen;//main screen + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + calcScreen = (TextView) findViewById(R.id.calcScreen); + ansview = (TextView) findViewById(R.id.anstxtview); + + if (savedInstanceState != null) { //if there is a saved instance + calcScreen.setText(savedInstanceState.getString("toBeEvaluated")); //set the text in the main screen to be the current expression + toBeEvaluated = savedInstanceState.getString("toBeEvaluated"); //sets toBeEvaluated to what we saved from the previous screen + } + + calcScreen.setText(toBeEvaluated); //sets the main screen text to the current contents in the expression. + } + + public void getButtonText(View v) { + + + Button button = (Button) findViewById(v.getId()); //any button in our layout with this method signature name in its onCall attribute + String buttonText = button.getText().toString(); //stores the contents of that button in a string variable. + + if (toBeEvaluated.equals(null)) { //if there is nothing in our toBeEvaluated var. + showOnScreen = buttonText; + toBeEvaluated += showOnScreen; + } else if (toBeEvaluated != null) { //otherwise, if there is something in toBeEvaluated. + + try { + if (Character.isDigit(toBeEvaluated.charAt(0)) || + Character.isDigit(toBeEvaluated.charAt(toBeEvaluated.length() - 1))) { //if the button contents are digits. + toBeEvaluated += buttonText; //the expression will add those numbers to the expression in the screen. + showOnScreen = toBeEvaluated; //What is shown on the main screen is what is saved in memory for the expression. + calcScreen.setText(showOnScreen); + } else { //if the button pressed is not a numerical digit. It will be added to whatever the current expression contains. + toBeEvaluated += buttonText; + showOnScreen = toBeEvaluated; //what is shown on screen is the current state of the expression. plus what button is pressed. + } + } catch (StringIndexOutOfBoundsException e) { //catching clearend exception. + toBeEvaluated += buttonText; //If clearend (ce) throws an exception the expression will add the number that caused it to the mainscreen. This fixes ce crash. + showOnScreen = toBeEvaluated; //What is shown on the main screen is what is saved in memory for the expression. + calcScreen.setText(showOnScreen); //show that to the user + } + } + calcScreen.setText(showOnScreen.trim()); //show the current state of said var. Whitespace ommited. + } + + public void ce(View v) { + + //backspace. (clearEnd) also ce. This method called by button ce clears the last letter + // currently shown on main screen. + + StringBuffer charDel = new StringBuffer(showOnScreen); + try { + charDel = charDel.deleteCharAt(charDel.length() - 1); //clears last letter of showOnScreen when method is called by button. + showOnScreen = String.valueOf(charDel); //saves the new state of showOnScreen + calcScreen.setText(showOnScreen); //prints it in the main screen + toBeEvaluated = showOnScreen; //saves it as the new expression + } catch (StringIndexOutOfBoundsException e) { //if there is nothing else to delete + calcScreen.setText(calcScreen.getText()); //sets the state of the main screen to an empty state + } + } + + public void getOperators(View v) { + + //This method checks to if the expression is empty first, if it is and an operator is pressed + //this method will add a 0 before the operator to prevent it from crashing, if there is + //already something there and the most recent button pressed was the same operator, nothing + //will be added, if the last thing added to the equation was a number the operator will be + //added. + + Button button = (Button) findViewById(v.getId()); + calcScreen = (TextView) findViewById(R.id.calcScreen); + + char checkIfOperand = button.getText().charAt(0); + + if ((toBeEvaluated == null) || (toBeEvaluated.equals("") || toBeEvaluated.equals(" "))) { + toBeEvaluated += "0" + button.getText().toString(); + showOnScreen = button.getText().toString(); + } else if (toBeEvaluated.charAt(toBeEvaluated.length() - 1) == checkIfOperand) { + toBeEvaluated += ""; + showOnScreen += ""; + } else { + toBeEvaluated += button.getText().toString(); + showOnScreen = button.getText().toString(); + } + calcScreen.setText(toBeEvaluated); + } + + public void factorial(View v) { + try { + int num = Integer.parseInt(calcScreen.getText().toString()); + String result1 = ""; + + for (int i = num; i > 1; i--) { + num--; + if (i > 2) { + result1 += num + "*"; + } else result1 += num; + } + toBeEvaluated += toBeEvaluated + "*" + result1; + showOnScreen = result1; + showOnScreen = toBeEvaluated; + + Expressions expressions = new Expressions(showOnScreen); + BigDecimal result = new BigDecimal(String.valueOf(expressions.eval())); + showOnScreen = result.toPlainString(); + if (showOnScreen.equals("0")){ + calcScreen.setText("Invalid oper."); + } else + calcScreen.setText(showOnScreen); + }catch (NumberFormatException e){ + calcScreen.setText("Only google can factor that"); + } + + } + + + + public void Sohcahtoa(View v) { + + //Code for parenthesis for sin cos and tan + //if nothing is on the screen this method will add the operation plus an opening parens + //if there is something on the screen it will grab whats on the screen and put in in parens + + Button button = (Button) findViewById(v.getId()); + TextView calcS = (TextView) findViewById(R.id.calcScreen); + + if (showOnScreen == null) { + toBeEvaluated = button.getText() + "("; + calcS.setText(toBeEvaluated); + } else if (showOnScreen.equals("") || showOnScreen.equals(" ")) { + showOnScreen.trim(); + toBeEvaluated = button.getText() + "("; + } else + toBeEvaluated = button.getText() + "(" + toBeEvaluated + ")"; + + } + + public void positiveNegativeSwitch(View v) { + + //Checks to see if the value of the first index is a negative and switches it to positive by + // getting rid of the negative sign, otherwise if no sign is there it will convert it to + // negative + + try { + Expressions expressions = new Expressions(toBeEvaluated); + BigDecimal result = new BigDecimal(String.valueOf(expressions.eval())); + toBeEvaluated = result.toPlainString(); + if (toBeEvaluated.charAt(0) != '-' && toBeEvaluated.charAt(0) != '+') { + toBeEvaluated = "-" + toBeEvaluated; + } else if (toBeEvaluated.charAt(0) == '-') { + toBeEvaluated = toBeEvaluated.replace(toBeEvaluated.charAt(0), ' '); + toBeEvaluated = toBeEvaluated.trim(); + } + calcScreen.setText(toBeEvaluated); + + } catch (EmptyStackException e) { + //error handling just in case + calcScreen.setText("Err. Nothing To Calculate"); + } catch (NullPointerException e) { + calcScreen.setText("Err. Invalid input, Clear Screen."); + } catch (RuntimeException r) { + calcScreen.setText("Error"); + } + } + + public void allClear(View v) { + + //clears whole screen. In layout as: (AC) + + toBeEvaluated = " "; + showOnScreen = toBeEvaluated; + calcScreen = (TextView) findViewById(R.id.calcScreen); + calcScreen.setText(toBeEvaluated); + + } + + public void ans(View v) { + + //Saves current state of the expressions' answer to a variable one can reuse + + try { + if ((calcScreen.getText() != "") && ans == "") { + Expressions expressions = new Expressions(calcScreen.getText().toString()); + BigDecimal res = new BigDecimal(String.valueOf(expressions.eval())); + ans = ((res.toPlainString())); + ansview.setText(ans); + } else if (ans != "") { + toBeEvaluated += ans; + calcScreen.setText(toBeEvaluated); + } else if (ans == "" && calcScreen.getText() == "") { + calcScreen.setText(""); + ansview.setText(""); + } + }catch (RuntimeException e){ + calcScreen.setText("Unquantifiable operation, Clear."); + } + } + + public void clearAns(View v) { + + //deletes saved ans variable + + ans = ""; + ansview.setText(ans); + } + + public void absbutton(View v) { + + //returns absolute value of expressions' answer. (it's positive value) + + Expressions expressions = new Expressions(toBeEvaluated); + BigDecimal result = new BigDecimal(String.valueOf(expressions.eval())); + toBeEvaluated = result.toPlainString(); + if (toBeEvaluated.charAt(0) == '-') { + toBeEvaluated = toBeEvaluated.replace(toBeEvaluated.charAt(0), ' '); + toBeEvaluated = toBeEvaluated.trim(); + } + calcScreen.setText(toBeEvaluated); + } + + private void checkParenthesis() { + + //if an open parens is added then P increases by 1, if a closing parenthesis is added + //then p decreases by one. If there are the same number of parens then p will =0, if there is + //one opened that isn't closed then p will be greater than one and this method will add the + //closing parens + + int p = 0; + + for (int i = 0; i < toBeEvaluated.length(); i++) { + if (toBeEvaluated.charAt(i) == '(') { + p++; + } else if (toBeEvaluated.charAt(i) == ')') { + p--; + } + } + if (p > 0) { + toBeEvaluated += ")"; + } + calcScreen.setText(toBeEvaluated); + } + + public void openAndCloseParens(View v) { + + //This method checks how many open and closing parens are currently in the equation and does + //magic to figure out which one is needed at the time and adds that to the equation when the + //button is pressed + + int p = 0; + Button button = (Button) findViewById(v.getId()); + if (toBeEvaluated == null) { + toBeEvaluated = "("; + } + if (toBeEvaluated.equals("") || toBeEvaluated.equals(" ")) { + toBeEvaluated = "("; + } else { + for (int i = 0; i < toBeEvaluated.length(); i++) { + if (toBeEvaluated.charAt(i) == '(') { + p++; + } else if (toBeEvaluated.charAt(i) == ')') { + p--; + } + } + if (p > 0) { + toBeEvaluated += ")"; + + } else { + toBeEvaluated += "("; + } + } + TextView calcS = (TextView) findViewById(R.id.calcScreen); + calcS.setText(toBeEvaluated); + } + + public void evaluateExpression(View v) { + + //equals sign calls on this to calculate and give the final solution to the expression. + + checkParenthesis(); + + try { + Button button = (Button) findViewById(v.getId()); + showOnScreen += button.getText(); + + Expressions expressions = new Expressions(toBeEvaluated); + BigDecimal result = new BigDecimal(String.valueOf(expressions.eval())); //gives result. + + showOnScreen = result.toPlainString(); + + toBeEvaluated += showOnScreen; + + calcScreen.setText((showOnScreen)); + + calcScreen.setText((showOnScreen)); //shows it on screen + toBeEvaluated = showOnScreen; //saves it as current expression. + + } catch (EmptyStackException e) { + calcScreen.setText("Err. Can't compute"); + } catch (NullPointerException e) { + calcScreen.setText("Err. Nothing here."); + } catch (RuntimeException r) { + calcScreen.setText("Infinity"); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + //saves current state of screen in case of device flip. + super.onSaveInstanceState(outState); + outState.putString("toBeEvaluated", calcScreen.getText().toString()); + outState.putString("showOnScreen", showOnScreen); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/customborder.xml b/app/src/main/res/drawable/customborder.xml new file mode 100644 index 0000000..ea58e07 --- /dev/null +++ b/app/src/main/res/drawable/customborder.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/customborderpurple.xml b/app/src/main/res/drawable/customborderpurple.xml new file mode 100644 index 0000000..fe42f2c --- /dev/null +++ b/app/src/main/res/drawable/customborderpurple.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/horizontalphi.jpg b/app/src/main/res/drawable/horizontalphi.jpg new file mode 100644 index 0000000..92798c6 Binary files /dev/null and b/app/src/main/res/drawable/horizontalphi.jpg differ diff --git a/app/src/main/res/drawable/verticalphi.jpg b/app/src/main/res/drawable/verticalphi.jpg new file mode 100644 index 0000000..7d2280f Binary files /dev/null and b/app/src/main/res/drawable/verticalphi.jpg differ diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml new file mode 100644 index 0000000..e4f828f --- /dev/null +++ b/app/src/main/res/layout-land/activity_main.xml @@ -0,0 +1,509 @@ + + + + +