rounding fix + color display + refactor
This commit is contained in:
parent
2753f3f53d
commit
c554cfc9f3
@ -6,8 +6,14 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.text.Html;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.model.ParseException;
|
||||
import org.solovyev.android.calculator.model.TextProcessor;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
@ -18,6 +24,9 @@ public class CalculatorDisplay extends TextView {
|
||||
|
||||
private boolean valid = true;
|
||||
|
||||
@NotNull
|
||||
private final static TextProcessor<String> textHighlighter = new TextHighlighter(Color.WHITE);
|
||||
|
||||
public CalculatorDisplay(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@ -44,4 +53,22 @@ public class CalculatorDisplay extends TextView {
|
||||
|
||||
setValid(true);
|
||||
}
|
||||
|
||||
public synchronized void redraw() {
|
||||
if (isValid()) {
|
||||
String text = getText().toString();
|
||||
|
||||
Log.d(this.getClass().getName(), text);
|
||||
|
||||
try {
|
||||
text = textHighlighter.process(text);
|
||||
} catch (ParseException e) {
|
||||
Log.e(this.getClass().getName(), e.getMessage(), e);
|
||||
}
|
||||
|
||||
Log.d(this.getClass().getName(), text);
|
||||
super.setText(Html.fromHtml(text), BufferType.EDITABLE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -171,19 +171,20 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
|
||||
}
|
||||
|
||||
private void evaluate(@Nullable final String expression) {
|
||||
final CalculatorDisplay localDisplay = display;
|
||||
if (!StringUtils.isEmpty(expression)) {
|
||||
try {
|
||||
Log.d(CalculatorModel.class.getName(), "Trying to evaluate: " + expression /*+ StringUtils.fromStackTrace(Thread.currentThread().getStackTrace())*/);
|
||||
localDisplay.setText(calculatorEngine.evaluate(JsclOperation.numeric, expression));
|
||||
display.setText(calculatorEngine.evaluate(JsclOperation.numeric, expression));
|
||||
} catch (EvalError e) {
|
||||
handleEvaluationException(expression, localDisplay, e);
|
||||
handleEvaluationException(expression, display, e);
|
||||
} catch (ParseException e) {
|
||||
handleEvaluationException(expression, localDisplay, e);
|
||||
handleEvaluationException(expression, display, e);
|
||||
}
|
||||
} else {
|
||||
localDisplay.setText("");
|
||||
this.display.setText("");
|
||||
}
|
||||
|
||||
this.display.redraw();
|
||||
}
|
||||
|
||||
private void handleEvaluationException(@NotNull String expression, @NotNull CalculatorDisplay localDisplay, @NotNull Exception e) {
|
||||
@ -212,15 +213,19 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
|
||||
final MathType.Result mathType = MathType.getType(text, 0);
|
||||
|
||||
int cursorPositionOffset = 0;
|
||||
|
||||
final StringBuilder textToBeInserted = new StringBuilder(text);
|
||||
switch (mathType.getMathType()) {
|
||||
case function:
|
||||
textToBeInserted.append("()");
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
case group_symbols:
|
||||
}
|
||||
|
||||
if (cursorPositionOffset == 0) {
|
||||
if ( MathType.openGroupSymbols.contains(text) ) {
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
editor.getText().insert(editor.getSelectionStart(), textToBeInserted.toString());
|
||||
@ -256,6 +261,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
|
||||
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
|
||||
|
||||
editor.redraw();
|
||||
display.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,15 +97,15 @@ public class TextHighlighter implements TextProcessor<String> {
|
||||
for (; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
|
||||
if (MathType.openGroupSymbols.contains(ch)) {
|
||||
if (MathType.open_group_symbol.getTokens().contains(String.valueOf(ch))) {
|
||||
result.append(ch);
|
||||
result.append("</font>");
|
||||
i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
|
||||
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
|
||||
if (i < s.length() && MathType.closeGroupSymbols.contains(s.charAt(i))) {
|
||||
if (i < s.length() && MathType.close_group_symbol.getTokens().contains(String.valueOf(s.charAt(i)))) {
|
||||
result.append(s.charAt(i));
|
||||
}
|
||||
} else if (MathType.closeGroupSymbols.contains(ch)) {
|
||||
} else if (MathType.close_group_symbol.getTokens().contains(String.valueOf(ch))) {
|
||||
break;
|
||||
} else {
|
||||
result.append(ch);
|
||||
|
@ -7,12 +7,14 @@
|
||||
package org.solovyev.android.calculator.jscl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.android.calculator.model.CalculatorEngine;
|
||||
import org.solovyev.android.calculator.model.ParseException;
|
||||
import org.solovyev.android.calculator.model.TextProcessor;
|
||||
import org.solovyev.common.utils.MathUtils;
|
||||
import org.solovyev.util.math.Complex;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
@ -25,11 +27,12 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
|
||||
@Override
|
||||
public String process(@NotNull String result) throws ParseException {
|
||||
try {
|
||||
final Double roundedValue = round(result);
|
||||
if ( roundedValue.isInfinite() ) {
|
||||
result = MathType.INFINITY;
|
||||
final Double doubleValue = Double.valueOf(result);
|
||||
|
||||
if (doubleValue.isInfinite()) {
|
||||
result = MathType.INFINITY;
|
||||
} else {
|
||||
result = String.valueOf(roundedValue);
|
||||
result = format(doubleValue);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
result = result.replace(MathType.INFINITY_JSCL, MathType.INFINITY);
|
||||
@ -49,6 +52,21 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private String format(@NotNull String value) {
|
||||
return format(Double.valueOf(value));
|
||||
}
|
||||
|
||||
private String format(@NotNull Double value) {
|
||||
if (!value.isInfinite() && !value.isNaN()) {
|
||||
final DecimalFormat df = new DecimalFormat();
|
||||
df.setGroupingUsed(false);
|
||||
df.setMaximumFractionDigits(CalculatorEngine.instance.getPrecision());
|
||||
return df.format(new BigDecimal(value).setScale(CalculatorEngine.instance.getPrecision(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
||||
} else {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected String createResultForComplexNumber(@NotNull final String s) {
|
||||
final Complex complex = new Complex();
|
||||
|
||||
@ -56,13 +74,13 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
|
||||
// may be it's just complex number
|
||||
int plusIndex = s.lastIndexOf("+");
|
||||
if (plusIndex >= 0) {
|
||||
complex.setReal(round(s.substring(0, plusIndex)));
|
||||
complex.setReal(format(s.substring(0, plusIndex)));
|
||||
result += complex.getReal();
|
||||
result += "+";
|
||||
} else {
|
||||
plusIndex = s.lastIndexOf("-");
|
||||
if (plusIndex >= 0) {
|
||||
complex.setReal(round(s.substring(0, plusIndex)));
|
||||
complex.setReal(format(s.substring(0, plusIndex)));
|
||||
result += complex.getReal();
|
||||
result += "-";
|
||||
}
|
||||
@ -71,7 +89,7 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
|
||||
|
||||
int multiplyIndex = s.indexOf("*");
|
||||
if (multiplyIndex >= 0) {
|
||||
complex.setImaginary(round(s.substring(plusIndex >= 0 ? plusIndex + 1 : 0, multiplyIndex)));
|
||||
complex.setImaginary(format(s.substring(plusIndex >= 0 ? plusIndex + 1 : 0, multiplyIndex)));
|
||||
result += complex.getImaginary();
|
||||
|
||||
}
|
||||
@ -81,8 +99,31 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Double round(@NotNull String result) {
|
||||
final Double dResult = Double.valueOf(result);
|
||||
return MathUtils.round(dResult, CalculatorEngine.instance.getNumberOfFractionDigits());
|
||||
private class Complex {
|
||||
|
||||
@Nullable
|
||||
private String real;
|
||||
|
||||
@Nullable
|
||||
private String imaginary;
|
||||
|
||||
@Nullable
|
||||
public String getReal() {
|
||||
return real;
|
||||
}
|
||||
|
||||
public void setReal(@Nullable String real) {
|
||||
this.real = real;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getImaginary() {
|
||||
return imaginary;
|
||||
}
|
||||
|
||||
public void setImaginary(@Nullable String imaginary) {
|
||||
this.imaginary = imaginary;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ public class Functions {
|
||||
allPrefix = functions;
|
||||
}
|
||||
|
||||
public final static Character FACT = '!';
|
||||
public final static Character DEGREE = '°';
|
||||
public final static String FACT = "!";
|
||||
public final static String DEGREE = "°";
|
||||
|
||||
public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
|
||||
public static final List<String> allPostfix = Arrays.asList(FACT, DEGREE);
|
||||
}
|
||||
|
@ -9,60 +9,119 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
||||
import org.solovyev.android.calculator.StartsWithFinder;
|
||||
import org.solovyev.android.calculator.model.CalculatorEngine;
|
||||
import org.solovyev.common.utils.CollectionsUtils;
|
||||
import org.solovyev.common.utils.Finder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static org.solovyev.common.utils.CollectionsUtils.get;
|
||||
|
||||
public enum MathType {
|
||||
|
||||
digit,
|
||||
dot,
|
||||
power_10,
|
||||
constant,
|
||||
function,
|
||||
postfix_function,
|
||||
unary_operation,
|
||||
binary_operation,
|
||||
group_symbols,
|
||||
open_group_symbol,
|
||||
close_group_symbol,
|
||||
text;
|
||||
digit(100, true, true, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot;
|
||||
}
|
||||
},
|
||||
|
||||
dot(200, true, true, "."){
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit;
|
||||
}
|
||||
},
|
||||
|
||||
power_10(300, true, false, "E"),
|
||||
|
||||
postfix_function(400, true, false, Functions.allPostfix),
|
||||
unary_operation(500, false, false, "-", "=", "!"),
|
||||
binary_operation(600, false, false, "-", "+", "*", "×", "∙", "/", "^"),
|
||||
open_group_symbol(800, true, false, "[", "(", "{") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function;
|
||||
}
|
||||
},
|
||||
close_group_symbol(900, false, true, "]", ")", "}") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
function(1000, true, true, Functions.allPrefix),
|
||||
constant(1100, true, true) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorEngine.instance.getVarsRegister().getVarNames();
|
||||
}
|
||||
},
|
||||
|
||||
text(1200, false, false);
|
||||
|
||||
@NotNull
|
||||
private final List<String> tokens;
|
||||
|
||||
@NotNull
|
||||
private final Integer priority;
|
||||
|
||||
private final boolean needMultiplicationSignBefore;
|
||||
|
||||
private final boolean needMultiplicationSignAfter;
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull String... tokens) {
|
||||
this(priority, needMultiplicationSignBefore, needMultiplicationSignAfter, CollectionsUtils.asList(tokens));
|
||||
}
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull List<String> tokens) {
|
||||
this.priority = priority;
|
||||
this.needMultiplicationSignBefore = needMultiplicationSignBefore;
|
||||
this.needMultiplicationSignAfter = needMultiplicationSignAfter;
|
||||
this.tokens = Collections.unmodifiableList(tokens);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignBefore() {
|
||||
return needMultiplicationSignBefore;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignAfter() {
|
||||
return needMultiplicationSignAfter;
|
||||
}
|
||||
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
|
||||
}
|
||||
|
||||
|
||||
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
|
||||
|
||||
public final static Character POWER_10 = 'E';
|
||||
public final static String POWER_10_JSCL = "10^";
|
||||
|
||||
public static final String IMAGINARY_NUMBER = "i";
|
||||
public static final String IMAGINARY_NUMBER_JSCL = "sqrt(-1)";
|
||||
|
||||
public static final String PI = "π";
|
||||
public static final String E = "e";
|
||||
public final static String NAN = "NaN";
|
||||
|
||||
public final static String INFINITY = "∞";
|
||||
public final static String INFINITY_JSCL = "Infinity";
|
||||
|
||||
public static final List<String> constants = Arrays.asList(E, PI, IMAGINARY_NUMBER, NAN, INFINITY);
|
||||
|
||||
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> unaryOperations = Arrays.asList('-', '=', '!');
|
||||
|
||||
public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^');
|
||||
|
||||
public static final List<String> prefixFunctions = Functions.allPrefix;
|
||||
|
||||
public static final List<Character> postfixFunctions = Functions.allPostfix;
|
||||
|
||||
public static final List<String> groupSymbols = Arrays.asList("[]", "()", "{}");
|
||||
|
||||
public static final List<Character> openGroupSymbols = Arrays.asList('[', '(', '{');
|
||||
|
||||
public static final List<Character> closeGroupSymbols = Arrays.asList(']', ')', '}');
|
||||
|
||||
/**
|
||||
* Method determines mathematical entity type for text substring starting from ith index
|
||||
*
|
||||
@ -80,67 +139,39 @@ public enum MathType {
|
||||
return new Result(MathType.text, text);
|
||||
}
|
||||
|
||||
final StartsWithFinder stringStartWithFinder = new StartsWithFinder(text, i);
|
||||
final CharacterAtPositionFinder characterStartWithFinder = new CharacterAtPositionFinder(text, i);
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(text, i);
|
||||
|
||||
String foundString = get(digits, stringStartWithFinder);
|
||||
if (foundString != null) {
|
||||
return new Result(MathType.digit, foundString);
|
||||
}
|
||||
|
||||
Character foundCharacter = get(dots, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(dot, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundCharacter = characterStartWithFinder.isFound(POWER_10) ? POWER_10 : null;
|
||||
if (foundCharacter != null) {
|
||||
return new Result(power_10, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundCharacter = get(postfixFunctions, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(postfix_function, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundCharacter = get(unaryOperations, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(unary_operation, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundCharacter = get(binaryOperations, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(binary_operation, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundString = get(groupSymbols, stringStartWithFinder);
|
||||
if (foundString != null) {
|
||||
return new Result(MathType.group_symbols, foundString);
|
||||
}
|
||||
|
||||
foundCharacter = get(openGroupSymbols, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(open_group_symbol, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundCharacter = get(closeGroupSymbols, characterStartWithFinder);
|
||||
if (foundCharacter != null) {
|
||||
return new Result(close_group_symbol, String.valueOf(foundCharacter));
|
||||
}
|
||||
|
||||
foundString = get(prefixFunctions, stringStartWithFinder);
|
||||
if (foundString != null) {
|
||||
return new Result(MathType.function, foundString);
|
||||
}
|
||||
|
||||
foundString = get(CalculatorEngine.instance.getVarsRegister().getVarNames(), stringStartWithFinder);
|
||||
if (foundString != null) {
|
||||
return new Result(MathType.constant, foundString);
|
||||
for (MathType mathType : getMathTypesByPriority()) {
|
||||
final String s = get(mathType.getTokens(), startsWithFinder);
|
||||
if ( s != null ) {
|
||||
return new Result(mathType, s);
|
||||
}
|
||||
}
|
||||
|
||||
return new Result(MathType.text, text.substring(i));
|
||||
}
|
||||
|
||||
|
||||
private static List<MathType> mathTypesByPriority;
|
||||
|
||||
@NotNull
|
||||
private static List<MathType> getMathTypesByPriority() {
|
||||
if ( mathTypesByPriority == null ) {
|
||||
final List<MathType> result = CollectionsUtils.asList(MathType.values());
|
||||
|
||||
Collections.sort(result, new Comparator<MathType>() {
|
||||
@Override
|
||||
public int compare(MathType l, MathType r) {
|
||||
return l.priority.compareTo(r.priority);
|
||||
}
|
||||
});
|
||||
|
||||
mathTypesByPriority = result;
|
||||
}
|
||||
|
||||
return mathTypesByPriority;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
@NotNull
|
||||
@ -149,7 +180,7 @@ public enum MathType {
|
||||
@NotNull
|
||||
private final String match;
|
||||
|
||||
public Result(@NotNull MathType mathType, @NotNull String match){
|
||||
public Result(@NotNull MathType mathType, @NotNull String match) {
|
||||
this.mathType = mathType;
|
||||
|
||||
this.match = match;
|
||||
|
@ -39,7 +39,7 @@ public enum CalculatorEngine {
|
||||
@NotNull
|
||||
private final Object lock = new Object();
|
||||
|
||||
private int numberOfFractionDigits = 5;
|
||||
private int precision = 5;
|
||||
|
||||
@NotNull
|
||||
public final TextProcessor<PreparedExpression> preprocessor = new ToJsclTextProcessor();
|
||||
@ -85,12 +85,12 @@ public enum CalculatorEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumberOfFractionDigits() {
|
||||
return numberOfFractionDigits;
|
||||
public int getPrecision() {
|
||||
return precision;
|
||||
}
|
||||
|
||||
public void setNumberOfFractionDigits(int numberOfFractionDigits) {
|
||||
this.numberOfFractionDigits = numberOfFractionDigits;
|
||||
public void setPrecision(int precision) {
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
public void init(@Nullable Context context, @Nullable SharedPreferences preferences) throws EvalError {
|
||||
@ -105,7 +105,7 @@ public enum CalculatorEngine {
|
||||
if (preferences != null) {
|
||||
final NumberMapper<Integer> integerNumberMapper = new NumberMapper<Integer>(Integer.class);
|
||||
//noinspection ConstantConditions
|
||||
this.setNumberOfFractionDigits(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT)));
|
||||
this.setPrecision(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT)));
|
||||
}
|
||||
|
||||
varsRegister.init(context, preferences);
|
||||
|
@ -50,7 +50,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
|
||||
// NOTE: fix for jscl for EMPTY functions processing (see tests)
|
||||
startsWithFinder.setI(i + 1);
|
||||
if ( i < s.length() && CollectionsUtils.get(MathType.groupSymbols, startsWithFinder) != null) {
|
||||
if ( i < s.length() && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) {
|
||||
throw new ParseException("Empty function: " + mathTypeResult.getMatch());
|
||||
/*i += 2;
|
||||
sb.append("(" + SPECIAL_STRING + ")");
|
||||
@ -78,7 +78,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
startsWithFinder.setI(i);
|
||||
|
||||
int offset = 0;
|
||||
String functionName = CollectionsUtils.get(MathType.prefixFunctions, startsWithFinder);
|
||||
String functionName = CollectionsUtils.get(MathType.function.getTokens(), startsWithFinder);
|
||||
if (functionName == null) {
|
||||
String varName = CollectionsUtils.get(CalculatorEngine.instance.getVarsRegister().getVarNames(), startsWithFinder);
|
||||
if (varName != null) {
|
||||
@ -114,7 +114,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
for (Var var : CalculatorEngine.instance.getVarsRegister().getVars()) {
|
||||
if (!var.isSystem()) {
|
||||
if (s.startsWith(var.getName(), i)) {
|
||||
if (CollectionsUtils.get(MathType.prefixFunctions, startsWithFinder) == null) {
|
||||
if (CollectionsUtils.get(MathType.function.getTokens(), startsWithFinder) == null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,7 +149,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
if (i > 0) {
|
||||
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
||||
endsWithFinder.setI(i + 1);
|
||||
if (!CollectionsUtils.contains(MathType.prefixFunctions, FilterType.included, endsWithFinder)) {
|
||||
if (!CollectionsUtils.contains(MathType.function.getTokens(), FilterType.included, endsWithFinder)) {
|
||||
MathType type = MathType.getType(s, i).getMathType();
|
||||
if (type != MathType.constant) {
|
||||
return true;
|
||||
@ -204,36 +204,16 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
@NotNull String s,
|
||||
int i,
|
||||
@Nullable MathType.Result mathTypeBeforeResult) {
|
||||
MathType.Result result = MathType.getType(s, i);
|
||||
final MathType.Result result = MathType.getType(s, i);
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
final MathType mathType = result.getMathType();
|
||||
final MathType current = result.getMathType();
|
||||
assert mathTypeBeforeResult != null;
|
||||
final MathType mathTypeBefore = mathTypeBeforeResult.getMathType();
|
||||
final MathType before = mathTypeBeforeResult.getMathType();
|
||||
|
||||
if (mathTypeBefore == MathType.constant || (mathTypeBefore != MathType.binary_operation &&
|
||||
mathTypeBefore != MathType.unary_operation &&
|
||||
mathTypeBefore != MathType.power_10 &&
|
||||
mathTypeBefore != MathType.function &&
|
||||
mathTypeBefore != MathType.open_group_symbol)) {
|
||||
|
||||
if (mathType == MathType.constant) {
|
||||
sb.append("*");
|
||||
} else if (mathType == MathType.power_10) {
|
||||
sb.append("*");
|
||||
} else if (mathType == MathType.open_group_symbol && mathTypeBefore != null) {
|
||||
sb.append("*");
|
||||
} else if (mathType == MathType.digit && ((mathTypeBefore != MathType.digit && mathTypeBefore != MathType.dot) || mathTypeBefore == MathType.constant)) {
|
||||
sb.append("*");
|
||||
} else {
|
||||
for (String function : MathType.prefixFunctions) {
|
||||
if (s.startsWith(function, i)) {
|
||||
sb.append("*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (current.isNeedMultiplicationSignBefore(before)) {
|
||||
sb.append("*");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import bsh.EvalError;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.simpleframework.xml.Attribute;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
/**
|
||||
@ -28,27 +27,52 @@ public class CalculatorEngineTest {
|
||||
public void testEvaluate() throws Exception {
|
||||
final CalculatorEngine cm = CalculatorEngine.instance;
|
||||
|
||||
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("4", cm.evaluate(JsclOperation.numeric, "2+2"));
|
||||
Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)"));
|
||||
Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(0.5)"));
|
||||
Assert.assertEquals("-0.396", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)"));
|
||||
Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)sqrt(2)"));
|
||||
Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)"));
|
||||
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "e^2"));
|
||||
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(1)^2"));
|
||||
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(2)"));
|
||||
Assert.assertEquals("2+i", cm.evaluate(JsclOperation.numeric, "2*1+sqrt(-1)"));
|
||||
Assert.assertEquals("0.921+3.142i", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))"));
|
||||
Assert.assertEquals("7.389i", cm.evaluate(JsclOperation.numeric, "iexp(2)"));
|
||||
Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)"));
|
||||
Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+√(-1)exp(2)"));
|
||||
Assert.assertEquals("2-2.5i", cm.evaluate(JsclOperation.numeric, "2-2.5i"));
|
||||
Assert.assertEquals("-2-2.5i", cm.evaluate(JsclOperation.numeric, "-2-2.5i"));
|
||||
Assert.assertEquals("-2+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i"));
|
||||
Assert.assertEquals("-2+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i"));
|
||||
Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)"));
|
||||
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("si", 5d));
|
||||
|
||||
Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)"));
|
||||
Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si"));
|
||||
Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "sisin(5)si"));
|
||||
Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si"));
|
||||
Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("s", 1d));
|
||||
Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
|
||||
Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "k11"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t", (String)null));
|
||||
Assert.assertEquals("11×t", cm.evaluate(JsclOperation.numeric, "t11"));
|
||||
Assert.assertEquals("11×e×t", cm.evaluate(JsclOperation.numeric, "t11e"));
|
||||
Assert.assertEquals("11×Infinity×t", cm.evaluate(JsclOperation.numeric, "t11∞"));
|
||||
Assert.assertEquals("-t+t^3", cm.evaluate(JsclOperation.numeric, "t(t-1)(t+1)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyFunction() throws Exception {
|
||||
final CalculatorEngine cm = CalculatorEngine.instance;
|
||||
try {
|
||||
cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))");
|
||||
Assert.fail();
|
||||
@ -60,78 +84,28 @@ public class CalculatorEngineTest {
|
||||
Assert.fail();
|
||||
} catch (ParseException e){
|
||||
}
|
||||
Assert.assertEquals("0.73909", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))"));
|
||||
Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("si", 5d));
|
||||
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||
Assert.assertEquals("5", 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"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("s", 1d));
|
||||
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
|
||||
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11"));
|
||||
|
||||
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t", (String)null));
|
||||
Assert.assertEquals("11*t", cm.evaluate(JsclOperation.numeric, "t11"));
|
||||
Assert.assertEquals("11*2.718281828459045*t", cm.evaluate(JsclOperation.numeric, "t11e"));
|
||||
Assert.assertEquals("11*Infinity*t", cm.evaluate(JsclOperation.numeric, "t11∞"));
|
||||
Assert.assertEquals("-t+t^3", cm.evaluate(JsclOperation.numeric, "t(t-1)(t+1)"));
|
||||
}
|
||||
|
||||
public interface TestInterface {
|
||||
Integer getField();
|
||||
}
|
||||
@Test
|
||||
public void testRounding() throws Exception {
|
||||
final CalculatorEngine cm = CalculatorEngine.instance;
|
||||
|
||||
public class TestClass implements TestInterface{
|
||||
cm.setPrecision(2);
|
||||
Assert.assertEquals("12345678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7"));
|
||||
cm.setPrecision(10);
|
||||
Assert.assertEquals("12345678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7"));
|
||||
Assert.assertEquals("123456789", cm.evaluate(JsclOperation.numeric, "1.234567890E8"));
|
||||
Assert.assertEquals("1234567890.1", cm.evaluate(JsclOperation.numeric, "1.2345678901E9"));
|
||||
|
||||
@Attribute(required = true)
|
||||
private Integer field;
|
||||
|
||||
public TestClass() {
|
||||
}
|
||||
|
||||
public TestClass(Integer field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public Integer getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void setField(Integer field) {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
|
||||
public class NewTestClass implements TestInterface{
|
||||
|
||||
@Attribute
|
||||
private Integer field;
|
||||
|
||||
public NewTestClass() {
|
||||
}
|
||||
|
||||
public NewTestClass(Integer field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public Integer getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void setField(Integer field) {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ package org.solovyev.android.calculator.model;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
@ -27,6 +26,17 @@ public class ToJsclTextProcessorTest {
|
||||
public void testProcess() throws Exception {
|
||||
final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor();
|
||||
|
||||
Assert.assertEquals( "", preprocessor.process("").toString());
|
||||
Assert.assertEquals( "()", preprocessor.process("[]").toString());
|
||||
Assert.assertEquals( "()*()", preprocessor.process("[][]").toString());
|
||||
Assert.assertEquals( "()*(1)", preprocessor.process("[][1]").toString());
|
||||
Assert.assertEquals( "(0)*(1)", preprocessor.process("[0][1]").toString());
|
||||
Assert.assertEquals( "(0)*(1*10^)", preprocessor.process("[0][1E]").toString());
|
||||
Assert.assertEquals( "(0)*(1*10^1)", preprocessor.process("[0][1E1]").toString());
|
||||
Assert.assertEquals( "(0)*(1*10^-1)", preprocessor.process("[0][1E-1]").toString());
|
||||
Assert.assertEquals( "(0)*(1.*10^-1)", preprocessor.process("[0][1.E-1]").toString());
|
||||
Assert.assertEquals( "(0)*(2*10^-1)", preprocessor.process("[0][2*E-1]").toString());
|
||||
Assert.assertEquals( "(0)*log(1)*(2*10^-1)", preprocessor.process("[0]ln(1)[2*E-1]").toString());
|
||||
Assert.assertEquals( "sin(4)*asin(0.5)*sqrt(2)", preprocessor.process("sin(4)asin(0.5)sqrt(2)").toString());
|
||||
Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)").toString());
|
||||
Assert.assertEquals( "3.141592653589793*sin(4)*3.141592653589793*cos(sqrt(5))", preprocessor.process("πsin(4)πcos(√(5))").toString());
|
||||
|
Loading…
Reference in New Issue
Block a user