diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/ExpressionFunction.java b/app/src/main/java/org/solovyev/android/calculator/plot/ExpressionFunction.java index 377560ac..15b693e7 100644 --- a/app/src/main/java/org/solovyev/android/calculator/plot/ExpressionFunction.java +++ b/app/src/main/java/org/solovyev/android/calculator/plot/ExpressionFunction.java @@ -93,7 +93,7 @@ public class ExpressionFunction extends Function { public float unwrap(Numeric content) { if (content instanceof Real) { - return (float) ((Real) content).doubleValue(); + return (float) content.doubleValue(); } if (content instanceof Complex) { return (float) (imaginary ? ((Complex) content).imaginaryPart() : ((Complex) content).realPart()); diff --git a/jscl/src/main/java/jscl/math/Expression.java b/jscl/src/main/java/jscl/math/Expression.java index 63d94eef..6a9759c5 100644 --- a/jscl/src/main/java/jscl/math/Expression.java +++ b/jscl/src/main/java/jscl/math/Expression.java @@ -512,7 +512,9 @@ public class Expression extends Generic { for (int j = 0; j < literal.size(); j++) { final Variable variable = literal.getVariable(j); - Generic b = content.get(variable).pow(literal.getPower(j)); + final int power = literal.getPower(j); + final Generic contentVariable = content.get(variable); + Generic b = pow(contentVariable, power); if (Matrix.isMatrixProduct(sumElement, b)) { throw new ArithmeticException("Should not be matrix!"); @@ -527,6 +529,18 @@ public class Expression extends Generic { return sum; } + @Nonnull + private Generic pow(@Nonnull Generic g, int power) { + switch (power) { + case 0: + return JsclInteger.valueOf(1); + case 1: + return g; + default: + return g.pow(power); + } + } + public Generic expand() { return substitute(literalScm().content(EXPAND_CONVERTER)); } diff --git a/jscl/src/main/java/jscl/math/JsclInteger.java b/jscl/src/main/java/jscl/math/JsclInteger.java index 5339e192..a8fc3efa 100644 --- a/jscl/src/main/java/jscl/math/JsclInteger.java +++ b/jscl/src/main/java/jscl/math/JsclInteger.java @@ -46,6 +46,9 @@ public final class JsclInteger extends Generic { @Nonnull public Generic add(@Nonnull Generic that) { + if (isZero()) { + return that; + } if (that instanceof JsclInteger) { return add((JsclInteger) that); } else { @@ -53,8 +56,15 @@ public final class JsclInteger extends Generic { } } - public JsclInteger subtract(JsclInteger integer) { - return new JsclInteger(content.subtract(integer.content)); + private boolean isZero() { + return content.equals(ZERO.content); + } + + public JsclInteger subtract(JsclInteger that) { + if(isZero()) { + return that.negate(); + } + return new JsclInteger(content.subtract(that.content)); } @Nonnull @@ -72,6 +82,9 @@ public final class JsclInteger extends Generic { @Nonnull public Generic multiply(@Nonnull Generic that) { + if (isOne()) { + return that; + } if (that instanceof JsclInteger) { return multiply((JsclInteger) that); } else { @@ -79,7 +92,14 @@ public final class JsclInteger extends Generic { } } + private boolean isOne() { + return content.equals(ONE.content); + } + public JsclInteger divide(@Nonnull JsclInteger that) { + if (isZero()) { + return ZERO; + } JsclInteger e[] = divideAndRemainder(that); if (e[1].signum() == 0) { return e[0]; @@ -149,7 +169,7 @@ public final class JsclInteger extends Generic { return new JsclInteger(content.pow(exponent)); } - public Generic negate() { + public JsclInteger negate() { return new JsclInteger(content.negate()); } diff --git a/jscl/src/main/java/jscl/math/Literal.java b/jscl/src/main/java/jscl/math/Literal.java index 0db4bcf6..66fa9f52 100644 --- a/jscl/src/main/java/jscl/math/Literal.java +++ b/jscl/src/main/java/jscl/math/Literal.java @@ -8,6 +8,7 @@ import jscl.mathml.MathML; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -382,7 +383,7 @@ public class Literal implements Comparable { } Map content(@Nonnull Function c) { - final Map result = new TreeMap(); + final Map result = new HashMap<>(size); for (int i = 0; i < size; i++) { result.put(variables[i], c.apply(variables[i])); diff --git a/jscl/src/main/java/jscl/math/function/CustomFunction.java b/jscl/src/main/java/jscl/math/function/CustomFunction.java index 45674cb3..cd4c2b6a 100644 --- a/jscl/src/main/java/jscl/math/function/CustomFunction.java +++ b/jscl/src/main/java/jscl/math/function/CustomFunction.java @@ -1,5 +1,6 @@ package jscl.math.function; +import com.google.common.collect.Lists; import jscl.CustomFunctionCalculationException; import jscl.JsclMathEngine; import jscl.math.*; @@ -15,18 +16,17 @@ import java.util.concurrent.atomic.AtomicInteger; public class CustomFunction extends Function implements IFunction { - private static final String LOCAL_VAR_POSTFIX = "_lv_09_03_1988_"; - private final static AtomicInteger counter = new AtomicInteger(0); - @Nonnull - private final Integer localVarId; + private final int id; @Nonnull private Expression content; @Nullable private String description; @Nonnull private List parameterNames = Collections.emptyList(); + @Nullable + private List parameterConstants; private CustomFunction(@Nonnull String name, @Nonnull List parameterNames, @@ -36,7 +36,18 @@ public class CustomFunction extends Function implements IFunction { this.parameterNames = parameterNames; this.content = content; this.description = description; - this.localVarId = counter.incrementAndGet(); + this.id = counter.incrementAndGet(); + } + + @Nonnull + private List makeParameterConstants(@Nonnull List names) { + return new ArrayList<>(Lists.transform(names, new com.google.common.base.Function() { + @Nullable + @Override + public ConstantData apply(@Nullable String name) { + return new ConstantData(name); + } + })); } private CustomFunction(@Nonnull String name, @@ -51,7 +62,7 @@ public class CustomFunction extends Function implements IFunction { throw new CustomFunctionCalculationException(this, e); } this.description = description; - this.localVarId = counter.incrementAndGet(); + this.id = counter.incrementAndGet(); } @Override @@ -91,29 +102,27 @@ public class CustomFunction extends Function implements IFunction { @Override public Generic selfExpand() { - Generic localContent = content; - - try { - for (String parameterName : parameterNames) { - localContent = localContent.substitute(new Constant(parameterName), Expression.valueOf(new Constant(getParameterNameForConstant(parameterName)))); - } - - for (int i = 0; i < parameterNames.size(); i++) { - localContent = localContent.substitute(new Constant(getParameterNameForConstant(parameterNames.get(i))), parameters[i]); - } - - } finally { - for (String parameterName : parameterNames) { - localContent = localContent.substitute(new Constant(getParameterNameForConstant(parameterName)), Expression.valueOf(new Constant(parameterName))); - } + Generic content = this.content; + final List parameterConstants = getParameterConstants(); + for (ConstantData cd : parameterConstants) { + content = content.substitute(cd.local, cd.globalExpression); } - - return localContent; + for (int i = 0; i < parameterConstants.size(); i++) { + final ConstantData cd = parameterConstants.get(i); + content = content.substitute(cd.global, parameters[i]); + } + for (ConstantData cd : parameterConstants) { + content = content.substitute(cd.global, cd.localExpression); + } + return content; } @Nonnull - private String getParameterNameForConstant(@Nonnull String parameterName) { - return parameterName + LOCAL_VAR_POSTFIX + "_" + this.localVarId; + private List getParameterConstants() { + if(parameterConstants == null) { + parameterConstants = makeParameterConstants(parameterNames); + } + return parameterConstants; } @Override @@ -328,4 +337,22 @@ public class CustomFunction extends Function implements IFunction { return customFunction; } } + + private final class ConstantData { + @Nonnull + final Constant global; + @Nonnull + final Constant local; + @Nonnull + final Generic globalExpression; + @Nonnull + final Generic localExpression; + + public ConstantData(@Nonnull String name) { + global = new Constant(name + "#" + id); + globalExpression = Expression.valueOf(global); + local = new Constant(name); + localExpression = Expression.valueOf(local); + } + } }