complex number support added

This commit is contained in:
serso 2011-09-18 00:08:04 +04:00
parent c99dd57e60
commit 898ac936df
16 changed files with 458 additions and 143 deletions

22
pom.xml
View File

@ -15,8 +15,24 @@
<additionalLibs>${basedir}/src/misc/lib</additionalLibs>
</properties>
<repositories>
<repository>
<id>congrace.de</id>
<name>releases</name>
<url>http://nexus.congrace.de/nexus/content/repositories/releases/</url>
<layout>default</layout>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.solovyev</groupId>
<artifactId>common</artifactId>
@ -37,6 +53,12 @@
<systemPath>${additionalLibs}/jscl.jar</systemPath>
</dependency>
<dependency>
<groupId>de.congrace</groupId>
<artifactId>exp4j</artifactId>
<version>0.2.8</version>
</dependency>
<dependency>
<groupId>com.intellij</groupId>
<artifactId>annotations</artifactId>

View File

@ -38,7 +38,7 @@
style="@style/control_button_style"
a:onClick="eraseButtonClickHandler"/>
<TextView
<org.solovyev.android.calculator.CalculatorDisplay
a:id="@+id/resultEditText"
style="@style/display_style"
a:gravity="right|top"
@ -75,8 +75,8 @@
calc:textDown="acos" style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/threeDigitButton" a:text="3" calc:textUp="tg"
calc:textDown="atg" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/threeDigitButton" a:text="3" calc:textUp="tan"
calc:textDown="atan" style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/multiplicationButton" a:text="×"
@ -106,20 +106,22 @@
<org.solovyev.android.view.DirectionDragButton a:id="@+id/fourDigitButton"
a:text="4"
calc:textUp=""
calc:textDown=""
calc:textUp="sinh"
calc:textDown="asinh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/fiveDigitButton"
a:text="5"
calc:textUp="ln"
calc:textUp="cosh"
calc:textDown="acosh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sixDigitButton" a:text="6"
calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
calc:textUp="tanh"
calc:textDown="atanh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/plusButton" a:text="+"
@ -147,12 +149,16 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sevenDigitButton" a:text="7" calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sevenDigitButton" a:text="7"
calc:textUp="i"
calc:textDown=""
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/eightDigitButton" a:text="8" calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/eightDigitButton" a:text="8"
calc:textUp="ln"
calc:textDown=""
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/nineDigitButton" a:text="9"

View File

@ -33,7 +33,7 @@
style="@style/control_button_style"
a:onClick="numericButtonClickHandler"/>
<TextView
<org.solovyev.android.calculator.CalculatorDisplay
a:id="@+id/resultEditText"
style="@style/display_style"
a:gravity="right|top"
@ -56,8 +56,8 @@
calc:textDown="acos" style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/threeDigitButton" a:text="3" calc:textUp="tg"
calc:textDown="atg" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/threeDigitButton" a:text="3" calc:textUp="tan"
calc:textDown="atan" style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/multiplicationButton" a:text="×"
@ -76,20 +76,22 @@
<org.solovyev.android.view.DirectionDragButton a:id="@+id/fourDigitButton"
a:text="4"
calc:textUp=""
calc:textDown=""
calc:textUp="sinh"
calc:textDown="asinh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/fiveDigitButton"
a:text="5"
calc:textUp="ln"
calc:textUp="cosh"
calc:textDown="acosh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sixDigitButton" a:text="6"
calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
calc:textUp="tanh"
calc:textDown="atanh"
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/divisionButton" a:text="/"
@ -106,12 +108,16 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sevenDigitButton" a:text="7" calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/sevenDigitButton" a:text="7"
calc:textUp="i"
calc:textDown=""
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/eightDigitButton" a:text="8" calc:textUp=""
calc:textDown="" style="@style/digit_button_style"
<org.solovyev.android.view.DirectionDragButton a:id="@+id/eightDigitButton" a:text="8"
calc:textUp="ln"
calc:textDown=""
style="@style/digit_button_style"
a:onClick="digitButtonClickHandler"/>
<org.solovyev.android.view.DirectionDragButton a:id="@+id/nineDigitButton" a:text="9"

View File

@ -2,7 +2,8 @@
<resources>
<string name="c_app_name">Calculator</string>
<string name="c_app_settings">Calculator</string>
<string name="syntax_error">Syntax error</string>
<string name="c_syntax_error">Syntax error</string>
<string name="c_result_copied">Result copied to clipboard!</string>
<string name="c_settings">Settings</string>
<string name="c_help">Help</string>
<string name="c_prefs_main_category">Main settings</string>

View File

@ -27,7 +27,7 @@
</style>
<style name="display_style">
<item name="android:textSize">30dp</item>
<item name="android:textSize">25dp</item>
<item name="android:background">#000000</item>
<item name="android:textColor">#ffffff</item>
<item name="android:gravity">left|top</item>

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* User: serso
* Date: 9/17/11
* Time: 10:58 PM
*/
public class CalculatorDisplay extends TextView {
private boolean valid = true;
public CalculatorDisplay(Context context) {
super(context);
}
public CalculatorDisplay(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CalculatorDisplay(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
setValid(true);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 9/17/11
* Time: 11:05 PM
*/
public class CalculatorDisplayHistoryState extends EditorHistoryState {
private boolean valid = true;
public CalculatorDisplayHistoryState() {
}
public CalculatorDisplayHistoryState(boolean valid) {
this.valid = valid;
}
public CalculatorDisplayHistoryState(int cursorPosition, @Nullable String text, boolean valid) {
super(cursorPosition, text);
this.valid = valid;
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
}

View File

@ -18,9 +18,9 @@ public class CalculatorHistoryState {
private EditorHistoryState editorState;
@NotNull
private EditorHistoryState displayState;
private CalculatorDisplayHistoryState displayState;
public CalculatorHistoryState(@NotNull EditorHistoryState editorState, @NotNull EditorHistoryState displayState) {
public CalculatorHistoryState(@NotNull EditorHistoryState editorState, @NotNull CalculatorDisplayHistoryState displayState) {
this.editorState = editorState;
this.displayState = displayState;
}
@ -35,11 +35,11 @@ public class CalculatorHistoryState {
}
@NotNull
public EditorHistoryState getDisplayState() {
public CalculatorDisplayHistoryState getDisplayState() {
return displayState;
}
public void setDisplayState(@NotNull EditorHistoryState displayState) {
public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) {
this.displayState = displayState;
}
}

View File

@ -5,13 +5,13 @@
package org.solovyev.android.calculator;
import android.util.Log;
import bsh.EvalError;
import bsh.Interpreter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.exceptions.SersoException;
import org.solovyev.common.utils.MathUtils;
import org.solovyev.common.utils.StringUtils;
import org.solovyev.util.math.Complex;
/**
* User: serso
@ -32,28 +32,76 @@ public class CalculatorModel {
interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
}
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 String preprocessedExpression = Preprocessor.process(expression);
Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
Object evaluationObject = interpreter.eval(Preprocessor.wrap(operation, preprocessedExpression));
String result = String.valueOf(evaluationObject).trim();
try {
final Double dResult = Double.valueOf(result);
result = String.valueOf(MathUtils.round(dResult, NUMBER_OF_FRACTION_DIGITS));
result = round(result);
} catch (NumberFormatException e) {
throw new ParseException(e);
if (result.contains("sqrt(-1)")) {
try {
result = createResultForComplexNumber(result.replace("sqrt(-1)", "i"));
} catch (NumberFormatException e1) {
// throw original one
throw new ParseException(e);
}
} else {
throw new ParseException(e);
}
}
return result;
}
public String createResultForComplexNumber(@NotNull final String s) {
final Complex complex = new Complex();
String result = "";
// may be it's just complex number
int plusIndex = s.lastIndexOf("+");
if (plusIndex >= 0) {
complex.setReal(round(s.substring(0, plusIndex)));
result += complex.getReal();
result += "+";
} else {
plusIndex = s.lastIndexOf("-");
if (plusIndex >= 0) {
complex.setReal(round(s.substring(0, plusIndex)));
result += complex.getReal();
result += "-";
}
}
int multiplyIndex = s.indexOf("*");
if (multiplyIndex >= 0) {
complex.setImag(round(s.substring(plusIndex >= 0 ? plusIndex+1 : 0, multiplyIndex)));
result += complex.getImag();
}
result += "i";
return result;
}
private String round(@NotNull String result) {
final Double dResult = Double.valueOf(result);
result = String.valueOf(MathUtils.round(dResult, NUMBER_OF_FRACTION_DIGITS));
return result;
}
public static class ParseException extends SersoException {
public ParseException(Throwable cause) {
super(cause);
}
}
}

View File

@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.view.CursorControl;
import org.solovyev.android.view.HistoryControl;
import org.solovyev.common.math.calculators.Calculator;
import org.solovyev.common.utils.MutableObject;
import org.solovyev.common.utils.StringUtils;
import org.solovyev.common.utils.history.HistoryAction;
@ -37,13 +36,13 @@ import org.solovyev.util.math.MathEntityType;
public class CalculatorView implements CursorControl, HistoryControl<CalculatorHistoryState> {
// millis to wait before evaluation after user edit action
public static final int EVAL_DELAY_MILLIS = 1000;
public static final int EVAL_DELAY_MILLIS = 500;
@NotNull
private final CalculatorEditText editor;
@NotNull
private final TextView display;
private final CalculatorDisplay display;
@NotNull
private final Activity activity;
@ -52,7 +51,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
private final CalculatorModel calculatorModel;
@NotNull
private HistoryHelper<CalculatorHistoryState> history;
private final HistoryHelper<CalculatorHistoryState> history;
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
this.activity = activity;
@ -64,15 +63,17 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
this.editor.setInputType(InputType.TYPE_NULL);
imm.hideSoftInputFromWindow(this.editor.getWindowToken(), 0);
this.display = (TextView) activity.findViewById(R.id.resultEditText);
this.display = (CalculatorDisplay) activity.findViewById(R.id.resultEditText);
this.display.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final CharSequence text = ((TextView) v).getText();
if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text);
Toast.makeText(activity, "Result copied to clipboard!", Toast.LENGTH_SHORT).show();
if (((CalculatorDisplay) v).isValid()) {
final CharSequence text = ((TextView) v).getText();
if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text);
Toast.makeText(activity, "Result copied to clipboard!", Toast.LENGTH_SHORT).show();
}
}
}
});
@ -120,17 +121,21 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
currentRunner.setObject(new Runnable() {
@Override
public void run() {
// allow only one runner at one time
synchronized (currentRunner) {
// do only if nothing was post delayed before current instance was posted
if (currentRunner.getObject() == this) {
// actually nothing shall be logged while text operations are done
evaluate(editorStateAfter, true);
//lock all operations with history
synchronized (history) {
// do only if nothing was post delayed before current instance was posted
if (currentRunner.getObject() == this) {
// actually nothing shall be logged while text operations are done
evaluate(editorStateAfter);
if (history.isUndoAvailable()) {
history.undo(getCurrentHistoryState());
if (history.isUndoAvailable()) {
history.undo(getCurrentHistoryState());
}
saveHistoryState();
}
saveHistoryState();
}
}
}
@ -142,29 +147,26 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
}
}
private void evaluate(@Nullable final String expression, final boolean showError) {
private void evaluate(@Nullable final String expression) {
if (!StringUtils.isEmpty(expression)) {
final TextView localDisplay = display;
final Activity localActivity = activity;
final CalculatorDisplay localDisplay = display;
try {
Log.d(CalculatorView.class.getName(), "Trying to evaluate: " + expression);
localDisplay.setText(calculatorModel.evaluate(JsclOperation.numeric, expression));
} catch (EvalError e) {
handleEvaluationException(expression, showError, localDisplay, localActivity, e);
handleEvaluationException(expression, localDisplay, e);
} catch (CalculatorModel.ParseException e) {
handleEvaluationException(expression, showError, localDisplay, localActivity, e);
handleEvaluationException(expression, localDisplay, e);
}
}
}
private void handleEvaluationException(@NotNull String expression, boolean showError, @NotNull TextView localDisplay, @NotNull Activity localActivity, @NotNull Exception e) {
private void handleEvaluationException(@NotNull String expression, @NotNull CalculatorDisplay localDisplay, @NotNull Exception e) {
Log.d(CalculatorView.class.getName(), "Evaluation failed for : " + expression + ". Error message: " + e.getMessage());
localDisplay.setText("");
if (showError) {
Toast.makeText(localActivity, R.string.syntax_error, Toast.LENGTH_SHORT).show();
}
localDisplay.setText(R.string.c_syntax_error);
localDisplay.setValid(false);
}
public void clear() {
@ -176,7 +178,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
}
public void evaluate() {
evaluate(editor.getText().toString(), true);
evaluate(editor.getText().toString());
}
public void processDigitButtonAction(@Nullable final String text) {
@ -223,18 +225,27 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override
public void doHistoryAction(@NotNull HistoryAction historyAction) {
if (history.isActionAvailable(historyAction)) {
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
if (newState != null) {
setCurrentHistoryState(newState);
synchronized (history) {
if (history.isActionAvailable(historyAction)) {
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
if (newState != null) {
setCurrentHistoryState(newState);
}
}
}
}
@Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
synchronized (history) {
setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
}
}
private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) {
setValuesFromHistory(display, (EditorHistoryState)editorHistoryState);
display.setValid(editorHistoryState.isValid());
}
private void setValuesFromHistory(@NotNull TextView editText, EditorHistoryState editorHistoryState) {
@ -247,7 +258,9 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override
@NotNull
public CalculatorHistoryState getCurrentHistoryState() {
return new CalculatorHistoryState(getEditorHistoryState(this.editor), getEditorHistoryState(this.display));
synchronized (history) {
return new CalculatorHistoryState(getEditorHistoryState(this.editor), getCalculatorDisplayHistoryState(this.display));
}
}
private EditorHistoryState getEditorHistoryState(@NotNull TextView textView) {
@ -258,4 +271,14 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
return result;
}
private CalculatorDisplayHistoryState getCalculatorDisplayHistoryState(@NotNull CalculatorDisplay display) {
final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
result.setText(String.valueOf(display.getText()));
result.setCursorPosition(display.getSelectionStart());
result.setValid(display.isValid());
return result;
}
}

View File

@ -6,6 +6,11 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.CollectionsUtils;
import org.solovyev.common.utils.EqualsFinder;
import org.solovyev.common.utils.Finder;
import org.solovyev.util.math.Functions;
import org.solovyev.util.math.MathEntityType;
public class Preprocessor {
@ -14,49 +19,75 @@ public class Preprocessor {
public static String process(@NotNull String s) {
final StringBuilder sb = new StringBuilder();
final StartWithFinder startsWithFinder = new StartWithFinder(s);
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
checkMultiplicationSignBeforeFunction(sb, s, i);
if (ch == '[' || ch == '{') {
if (MathEntityType.openGroupSymbols.contains(ch)) {
sb.append('(');
} else if (ch == ']' || ch == '}') {
} else if (MathEntityType.closeGroupSymbols.contains(ch)) {
sb.append(')');
} else if (ch == 'π') {
sb.append("pi");
} else if (ch == '×' || ch == '∙') {
sb.append("*");
} else if (s.startsWith("ln", i)) {
sb.append("log");
i += 1;
} else if (s.startsWith("tg", i)) {
sb.append("tan");
i += 1;
} else if (s.startsWith("atg", i)) {
sb.append("atan");
i += 2;
} else if (s.startsWith("acos", i)) {
sb.append("acos");
i += 3;
} else if (s.startsWith("asin", i)) {
sb.append("asin");
i += 3;
} else if (s.startsWith("e(", i)) {
sb.append("exp(");
i += 1;
} else if (ch == 'e') {
sb.append("exp(1)");
} else if (ch == '√') {
sb.append("sqrt");
} else {
sb.append(ch);
startsWithFinder.setI(i);
final String function = CollectionsUtils.get(MathEntityType.functions, startsWithFinder);
if (function != null) {
sb.append(toJsclFunction(function));
i += function.length() - 1;
} else if (ch == 'e') {
sb.append("exp(1)");
} else if (ch == 'i') {
sb.append("sqrt(-1)");
} else {
sb.append(ch);
}
}
}
return sb.toString();
}
@NotNull
private static String toJsclFunction(@NotNull String function) {
final String result;
if (function.equals(Functions.LN)) {
result = Functions.LOG;
} else if (function.equals(Functions.SQRT_SIGN)) {
result = Functions.SQRT;
} else {
result = function;
}
return result;
}
private static class StartWithFinder implements Finder<String> {
private int i;
@NotNull
private final String targetString;
private StartWithFinder(@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 void checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, @NotNull String s, int i) {
if (i > 0) {
// get character before function

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.util.math;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 9/17/11
* Time: 11:35 PM
*/
public class Complex {
@Nullable
private String real, imag;
@Nullable
public String getReal() {
return real;
}
public void setReal(@Nullable String real) {
this.real = real;
}
@Nullable
public String getImag() {
return imag;
}
public void setImag(@Nullable String imag) {
this.imag = imag;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.util.math;
import org.jetbrains.annotations.NonNls;
import java.util.Arrays;
import java.util.List;
/**
* User: serso
* Date: 9/17/11
* Time: 10:01 PM
*/
public interface Functions {
String SIN = "sin";
String SINH = "sinh";
String ASIN = "asin";
String ASINH = "asinh";
String COS = "cos";
String COSH = "cosh";
String ACOS = "acos";
String ACOSH = "acosh";
String TAN = "tan";
String TANH = "tanh";
String ATAN = "atan";
String ATANH = "atanh";
String LOG = "log";
String LN = "ln";
String MOD = "mod";
String EXP = "exp";
String SQRT_SIGN = "";
String SQRT = "sqrt";
public static final List<String> all = Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP);
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.util.math;
import org.jetbrains.annotations.NotNull;
public enum MathEntity {
minus("-"),
equals("="),
factorial("!"),
plus("+"),
multiply("*"),
divide("/"),
power("^"),
sin("sin"),
asin("asin"),
cos("cos"),
acos("acos"),
tg("tg"),
atg("atg"),
exp("exp"),
log("log"),
ln("ln"),
mod("mod"),
sqrt("sqrt");
@NotNull
private final String text;
private MathEntity (@NotNull String text) {
this.text = text;
}
@NotNull
public String getText() {
return text;
}
}

View File

@ -24,7 +24,7 @@ public enum MathEntityType {
group_symbols,
group_symbol;
public static final List<Character> constants = Arrays.asList('e', 'π');
public static final List<Character> constants = Arrays.asList('e', 'π', 'i');
public static final List<Character> dots = Arrays.asList('.', ',');
@ -32,7 +32,7 @@ public enum MathEntityType {
public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^' );
public static final List<String> functions = Arrays.asList("sin", "asin", "cos", "acos", "tg", "atg", "log", "ln", "mod", "");
public static final List<String> functions = Functions.all;
public static final List<String> groupSymbols = Arrays.asList("[]", "()", "{}");

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
import de.congrace.exp4j.Calculable;
import de.congrace.exp4j.ExpressionBuilder;
import de.congrace.exp4j.UnknownFunctionException;
import de.congrace.exp4j.UnparsableExpressionException;
import org.junit.Assert;
import org.junit.Test;
/**
* User: serso
* Date: 9/17/11
* Time: 9:47 PM
*/
public class CalculatorModelTest {
@Test
public void testEvaluate() throws Exception {
final CalculatorModel cm = new CalculatorModel();
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "2+2"));
Assert.assertEquals("-0.7568", cm.evaluate(JsclOperation.numeric, "sin(4)"));
Assert.assertEquals("0.5236", cm.evaluate(JsclOperation.numeric, "asin(0.5)"));
Assert.assertEquals("-0.39626", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)"));
Assert.assertEquals("-0.5604", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)sqrt(2)"));
Assert.assertEquals("-0.5604", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)"));
Assert.assertEquals("7.38906", cm.evaluate(JsclOperation.numeric, "e^2"));
Assert.assertEquals("7.38906", cm.evaluate(JsclOperation.numeric, "exp(1)^2"));
Assert.assertEquals("7.38906", cm.evaluate(JsclOperation.numeric, "exp(2)"));
Assert.assertEquals("2.0+i", cm.evaluate(JsclOperation.numeric, "2*1+sqrt(-1)"));
Assert.assertEquals("0.92054+3.14159i", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))"));
Assert.assertEquals("7.38906i", cm.evaluate(JsclOperation.numeric, "iexp(2)"));
Assert.assertEquals("2.0+7.38906i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)"));
Assert.assertEquals("2.0+7.38906i", cm.evaluate(JsclOperation.numeric, "2+√(-1)exp(2)"));
Assert.assertEquals("2.0-2.5i", cm.evaluate(JsclOperation.numeric, "2-2.5i"));
Assert.assertEquals("-2.0-2.5i", cm.evaluate(JsclOperation.numeric, "-2-2.5i"));
Assert.assertEquals("-2.0+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i"));
Assert.assertEquals("-2.0+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i"));
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)"));
}
@Test
public void testComplexNumbers() throws Exception {
final CalculatorModel cm = new CalculatorModel();
Assert.assertEquals("1.22133+23123.0i", cm.createResultForComplexNumber("1.22133232+23123*i"));
Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i"));
Assert.assertEquals("1.22i", cm.createResultForComplexNumber("1.22*i"));
Assert.assertEquals("i", cm.createResultForComplexNumber("i"));
}
}