var activity
This commit is contained in:
parent
f2d260706e
commit
8b69516aa0
@ -37,7 +37,7 @@
|
|||||||
<EditText a:id="@+id/var_edit_value"
|
<EditText a:id="@+id/var_edit_value"
|
||||||
a:layout_width="match_parent"
|
a:layout_width="match_parent"
|
||||||
a:layout_height="wrap_content"
|
a:layout_height="wrap_content"
|
||||||
a:inputType="number"
|
a:inputType="numberDecimal"
|
||||||
a:textSize="20dp">
|
a:textSize="20dp">
|
||||||
</EditText>
|
</EditText>
|
||||||
|
|
||||||
|
@ -26,7 +26,10 @@ import org.solovyev.util.math.Complex;
|
|||||||
public class CalculatorModel {
|
public class CalculatorModel {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Interpreter interpreter;
|
private Interpreter interpreter;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final Object interpreterMonitor = new Object();
|
||||||
|
|
||||||
private int numberOfFractionDigits = 5;
|
private int numberOfFractionDigits = 5;
|
||||||
|
|
||||||
@ -38,30 +41,41 @@ public class CalculatorModel {
|
|||||||
|
|
||||||
private static CalculatorModel instance;
|
private static CalculatorModel instance;
|
||||||
|
|
||||||
private CalculatorModel(@Nullable Context context) throws EvalError {
|
private CalculatorModel(@Nullable Context context) {
|
||||||
load(context);
|
load(context);
|
||||||
|
|
||||||
interpreter = new Interpreter();
|
reset();
|
||||||
interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
synchronized (interpreterMonitor) {
|
||||||
|
try {
|
||||||
|
interpreter = new Interpreter();
|
||||||
|
interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
||||||
|
|
||||||
|
/*for (Var var : varsRegister.getVars()) {
|
||||||
|
if (!var.isSystem()) {
|
||||||
|
exec(var.getName() + "=" + var.getValue() + ";");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
} catch (EvalError evalError) {
|
||||||
|
throw new RuntimeException(evalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException {
|
public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException {
|
||||||
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
/*
|
|
||||||
for (Var var : varsRegister.getVars()) {
|
|
||||||
if (!var.isSystem()) {
|
|
||||||
sb.append(var.getName()).append("=").append(var.getValue()).append(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
sb.append(preprocessor.process(expression));
|
sb.append(preprocessor.process(expression));
|
||||||
|
|
||||||
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
|
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
|
||||||
|
|
||||||
Object evaluationObject = interpreter.eval(ToJsclPreprocessor.wrap(operation, sb.toString()));
|
final Object evaluationObject;
|
||||||
|
synchronized (interpreterMonitor) {
|
||||||
|
evaluationObject = interpreter.eval(ToJsclPreprocessor.wrap(operation, sb.toString()));
|
||||||
|
}
|
||||||
String result = String.valueOf(evaluationObject).trim();
|
String result = String.valueOf(evaluationObject).trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -120,7 +134,7 @@ public class CalculatorModel {
|
|||||||
return MathUtils.round(dResult, numberOfFractionDigits);
|
return MathUtils.round(dResult, numberOfFractionDigits);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void load(@Nullable Context context) {
|
public synchronized void load(@Nullable Context context) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
@ -154,7 +168,7 @@ public class CalculatorModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CalculatorModel getInstance() {
|
public static CalculatorModel getInstance() {
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
throw new RuntimeException("CalculatorModel must be instantiated!");
|
throw new RuntimeException("CalculatorModel must be instantiated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,8 +179,34 @@ public class CalculatorModel {
|
|||||||
return instance != null;
|
return instance != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void exec(String str) throws EvalError {
|
||||||
|
interpreter.eval(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String eval(String str) throws EvalError {
|
||||||
|
return interpreter.eval(commands(str)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public VarsRegister getVarsRegister() {
|
public VarsRegister getVarsRegister() {
|
||||||
return varsRegister;
|
return varsRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String commands(String str) {
|
||||||
|
return commands(str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String commands(String str, boolean found) {
|
||||||
|
for (int i = 0; i < cmds.length; i++) {
|
||||||
|
int n = str.length() - cmds[i].length() - 1;
|
||||||
|
if (n >= 0 && (" " + cmds[i].toLowerCase()).equals(str.substring(n)))
|
||||||
|
return commands(str.substring(0, n), true) + "." + cmds[i] + "()";
|
||||||
|
}
|
||||||
|
str = str.replaceAll("\n", "");
|
||||||
|
return found ? "jscl.math.Expression.valueOf(\"" + str + "\")" : str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"};
|
||||||
}
|
}
|
||||||
|
@ -177,10 +177,10 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show();
|
Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show();
|
||||||
createEditVariableDialog(editedInstance, name, value, description);
|
createEditVariableDialog(editedInstance, name, value, description);
|
||||||
} else {
|
} else {
|
||||||
if (editedInstance != null && !editedInstance.getName().equals(name)) {
|
if ( editedInstance == null ) {
|
||||||
varsRegister.addVar(editedInstance.getName(), varBuilder);
|
|
||||||
} else {
|
|
||||||
CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder));
|
CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder));
|
||||||
|
} else {
|
||||||
|
varsRegister.addVar(editedInstance.getName(), varBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
varsRegister.save(CalculatorVarsActivity.this);
|
varsRegister.save(CalculatorVarsActivity.this);
|
||||||
|
@ -192,7 +192,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
|||||||
@Override
|
@Override
|
||||||
public void doOperation(@NotNull EditText editor) {
|
public void doOperation(@NotNull EditText editor) {
|
||||||
|
|
||||||
final MathEntityType type = MathEntityType.getType(text);
|
final MathEntityType type = MathEntityType.getType(text, 0);
|
||||||
|
|
||||||
int cursorPositionOffset = 0;
|
int cursorPositionOffset = 0;
|
||||||
final StringBuilder textToBeInserted = new StringBuilder(text);
|
final StringBuilder textToBeInserted = new StringBuilder(text);
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||||
|
* For more information, please, contact se.solovyev@gmail.com
|
||||||
|
* or visit http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/3/11
|
||||||
|
* Time: 12:54 AM
|
||||||
|
*/
|
||||||
|
public class CharacterAtPositionFinder implements Finder<Character> {
|
||||||
|
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final String targetString;
|
||||||
|
|
||||||
|
public CharacterAtPositionFinder(@NotNull String targetString, int i) {
|
||||||
|
this.targetString = targetString;
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFound(@Nullable Character s) {
|
||||||
|
return s != null && s.equals(targetString.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setI(int i) {
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||||
|
* For more information, please, contact se.solovyev@gmail.com
|
||||||
|
* or visit http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/3/11
|
||||||
|
* Time: 12:49 AM
|
||||||
|
*/
|
||||||
|
public class StartsWithFinder implements Finder<String> {
|
||||||
|
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final String targetString;
|
||||||
|
|
||||||
|
public StartsWithFinder(@NotNull String targetString, int i) {
|
||||||
|
this.targetString = targetString;
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFound(@Nullable String s) {
|
||||||
|
return targetString.startsWith(s, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setI(int i) {
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
}
|
@ -19,46 +19,88 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public String process(@NotNull String s) {
|
public String process(@NotNull String s) {
|
||||||
|
|
||||||
|
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
boolean constantBefore = false;
|
||||||
for (int i = 0; i < s.length(); i++) {
|
for (int i = 0; i < s.length(); i++) {
|
||||||
char ch = s.charAt(i);
|
char ch = s.charAt(i);
|
||||||
if ( MathEntityType.getType(ch) == MathEntityType.postfix_function ) {
|
startsWithFinder.setI(i);
|
||||||
int start = getPostfixFunctionStart(s, i - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s);
|
checkMultiplicationSignBeforeFunction(sb, s, i, constantBefore);
|
||||||
for (int i = 0; i < s.length(); i++) {
|
constantBefore = false;
|
||||||
char ch = s.charAt(i);
|
|
||||||
|
|
||||||
checkMultiplicationSignBeforeFunction(sb, s, i);
|
|
||||||
|
|
||||||
if (MathEntityType.openGroupSymbols.contains(ch)) {
|
if (MathEntityType.openGroupSymbols.contains(ch)) {
|
||||||
sb.append('(');
|
sb.append('(');
|
||||||
} else if (MathEntityType.closeGroupSymbols.contains(ch)) {
|
} else if (MathEntityType.closeGroupSymbols.contains(ch)) {
|
||||||
sb.append(')');
|
sb.append(')');
|
||||||
} else if (ch == 'π') {
|
|
||||||
sb.append("pi");
|
|
||||||
} else if (ch == '×' || ch == '∙') {
|
} else if (ch == '×' || ch == '∙') {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else {
|
} else {
|
||||||
startsWithFinder.setI(i);
|
String entity = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder);
|
||||||
final String function = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder);
|
if (entity == null) {
|
||||||
if (function != null) {
|
entity = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder);
|
||||||
sb.append(toJsclFunction(function));
|
if (entity == null) {
|
||||||
i += function.length() - 1;
|
sb.append(ch);
|
||||||
} else if (ch == 'e') {
|
} else {
|
||||||
sb.append("exp(1)");
|
sb.append(entity);
|
||||||
} else if (ch == 'i') {
|
i += entity.length() - 1;
|
||||||
sb.append("sqrt(-1)");
|
constantBefore = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sb.append(ch);
|
sb.append(toJsclFunction(entity));
|
||||||
|
i += entity.length() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return replaceVariables(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceVariables(@NotNull final String s) {
|
||||||
|
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||||
|
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
startsWithFinder.setI(i);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
String functionName = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder);
|
||||||
|
if (functionName == null) {
|
||||||
|
String varName = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder);
|
||||||
|
if (varName != null) {
|
||||||
|
final Var var = CalculatorModel.getInstance().getVarsRegister().getVar(varName);
|
||||||
|
if (var != null) {
|
||||||
|
result.append(var.getValue());
|
||||||
|
offset = varName.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.append(functionName);
|
||||||
|
offset = functionName.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (offset == 0) {
|
||||||
|
result.append(s.charAt(i));
|
||||||
|
} else {
|
||||||
|
i += offset - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) {
|
||||||
|
for (Var var : CalculatorModel.getInstance().getVarsRegister().getVars()) {
|
||||||
|
if (!var.isSystem()) {
|
||||||
|
if (s.startsWith(var.getName(), i)) {
|
||||||
|
if (CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder) == null) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPostfixFunctionStart(@NotNull String s, int position) {
|
public int getPostfixFunctionStart(@NotNull String s, int position) {
|
||||||
@ -66,17 +108,16 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
|
|
||||||
int numberOfOpenGroups = 0;
|
int numberOfOpenGroups = 0;
|
||||||
int result = position;
|
int result = position;
|
||||||
for ( ; result >= 0; result-- ) {
|
for (; result >= 0; result--) {
|
||||||
char ch = s.charAt(result);
|
|
||||||
|
|
||||||
final MathEntityType mathEntityType = MathEntityType.getType(ch);
|
final MathEntityType mathEntityType = MathEntityType.getType(s, result);
|
||||||
|
|
||||||
if ( mathEntityType != null ) {
|
if (mathEntityType != null) {
|
||||||
if ( CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot) ) {
|
if (CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot)) {
|
||||||
// continue
|
// continue
|
||||||
} else if (MathEntityType.closeGroupSymbols.contains(ch)) {
|
} else if (MathEntityType.closeGroupSymbols.contains(s.charAt(result))) {
|
||||||
numberOfOpenGroups++;
|
numberOfOpenGroups++;
|
||||||
} else if (MathEntityType.openGroupSymbols.contains(ch)) {
|
} else if (MathEntityType.openGroupSymbols.contains(s.charAt(result))) {
|
||||||
numberOfOpenGroups--;
|
numberOfOpenGroups--;
|
||||||
} else {
|
} else {
|
||||||
if (stop(s, numberOfOpenGroups, result)) break;
|
if (stop(s, numberOfOpenGroups, result)) break;
|
||||||
@ -90,12 +131,12 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean stop(String s, int numberOfOpenGroups, int i) {
|
private boolean stop(String s, int numberOfOpenGroups, int i) {
|
||||||
if ( numberOfOpenGroups == 0 ) {
|
if (numberOfOpenGroups == 0) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
||||||
endsWithFinder.setI(i+1);
|
endsWithFinder.setI(i + 1);
|
||||||
if ( !CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder) ) {
|
if (!CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder)) {
|
||||||
MathEntityType type = MathEntityType.getType(s.charAt(i));
|
MathEntityType type = MathEntityType.getType(s, i);
|
||||||
if (type != null && type != MathEntityType.constant) {
|
if (type != null && type != MathEntityType.constant) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -123,27 +164,6 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class StartsWithFinder implements Finder<String> {
|
|
||||||
|
|
||||||
private int i;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final String targetString;
|
|
||||||
|
|
||||||
private StartsWithFinder(@NotNull String targetString) {
|
|
||||||
this.targetString = targetString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFound(@Nullable String s) {
|
|
||||||
return targetString.startsWith(s, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setI(int i) {
|
|
||||||
this.i = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class EndsWithFinder implements Finder<String> {
|
private static class EndsWithFinder implements Finder<String> {
|
||||||
|
|
||||||
private int i;
|
private int i;
|
||||||
@ -165,25 +185,25 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, @NotNull String s, int i) {
|
private static void checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, @NotNull String s, int i, boolean constantBefore) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
// get character before function
|
// get character before function
|
||||||
char chBefore = s.charAt(i - 1);
|
char chBefore = s.charAt(i - 1);
|
||||||
char ch = s.charAt(i);
|
char ch = s.charAt(i);
|
||||||
|
|
||||||
final MathEntityType mathTypeBefore = MathEntityType.getType(String.valueOf(chBefore));
|
final MathEntityType mathTypeBefore = MathEntityType.getType(String.valueOf(chBefore));
|
||||||
final MathEntityType mathType = MathEntityType.getType(String.valueOf(ch));
|
final MathEntityType mathType = MathEntityType.getType(s, i);
|
||||||
|
|
||||||
if (mathTypeBefore != MathEntityType.binary_operation &&
|
if (constantBefore || (mathTypeBefore != MathEntityType.binary_operation &&
|
||||||
mathTypeBefore != MathEntityType.unary_operation &&
|
mathTypeBefore != MathEntityType.unary_operation &&
|
||||||
mathTypeBefore != MathEntityType.function &&
|
mathTypeBefore != MathEntityType.function &&
|
||||||
!MathEntityType.openGroupSymbols.contains(chBefore)) {
|
!MathEntityType.openGroupSymbols.contains(chBefore))) {
|
||||||
|
|
||||||
if (mathType == MathEntityType.constant) {
|
if (mathType == MathEntityType.constant) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else if (MathEntityType.openGroupSymbols.contains(ch) && mathTypeBefore != null) {
|
} else if (MathEntityType.openGroupSymbols.contains(ch) && mathTypeBefore != null) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else if (mathType == MathEntityType.digit && mathTypeBefore != MathEntityType.digit && mathTypeBefore != MathEntityType.dot) {
|
} else if (mathType == MathEntityType.digit && ((mathTypeBefore != MathEntityType.digit && mathTypeBefore != MathEntityType.dot) || constantBefore) ) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else {
|
} else {
|
||||||
for (String function : MathEntityType.prefixFunctions) {
|
for (String function : MathEntityType.prefixFunctions) {
|
||||||
|
@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.simpleframework.xml.Serializer;
|
import org.simpleframework.xml.Serializer;
|
||||||
import org.simpleframework.xml.core.Persister;
|
import org.simpleframework.xml.core.Persister;
|
||||||
|
import org.solovyev.android.calculator.math.MathEntityComparator;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathEntityType;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
@ -46,20 +47,34 @@ public class VarsRegister {
|
|||||||
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
|
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
|
||||||
final Var var = builder.create();
|
final Var var = builder.create();
|
||||||
|
|
||||||
final Var varFromRegister = getVar(name == null ? var.getName() : name);
|
Var varFromRegister = getVar(name == null ? var.getName() : name);
|
||||||
if (varFromRegister == null) {
|
if (varFromRegister == null) {
|
||||||
|
varFromRegister = var;
|
||||||
vars.add(var);
|
vars.add(var);
|
||||||
} else {
|
} else {
|
||||||
varFromRegister.copy(var);
|
varFromRegister.copy(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
return var;
|
return varFromRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove (@NotNull Var var) {
|
public void remove (@NotNull Var var) {
|
||||||
this.vars.remove(var);
|
this.vars.remove(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<String> getVarNames () {
|
||||||
|
final List<String> result = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (Var var : vars) {
|
||||||
|
result.add(var.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(result, new MathEntityComparator());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Var getVar(@NotNull final String name) {
|
public Var getVar(@NotNull final String name) {
|
||||||
return CollectionsUtils.get(vars, new Finder<Var>() {
|
return CollectionsUtils.get(vars, new Finder<Var>() {
|
||||||
@ -121,7 +136,7 @@ public class VarsRegister {
|
|||||||
} else if (systemVarName.equals("π")) {
|
} else if (systemVarName.equals("π")) {
|
||||||
systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create();
|
systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create();
|
||||||
} else if (systemVarName.equals("i")) {
|
} else if (systemVarName.equals("i")) {
|
||||||
systemVar = new Var.Builder(systemVarName, "√(-1)").setSystem(true).create();
|
systemVar = new Var.Builder(systemVarName, "sqrt(-1)").setSystem(true).create();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(systemVarName + " is not supported yet!");
|
throw new IllegalArgumentException(systemVarName + " is not supported yet!");
|
||||||
}
|
}
|
||||||
@ -157,7 +172,7 @@ public class VarsRegister {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.putString(context.getString(R.string.p_calc_vars),sw.toString());
|
editor.putString(context.getString(R.string.p_calc_vars), sw.toString());
|
||||||
|
|
||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
@ -5,41 +5,48 @@
|
|||||||
|
|
||||||
package org.solovyev.android.calculator.math;
|
package org.solovyev.android.calculator.math;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NonNls;
|
import java.util.*;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: serso
|
* User: serso
|
||||||
* Date: 9/17/11
|
* Date: 9/17/11
|
||||||
* Time: 10:01 PM
|
* Time: 10:01 PM
|
||||||
*/
|
*/
|
||||||
public interface Functions {
|
public class Functions {
|
||||||
|
|
||||||
String SIN = "sin";
|
public final static String SIN = "sin";
|
||||||
String SINH = "sinh";
|
public final static String SINH = "sinh";
|
||||||
String ASIN = "asin";
|
public final static String ASIN = "asin";
|
||||||
String ASINH = "asinh";
|
public final static String ASINH = "asinh";
|
||||||
String COS = "cos";
|
public final static String COS = "cos";
|
||||||
String COSH = "cosh";
|
public final static String COSH = "cosh";
|
||||||
String ACOS = "acos";
|
public final static String ACOS = "acos";
|
||||||
String ACOSH = "acosh";
|
public final static String ACOSH = "acosh";
|
||||||
String TAN = "tan";
|
public final static String TAN = "tan";
|
||||||
String TANH = "tanh";
|
public final static String TANH = "tanh";
|
||||||
String ATAN = "atan";
|
public final static String ATAN = "atan";
|
||||||
String ATANH = "atanh";
|
public final static String ATANH = "atanh";
|
||||||
String LOG = "log";
|
public final static String LOG = "log";
|
||||||
String LN = "ln";
|
public final static String LN = "ln";
|
||||||
String MOD = "mod";
|
public final static String MOD = "mod";
|
||||||
String EXP = "exp";
|
public final static String EXP = "exp";
|
||||||
String SQRT_SIGN = "√";
|
public final static String SQRT_SIGN = "√";
|
||||||
String SQRT = "sqrt";
|
public final static String SQRT = "sqrt";
|
||||||
|
|
||||||
public static final List<String> allPrefix = Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP);
|
public static final List<String> allPrefix;
|
||||||
|
|
||||||
Character FACT = '!';
|
static {
|
||||||
Character DEGREE = '°';
|
final List<String> functions = new ArrayList<String>(Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP));
|
||||||
|
Collections.sort(functions, new MathEntityComparator());
|
||||||
|
allPrefix = functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static Character FACT = '!';
|
||||||
|
public final static Character DEGREE = '°';
|
||||||
|
|
||||||
public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
|
public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
|
||||||
|
|
||||||
|
private Functions() {
|
||||||
|
throw new AssertionError("Not allowed!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||||
|
* For more information, please, contact se.solovyev@gmail.com
|
||||||
|
* or visit http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator.math;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/3/11
|
||||||
|
* Time: 12:30 AM
|
||||||
|
*/
|
||||||
|
public class MathEntityComparator implements Comparator<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(String s, String s1) {
|
||||||
|
return s1.length() - s.length();
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ package org.solovyev.android.calculator.math;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.CalculatorModel;
|
import org.solovyev.android.calculator.CalculatorModel;
|
||||||
|
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
||||||
|
import org.solovyev.android.calculator.StartsWithFinder;
|
||||||
import org.solovyev.android.calculator.Var;
|
import org.solovyev.android.calculator.Var;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
@ -22,20 +24,21 @@ public enum MathEntityType {
|
|||||||
digit,
|
digit,
|
||||||
constant,
|
constant,
|
||||||
dot,
|
dot,
|
||||||
function,
|
function,
|
||||||
postfix_function,
|
postfix_function,
|
||||||
unary_operation,
|
unary_operation,
|
||||||
binary_operation,
|
binary_operation,
|
||||||
group_symbols,
|
group_symbols,
|
||||||
group_symbol;
|
group_symbol;
|
||||||
|
|
||||||
public static final List<String> constants = Arrays.asList("e", "π", "i");
|
public static final List<String> constants = Arrays.asList("e", "π", "i");
|
||||||
|
|
||||||
|
public static final List<String> digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
|
||||||
public static final List<Character> dots = Arrays.asList('.');
|
public static final List<Character> dots = Arrays.asList('.');
|
||||||
|
|
||||||
public static final List<Character> unaryOperations = Arrays.asList('-', '=', '!');
|
public static final List<Character> unaryOperations = Arrays.asList('-', '=', '!');
|
||||||
|
|
||||||
public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^' );
|
public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^');
|
||||||
|
|
||||||
public static final List<String> prefixFunctions = Functions.allPrefix;
|
public static final List<String> prefixFunctions = Functions.allPrefix;
|
||||||
|
|
||||||
@ -48,6 +51,7 @@ public enum MathEntityType {
|
|||||||
public static final List<Character> closeGroupSymbols = Arrays.asList(']', ')', '}');
|
public static final List<Character> closeGroupSymbols = Arrays.asList(']', ')', '}');
|
||||||
|
|
||||||
public static final List<Character> singleGroupSymbols;
|
public static final List<Character> singleGroupSymbols;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final List<Character> list = new ArrayList<Character>();
|
final List<Character> list = new ArrayList<Character>();
|
||||||
list.addAll(openGroupSymbols);
|
list.addAll(openGroupSymbols);
|
||||||
@ -56,24 +60,24 @@ public enum MathEntityType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static MathEntityType getType( @NotNull String s ) {
|
public static MathEntityType getType(@NotNull String s) {
|
||||||
MathEntityType result = null;
|
MathEntityType result = null;
|
||||||
|
|
||||||
if ( s.length() == 1 ) {
|
if (s.length() == 1) {
|
||||||
result = getType(s.charAt(0));
|
result = getType(s.charAt(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( result == null ) {
|
if (result == null) {
|
||||||
if ( isConstant(s) ) {
|
if (prefixFunctions.contains(s)) {
|
||||||
result = MathEntityType.constant;
|
|
||||||
} else if ( prefixFunctions.contains(s) ) {
|
|
||||||
result = MathEntityType.function;
|
result = MathEntityType.function;
|
||||||
} else if ( groupSymbols.contains(s) ) {
|
} else if (isConstant(s)) {
|
||||||
|
result = MathEntityType.constant;
|
||||||
|
} else if (groupSymbols.contains(s)) {
|
||||||
result = MathEntityType.group_symbols;
|
result = MathEntityType.group_symbols;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,19 +85,19 @@ public enum MathEntityType {
|
|||||||
public static MathEntityType getType(final char ch) {
|
public static MathEntityType getType(final char ch) {
|
||||||
MathEntityType result = null;
|
MathEntityType result = null;
|
||||||
|
|
||||||
if ( Character.isDigit(ch) ) {
|
if (Character.isDigit(ch)) {
|
||||||
result = MathEntityType.digit;
|
result = MathEntityType.digit;
|
||||||
} else if ( postfixFunctions.contains(ch) ) {
|
} else if (postfixFunctions.contains(ch)) {
|
||||||
result = MathEntityType.postfix_function;
|
result = MathEntityType.postfix_function;
|
||||||
} else if ( unaryOperations.contains(ch) ) {
|
} else if (unaryOperations.contains(ch)) {
|
||||||
result = MathEntityType.unary_operation;
|
result = MathEntityType.unary_operation;
|
||||||
} else if ( binaryOperations.contains(ch) ) {
|
} else if (binaryOperations.contains(ch)) {
|
||||||
result = MathEntityType.binary_operation;
|
result = MathEntityType.binary_operation;
|
||||||
} else if ( singleGroupSymbols.contains(ch) ) {
|
} else if (singleGroupSymbols.contains(ch)) {
|
||||||
result = MathEntityType.group_symbol;
|
result = MathEntityType.group_symbol;
|
||||||
} else if (isConstant(ch)) {
|
} else if (isConstant(ch)) {
|
||||||
result = MathEntityType.constant;
|
result = MathEntityType.constant;
|
||||||
} else if ( dots.contains(ch) ) {
|
} else if (dots.contains(ch)) {
|
||||||
result = MathEntityType.dot;
|
result = MathEntityType.dot;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -113,4 +117,46 @@ public enum MathEntityType {
|
|||||||
}
|
}
|
||||||
}) != null;
|
}) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MathEntityType getType(String s, int i) {
|
||||||
|
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, i);
|
||||||
|
final CharacterAtPositionFinder characterStartWithFinder = new CharacterAtPositionFinder(s, i);
|
||||||
|
|
||||||
|
return getType(startsWithFinder, characterStartWithFinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static MathEntityType getType(@NotNull Finder<String> finder, @NotNull CharacterAtPositionFinder characterStartWithFinder) {
|
||||||
|
MathEntityType result = null;
|
||||||
|
|
||||||
|
if (contains(digits, finder)) {
|
||||||
|
result = MathEntityType.digit;
|
||||||
|
} else if (contains(postfixFunctions, characterStartWithFinder)) {
|
||||||
|
result = MathEntityType.postfix_function;
|
||||||
|
} else if (contains(unaryOperations, characterStartWithFinder)) {
|
||||||
|
result = MathEntityType.unary_operation;
|
||||||
|
} else if (contains(binaryOperations, characterStartWithFinder)) {
|
||||||
|
result = MathEntityType.binary_operation;
|
||||||
|
} else if (contains(groupSymbols, finder)) {
|
||||||
|
result = MathEntityType.group_symbols;
|
||||||
|
} else if (contains(singleGroupSymbols, characterStartWithFinder)) {
|
||||||
|
result = MathEntityType.group_symbol;
|
||||||
|
} else if (contains(prefixFunctions, finder)) {
|
||||||
|
result = MathEntityType.function;
|
||||||
|
} else if (contains(CalculatorModel.getInstance().getVarsRegister().getVarNames(), finder)) {
|
||||||
|
result = MathEntityType.constant;
|
||||||
|
} else if (contains(dots, characterStartWithFinder)) {
|
||||||
|
result = MathEntityType.dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contains(@NotNull List<String> list, @NotNull final Finder<String> startsWithFinder) {
|
||||||
|
return CollectionsUtils.get(list, startsWithFinder) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contains(@NotNull List<Character> list, @NotNull final CharacterAtPositionFinder atPositionFinder) {
|
||||||
|
return CollectionsUtils.get(list, atPositionFinder) != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import bsh.EvalError;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -47,6 +47,25 @@ public class CalculatorModelTest {
|
|||||||
Assert.assertEquals("-3.41007+3.41007i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)"));
|
Assert.assertEquals("-3.41007+3.41007i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)"));
|
||||||
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)"));
|
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)"));
|
||||||
|
|
||||||
|
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("si", 5d));
|
||||||
|
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||||
|
try {
|
||||||
|
cm.evaluate(JsclOperation.numeric, "sin");
|
||||||
|
Assert.fail();
|
||||||
|
} catch (EvalError e) {
|
||||||
|
}
|
||||||
|
Assert.assertEquals("-0.95892", cm.evaluate(JsclOperation.numeric, "sin(5)"));
|
||||||
|
Assert.assertEquals("-4.79462", cm.evaluate(JsclOperation.numeric, "sin(5)si"));
|
||||||
|
Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "sisin(5)si"));
|
||||||
|
Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "si*sin(5)si"));
|
||||||
|
Assert.assertEquals("-3.30879", cm.evaluate(JsclOperation.numeric, "sisin(5si)si"));
|
||||||
|
|
||||||
|
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("s", 1d));
|
||||||
|
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||||
|
|
||||||
|
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
|
||||||
|
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
|
||||||
|
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user