WarpPI/core/src/main/java/it/cavallium/warppi/math/functions/Number.java

287 lines
7.7 KiB
Java
Raw Normal View History

package it.cavallium.warppi.math.functions;
2016-09-02 20:32:37 +02:00
import java.math.BigDecimal;
2016-07-12 22:26:54 +02:00
import java.math.BigInteger;
import java.util.LinkedList;
2018-09-02 12:45:51 +02:00
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;
2016-07-12 22:26:54 +02:00
public class Number implements Function {
2016-07-12 22:26:54 +02:00
private final MathContext root;
protected BigDecimal term;
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final BigInteger val) {
2017-01-17 22:32:40 +01:00
this.root = root;
term = new BigDecimal(val).setScale(Utils.scale, Utils.scaleMode2);
}
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final BigDecimal val) {
2017-01-17 22:32:40 +01:00
this.root = root;
term = val.setScale(Utils.scale, Utils.scaleMode2);
2016-07-12 22:26:54 +02:00
}
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final String s) throws Error {
2017-01-17 22:32:40 +01:00
this(root, new BigDecimal(s).setScale(Utils.scale, Utils.scaleMode2));
2016-07-12 22:26:54 +02:00
}
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final int s) {
2017-01-17 22:32:40 +01:00
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
2016-07-12 22:26:54 +02:00
}
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final float s) {
2017-01-17 22:32:40 +01:00
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
}
2018-09-22 11:17:30 +02:00
public Number(final MathContext root, final double s) {
2017-01-17 22:32:40 +01:00
this(root, BigDecimal.valueOf(s).setScale(Utils.scale, Utils.scaleMode2));
}
2018-10-04 23:39:19 +02:00
/**
* Copy
* @param n
* @param newContext
*/
public Number(Number old, MathContext newContext) {
this.root = newContext;
this.term = old.term;
}
public BigDecimal getTerm() {
2016-07-12 22:26:54 +02:00
return term;
}
2018-09-22 11:17:30 +02:00
public void setTerm(final BigDecimal val) {
term = val.setScale(Utils.scale, Utils.scaleMode2);
2016-07-12 22:26:54 +02:00
}
2018-09-22 11:17:30 +02:00
public Number add(final Number f) {
final Number ret = new Number(root, getTerm().add(f.getTerm()));
2016-07-12 22:26:54 +02:00
return ret;
}
2018-09-22 11:17:30 +02:00
public Number multiply(final Number f) {
final Number ret = new Number(root, getTerm().multiply(f.getTerm()));
2016-07-12 22:26:54 +02:00
return ret;
}
2018-09-22 11:17:30 +02:00
public Number divide(final Number f) throws Error {
final Number ret = new Number(root, BigDecimalMath.divideRound(getTerm(), f.getTerm()));
2016-07-12 22:26:54 +02:00
return ret;
}
2018-09-22 11:17:30 +02:00
public Number pow(final Number f) throws Error, InterruptedException {
Number ret = new Number(root, BigDecimal.ONE);
if (Utils.isIntegerValue(f.term)) {
2017-09-15 23:24:12 +02:00
final BigInteger bi = f.term.toBigInteger().abs();
for (BigInteger i = BigInteger.ZERO; i.compareTo(bi) < 0; i = i.add(BigInteger.ONE)) {
2018-09-28 11:39:28 +02:00
if (Thread.interrupted()) {
2018-05-12 21:18:29 +02:00
throw new InterruptedException();
2018-09-28 11:39:28 +02:00
}
ret = ret.multiply(new Number(root, getTerm()));
}
2018-09-28 11:39:28 +02:00
if (f.term.signum() == -1) {
2017-09-15 23:24:12 +02:00
ret = new Number(root, 1).divide(ret);
2018-09-28 11:39:28 +02:00
}
} else {
ret.term = BigDecimalMath.pow(term, f.term);
2018-09-28 11:39:28 +02:00
}
2016-07-12 22:26:54 +02:00
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("\\.$", "");
2018-09-28 11:39:28 +02:00
if (sExtended.length() > s.length()) {
s = s + "…";
2018-09-28 11:39:28 +02:00
}
2017-01-17 22:32:40 +01:00
if (root.exactMode == false) {
final String cuttedNumber = s.split("\\.")[0];
2018-09-28 11:39:28 +02:00
if (cuttedNumber.length() > 8) {
return cuttedNumber.substring(0, 1) + "," + cuttedNumber.substring(1, 8) + "ℯ℮" + (cuttedNumber.length() - 1);
2018-09-28 11:39:28 +02:00
}
}
return s;
2016-07-12 22:26:54 +02:00
}
@Override
public Number clone() {
return new Number(root, term);
2016-07-12 22:26:54 +02:00
}
2018-10-04 23:39:19 +02:00
@Override
public Number clone(MathContext c) {
return new Number(c, term);
}
@Override
2018-09-22 11:17:30 +02:00
public ObjectArrayList<Function> simplify(final Rule rule) throws Error, InterruptedException {
2017-12-22 22:39:58 +01:00
return rule.execute(this);
}
2017-02-02 12:49:31 +01:00
public int getNumberOfDecimalPlaces() {
return Math.max(0, term.stripTrailingZeros().scale());
2017-02-02 12:49:31 +01:00
}
2017-02-02 12:49:31 +01:00
public boolean isInteger() {
return getNumberOfDecimalPlaces() <= 0;
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
2018-09-22 11:17:30 +02:00
public boolean equals(final Object o) {
2018-09-28 11:39:28 +02:00
if (o != null & term != null) {
2016-11-02 21:56:40 +01:00
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) {
2018-09-28 11:39:28 +02:00
if (na1 == true) {
return true;
2018-09-28 11:39:28 +02:00
}
} else {
return false;
2018-09-28 11:39:28 +02:00
}
2016-11-02 21:56:40 +01:00
return nav.compareTo(term) == 0;
}
2018-09-28 11:39:28 +02:00
}
2016-11-02 21:56:40 +01:00
return false;
}
@Override
public MathContext getMathContext() {
2017-01-17 22:32:40 +01:00
return root;
}
2016-09-02 20:32:37 +02:00
/*
* @Override
* public void draw(int x, int y, Graphics g) {
* }
2018-09-22 11:17:30 +02:00
*
2016-09-02 20:32:37 +02:00
* @Override
* public int getHeight() {
* return Utils.getFontHeight();
* }
2018-09-22 11:17:30 +02:00
*
2016-09-02 20:32:37 +02:00
* @Override
* public int getWidth() {
* return 6*toString().length()-1;
* }
*/
public boolean canBeFactorized() {
2018-09-28 11:39:28 +02:00
if (Utils.isIntegerValue(getTerm())) {
return getTerm().toBigIntegerExact().compareTo(BigInteger.valueOf(1)) > 1;
2018-09-28 11:39:28 +02:00
}
return false;
}
2017-07-02 23:09:44 +02:00
/**
* @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);
2018-09-28 11:39:28 +02:00
if (comparedToZero == 0) {
return fs;
2018-09-28 11:39:28 +02:00
}
if (comparedToTwo < 0) {
if (comparedToZero > 0) {
return fs;
2018-09-28 11:39:28 +02:00
} else {
fs.add(BigInteger.valueOf(-1));
n = n.multiply(BigInteger.valueOf(-1));
}
2018-09-28 11:39:28 +02:00
}
2018-09-28 11:39:28 +02:00
if (n.compareTo(two) < 0) {
throw new IllegalArgumentException("must be greater than one");
2018-09-28 11:39:28 +02:00
}
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);
2018-09-28 11:39:28 +02:00
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);
2018-09-28 11:39:28 +02:00
} else {
f = f.add(two);
2018-09-28 11:39:28 +02:00
}
}
fs.add(n);
}
return fs;
}
@Override
2018-09-22 11:17:30 +02:00
public ObjectArrayList<Block> toBlock(final MathContext context) {
2018-05-12 21:18:29 +02:00
final ObjectArrayList<Block> result = new ObjectArrayList<>();
final String numberString = toString();
if (numberString.contains("ℯ℮")) {
2018-05-12 21:18:29 +02:00
final String[] numberParts = numberString.split("ℯ℮", 2);
final BlockPower bp = new BlockExponentialNotation();
final BlockContainer bpec = bp.getExponentContainer();
2018-09-28 11:39:28 +02:00
for (final char c : numberParts[0].toCharArray()) {
result.add(new BlockNumericChar(c));
2018-09-28 11:39:28 +02:00
}
for (final char c : numberParts[1].toCharArray()) {
bpec.appendBlockUnsafe(new BlockNumericChar(c));
2018-09-28 11:39:28 +02:00
} ;
bpec.recomputeDimensions();
bp.recomputeDimensions();
result.add(bp);
return result;
2018-09-28 11:39:28 +02:00
} else {
for (final char c : numberString.toCharArray()) {
result.add(new BlockNumericChar(c));
2018-09-28 11:39:28 +02:00
}
}
return result;
}
@Override
public <Argument, Result> Result accept(final Function.Visitor<Argument, Result> visitor, final Argument argument) {
return visitor.visit(this, argument);
}
@Override
2018-09-22 11:17:30 +02:00
public Function setParameter(final int index, final Function var) throws IndexOutOfBoundsException {
throw new IndexOutOfBoundsException();
}
@Override
2018-09-22 11:17:30 +02:00
public Function getParameter(final int index) throws IndexOutOfBoundsException {
throw new IndexOutOfBoundsException();
}
2016-07-12 22:26:54 +02:00
}