complex number support added
This commit is contained in:
parent
c1306db96a
commit
58ff7d4522
22
pom.xml
22
pom.xml
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,22 +32,69 @@ 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -56,4 +103,5 @@ public class CalculatorModel {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,10 +63,11 @@ 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) {
|
||||
if (((CalculatorDisplay) v).isValid()) {
|
||||
final CharSequence text = ((TextView) v).getText();
|
||||
if (!StringUtils.isEmpty(text)) {
|
||||
final ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
|
||||
@ -75,6 +75,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
||||
Toast.makeText(activity, "Result copied to clipboard!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.history = new SimpleHistoryHelper<CalculatorHistoryState>();
|
||||
@ -120,11 +121,14 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
||||
currentRunner.setObject(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// allow only one runner at one time
|
||||
synchronized (currentRunner) {
|
||||
//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, true);
|
||||
evaluate(editorStateAfter);
|
||||
|
||||
if (history.isUndoAvailable()) {
|
||||
history.undo(getCurrentHistoryState());
|
||||
@ -134,6 +138,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Handler().postDelayed(currentRunner.getObject(), EVAL_DELAY_MILLIS);
|
||||
@ -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,6 +225,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
||||
|
||||
@Override
|
||||
public void doHistoryAction(@NotNull HistoryAction historyAction) {
|
||||
synchronized (history) {
|
||||
if (history.isActionAvailable(historyAction)) {
|
||||
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
|
||||
if (newState != null) {
|
||||
@ -230,12 +233,20 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
|
||||
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) {
|
||||
editText.setText(editorHistoryState.getText());
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
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 == '√') {
|
||||
sb.append("sqrt");
|
||||
} 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
|
||||
|
37
src/main/java/org/solovyev/util/math/Complex.java
Normal file
37
src/main/java/org/solovyev/util/math/Complex.java
Normal 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;
|
||||
}
|
||||
}
|
40
src/main/java/org/solovyev/util/math/Functions.java
Normal file
40
src/main/java/org/solovyev/util/math/Functions.java
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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("[]", "()", "{}");
|
||||
|
||||
|
@ -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"));
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user