Andrea Cavalli
4c29eeb31c
Fixed implicit multiplication symbols, zoom is now 1x, debug steps are printed, fixed missing numeric chars, changed RootSquare base class to FunctionSingle, added two hardcoded multiplication rules, added rootsquarerule, isolated the swing engine from the window, added 2 Fractions rules and 1 exponent rule
287 lines
7.7 KiB
Java
287 lines
7.7 KiB
Java
package it.cavallium.warppi.math.functions;
|
||
|
||
import java.math.BigDecimal;
|
||
import java.math.BigInteger;
|
||
import java.util.LinkedList;
|
||
|
||
import it.cavallium.warppi.gui.expression.blocks.*;
|
||
import org.nevec.rjm.BigDecimalMath;
|
||
|
||
import it.cavallium.warppi.math.Function;
|
||
import it.cavallium.warppi.math.MathContext;
|
||
import it.cavallium.warppi.math.rules.Rule;
|
||
import it.cavallium.warppi.util.Error;
|
||
import it.cavallium.warppi.util.Utils;
|
||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||
|
||
public class Number implements Function {
|
||
|
||
private final MathContext root;
|
||
protected BigDecimal term;
|
||
|
||
public Number(final MathContext root, final BigInteger val) {
|
||
this.root = root;
|
||
term = new BigDecimal(val).setScale(Utils.scale, Utils.scaleMode2);
|
||
}
|
||
|
||
public Number(final MathContext root, final BigDecimal val) {
|
||
this.root = root;
|
||
term = val.setScale(Utils.scale, Utils.scaleMode2);
|
||
}
|
||
|
||
public Number(final MathContext root, final String s) throws Error {
|
||
this(root, new BigDecimal(s).setScale(Utils.scale, Utils.scaleMode2));
|
||
}
|
||
|
||
public Number(final MathContext root, final int s) {
|
||
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
|
||
}
|
||
|
||
public Number(final MathContext root, final float s) {
|
||
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
|
||
}
|
||
|
||
public Number(final MathContext root, final double s) {
|
||
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
|
||
}
|
||
|
||
/**
|
||
* Copy
|
||
* @param n
|
||
* @param newContext
|
||
*/
|
||
public Number(Number old, MathContext newContext) {
|
||
this.root = newContext;
|
||
this.term = old.term;
|
||
}
|
||
|
||
public BigDecimal getTerm() {
|
||
return term;
|
||
}
|
||
|
||
public void setTerm(final BigDecimal val) {
|
||
term = val.setScale(Utils.scale, Utils.scaleMode2);
|
||
}
|
||
|
||
public Number add(final Number f) {
|
||
final Number ret = new Number(root, getTerm().add(f.getTerm()));
|
||
return ret;
|
||
}
|
||
|
||
public Number multiply(final Number f) {
|
||
final Number ret = new Number(root, getTerm().multiply(f.getTerm()));
|
||
return ret;
|
||
}
|
||
|
||
public Number divide(final Number f) throws Error {
|
||
final Number ret = new Number(root, BigDecimalMath.divideRound(getTerm(), f.getTerm()));
|
||
return ret;
|
||
}
|
||
|
||
public Number pow(final Number f) throws Error, InterruptedException {
|
||
Number ret = new Number(root, BigDecimal.ONE);
|
||
if (Utils.isIntegerValue(f.term)) {
|
||
final BigInteger bi = f.term.toBigInteger().abs();
|
||
for (BigInteger i = BigInteger.ZERO; i.compareTo(bi) < 0; i = i.add(BigInteger.ONE)) {
|
||
if (Thread.interrupted()) {
|
||
throw new InterruptedException();
|
||
}
|
||
ret = ret.multiply(new Number(root, getTerm()));
|
||
}
|
||
if (f.term.signum() == -1) {
|
||
ret = new Number(root, 1).divide(ret);
|
||
}
|
||
} else {
|
||
ret.term = BigDecimalMath.pow(term, f.term);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
@Override
|
||
public String toString() {
|
||
final String sWith0 = getTerm().setScale(Utils.displayScale, Utils.scaleMode2).toPlainString();
|
||
final String sExtendedWith0 = getTerm().toPlainString();
|
||
//Remove trailing zeroes. Thanks to Kent, http://stackoverflow.com/questions/14984664/remove-trailing-zero-in-java
|
||
String s = sWith0.indexOf(".") < 0 ? sWith0 : sWith0.replaceAll("0*$", "").replaceAll("\\.$", "");
|
||
final String sExtended = sExtendedWith0.indexOf(".") < 0 ? sExtendedWith0 : sExtendedWith0.replaceAll("0*$", "").replaceAll("\\.$", "");
|
||
|
||
if (sExtended.length() > s.length()) {
|
||
s = s + "…";
|
||
}
|
||
|
||
if (root.exactMode == false) {
|
||
final String cuttedNumber = s.split("\\.")[0];
|
||
if (cuttedNumber.length() > 8) {
|
||
return cuttedNumber.substring(0, 1) + "," + cuttedNumber.substring(1, 8) + "ℯ℮" + (cuttedNumber.length() - 1);
|
||
}
|
||
}
|
||
return s;
|
||
}
|
||
|
||
@Override
|
||
public Number clone() {
|
||
return new Number(root, term);
|
||
}
|
||
|
||
@Override
|
||
public Number clone(MathContext c) {
|
||
return new Number(c, term);
|
||
}
|
||
|
||
@Override
|
||
public ObjectArrayList<Function> simplify(final Rule rule) throws Error, InterruptedException {
|
||
return rule.execute(this);
|
||
}
|
||
|
||
public int getNumberOfDecimalPlaces() {
|
||
return Math.max(0, term.stripTrailingZeros().scale());
|
||
}
|
||
|
||
public boolean isInteger() {
|
||
return getNumberOfDecimalPlaces() <= 0;
|
||
}
|
||
|
||
@Override
|
||
public int hashCode() {
|
||
return toString().hashCode();
|
||
}
|
||
|
||
@Override
|
||
public boolean equals(final Object o) {
|
||
if (o != null & term != null) {
|
||
if (o instanceof Number) {
|
||
final BigDecimal nav = ((Number) o).getTerm();
|
||
final boolean na1 = term.compareTo(BigDecimal.ZERO) == 0;
|
||
final boolean na2 = nav.compareTo(BigDecimal.ZERO) == 0;
|
||
if (na1 == na2) {
|
||
if (na1 == true) {
|
||
return true;
|
||
}
|
||
} else {
|
||
return false;
|
||
}
|
||
return nav.compareTo(term) == 0;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
@Override
|
||
public MathContext getMathContext() {
|
||
return root;
|
||
}
|
||
|
||
/*
|
||
* @Override
|
||
* public void draw(int x, int y, Graphics g) {
|
||
* }
|
||
*
|
||
* @Override
|
||
* public int getHeight() {
|
||
* return Utils.getFontHeight();
|
||
* }
|
||
*
|
||
* @Override
|
||
* public int getWidth() {
|
||
* return 6*toString().length()-1;
|
||
* }
|
||
*/
|
||
|
||
public boolean canBeFactorized() {
|
||
if (Utils.isIntegerValue(getTerm())) {
|
||
return getTerm().toBigIntegerExact().compareTo(BigInteger.valueOf(1)) > 1;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* @author programmingpraxis
|
||
* @return
|
||
*/
|
||
public LinkedList<BigInteger> getFactors() {
|
||
BigInteger n = getTerm().toBigIntegerExact();
|
||
final BigInteger two = BigInteger.valueOf(2);
|
||
final BigInteger zero = BigInteger.ZERO;
|
||
final LinkedList<BigInteger> fs = new LinkedList<>();
|
||
|
||
final int comparedToZero = n.compareTo(zero);
|
||
final int comparedToTwo = n.compareTo(two);
|
||
if (comparedToZero == 0) {
|
||
return fs;
|
||
}
|
||
if (comparedToTwo < 0) {
|
||
if (comparedToZero > 0) {
|
||
return fs;
|
||
} else {
|
||
fs.add(BigInteger.valueOf(-1));
|
||
n = n.multiply(BigInteger.valueOf(-1));
|
||
}
|
||
}
|
||
|
||
if (n.compareTo(two) < 0) {
|
||
throw new IllegalArgumentException("must be greater than one");
|
||
}
|
||
|
||
while (n.mod(two).equals(BigInteger.ZERO)) {
|
||
fs.add(two);
|
||
n = n.divide(two);
|
||
}
|
||
|
||
if (n.compareTo(BigInteger.ONE) > 0) {
|
||
BigInteger f = BigInteger.valueOf(3);
|
||
while (f.compareTo(Utils.maxFactor) <= 0 && f.multiply(f).compareTo(n) <= 0) {
|
||
if (n.mod(f).equals(BigInteger.ZERO)) {
|
||
fs.add(f);
|
||
n = n.divide(f);
|
||
} else {
|
||
f = f.add(two);
|
||
}
|
||
}
|
||
fs.add(n);
|
||
}
|
||
|
||
return fs;
|
||
}
|
||
|
||
@Override
|
||
public ObjectArrayList<Block> toBlock(final MathContext context) {
|
||
final ObjectArrayList<Block> result = new ObjectArrayList<>();
|
||
final String numberString = toString();
|
||
if (numberString.contains("ℯ℮")) {
|
||
final String[] numberParts = numberString.split("ℯ℮", 2);
|
||
final BlockPower bp = new BlockExponentialNotation();
|
||
final BlockContainer bpec = bp.getExponentContainer();
|
||
for (final char c : numberParts[0].toCharArray()) {
|
||
result.add(new BlockNumericChar(c));
|
||
}
|
||
for (final char c : numberParts[1].toCharArray()) {
|
||
bpec.appendBlockUnsafe(new BlockNumericChar(c));
|
||
} ;
|
||
bpec.recomputeDimensions();
|
||
bp.recomputeDimensions();
|
||
result.add(bp);
|
||
return result;
|
||
} else {
|
||
for (final char c : numberString.toCharArray()) {
|
||
result.add(new BlockNumericChar(c));
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
public <Argument, Result> Result accept(final Function.Visitor<Argument, Result> visitor, final Argument argument) {
|
||
return visitor.visit(this, argument);
|
||
}
|
||
|
||
@Override
|
||
public Function setParameter(final int index, final Function var) throws IndexOutOfBoundsException {
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
@Override
|
||
public Function getParameter(final int index) throws IndexOutOfBoundsException {
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
}
|