From f5d0fa9d3ba62600600ea2dea4efa6ce15e9f194 Mon Sep 17 00:00:00 2001 From: serso Date: Fri, 21 Oct 2011 00:29:55 +0400 Subject: [PATCH] rounding fix + color display + refactor --- .../android/calculator/CalculatorDisplay.java | 27 +++ .../android/calculator/CalculatorModel.java | 20 +- .../android/calculator/TextHighlighter.java | 6 +- .../jscl/FromJsclNumericTextProcessor.java | 65 +++++- .../android/calculator/math/Functions.java | 6 +- .../android/calculator/math/MathType.java | 209 ++++++++++-------- .../calculator/model/CalculatorEngine.java | 12 +- .../calculator/model/ToJsclTextProcessor.java | 38 +--- .../model/CalculatorEngineTest.java | 136 +++++------- .../model/ToJsclTextProcessorTest.java | 12 +- 10 files changed, 300 insertions(+), 231 deletions(-) diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java index 3dd32d57..bf01d675 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java @@ -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 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); + } + } + } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java index 530fcf07..1c6d2c9b 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java @@ -171,19 +171,20 @@ public enum CalculatorModel implements CursorControl, HistoryControl { 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(""); i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups); result.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); diff --git a/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java b/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java index 216bc897..e1c15bba 100644 --- a/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java @@ -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 { @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 { 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 { // 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 { 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 { 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; + } } + } diff --git a/src/main/java/org/solovyev/android/calculator/math/Functions.java b/src/main/java/org/solovyev/android/calculator/math/Functions.java index ef8d8298..d2e616e4 100644 --- a/src/main/java/org/solovyev/android/calculator/math/Functions.java +++ b/src/main/java/org/solovyev/android/calculator/math/Functions.java @@ -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 allPostfix = Arrays.asList(FACT, DEGREE); + public static final List allPostfix = Arrays.asList(FACT, DEGREE); } diff --git a/src/main/java/org/solovyev/android/calculator/math/MathType.java b/src/main/java/org/solovyev/android/calculator/math/MathType.java index 32739f33..3e1b6752 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -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 getTokens() { + return CalculatorEngine.instance.getVarsRegister().getVarNames(); + } + }, + + text(1200, false, false); + + @NotNull + private final List 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 tokens) { + this.priority = priority; + this.needMultiplicationSignBefore = needMultiplicationSignBefore; + this.needMultiplicationSignAfter = needMultiplicationSignAfter; + this.tokens = Collections.unmodifiableList(tokens); + } + + @NotNull + public List 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 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 constants = Arrays.asList(E, PI, IMAGINARY_NUMBER, NAN, INFINITY); - public static final List digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); - - public static final List dots = Arrays.asList('.'); - - - public static final List unaryOperations = Arrays.asList('-', '=', '!'); - - public static final List binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^'); - - public static final List prefixFunctions = Functions.allPrefix; - - public static final List postfixFunctions = Functions.allPostfix; - - public static final List groupSymbols = Arrays.asList("[]", "()", "{}"); - - public static final List openGroupSymbols = Arrays.asList('[', '(', '{'); - - public static final List 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 mathTypesByPriority; + + @NotNull + private static List getMathTypesByPriority() { + if ( mathTypesByPriority == null ) { + final List result = CollectionsUtils.asList(MathType.values()); + + Collections.sort(result, new Comparator() { + @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; diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java index 97daf5d5..215372f2 100644 --- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java @@ -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 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 integerNumberMapper = new NumberMapper(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); diff --git a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java index 2ad284d8..7215bc30 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java @@ -50,7 +50,7 @@ class ToJsclTextProcessor implements TextProcessor { // 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 { 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 { 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 { 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 { @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("*"); } } diff --git a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java index cede9000..b57f5ba0 100644 --- a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java @@ -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; - } } } diff --git a/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java b/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java index b82fa384..5031baeb 100644 --- a/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java @@ -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());