2018-09-02 13:36:49 +02:00
|
|
|
|
package it.cavallium.warppi.math.functions;
|
2016-09-02 20:32:37 +02:00
|
|
|
|
|
2016-12-05 19:58:49 +01:00
|
|
|
|
import java.math.BigDecimal;
|
2016-07-12 22:26:54 +02:00
|
|
|
|
import java.math.BigInteger;
|
2016-12-05 22:57:11 +01:00
|
|
|
|
import java.util.LinkedList;
|
2018-09-02 12:45:51 +02:00
|
|
|
|
|
2019-11-16 01:32:47 +01:00
|
|
|
|
import it.cavallium.warppi.gui.expression.blocks.*;
|
2016-12-05 19:58:49 +01:00
|
|
|
|
import org.nevec.rjm.BigDecimalMath;
|
2017-05-16 22:02:44 +02:00
|
|
|
|
|
2018-09-02 13:36:49 +02:00
|
|
|
|
import it.cavallium.warppi.math.Function;
|
|
|
|
|
import it.cavallium.warppi.math.MathContext;
|
|
|
|
|
import it.cavallium.warppi.math.rules.Rule;
|
2018-09-12 22:16:33 +02:00
|
|
|
|
import it.cavallium.warppi.util.Error;
|
|
|
|
|
import it.cavallium.warppi.util.Utils;
|
2017-05-16 22:02:44 +02:00
|
|
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
2016-07-12 22:26:54 +02:00
|
|
|
|
|
2016-09-19 18:48:27 +02:00
|
|
|
|
public class Number implements Function {
|
2016-07-12 22:26:54 +02:00
|
|
|
|
|
2017-02-14 20:02:03 +01:00
|
|
|
|
private final MathContext root;
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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;
|
2016-12-05 19:58:49 +01:00
|
|
|
|
term = new BigDecimal(val).setScale(Utils.scale, Utils.scaleMode2);
|
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
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;
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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));
|
2016-12-05 19:58:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
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));
|
2016-12-05 19:58:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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) {
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
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) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
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 {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final Number ret = new Number(root, BigDecimalMath.divideRound(getTerm(), f.getTerm()));
|
2016-07-12 22:26:54 +02:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
2018-09-22 11:17:30 +02:00
|
|
|
|
public Number pow(final Number f) throws Error, InterruptedException {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
Number ret = new Number(root, BigDecimal.ONE);
|
2016-12-05 19:58:49 +01:00
|
|
|
|
if (Utils.isIntegerValue(f.term)) {
|
2017-09-15 23:24:12 +02:00
|
|
|
|
final BigInteger bi = f.term.toBigInteger().abs();
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
ret = ret.multiply(new Number(root, getTerm()));
|
2016-12-05 19:58:49 +01:00
|
|
|
|
}
|
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 {
|
2016-12-05 19:58:49 +01:00
|
|
|
|
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() {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final String sWith0 = getTerm().setScale(Utils.displayScale, Utils.scaleMode2).toPlainString();
|
|
|
|
|
final String sExtendedWith0 = getTerm().toPlainString();
|
2016-12-05 19:58:49 +01:00
|
|
|
|
//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("\\.$", "");
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final String sExtended = sExtendedWith0.indexOf(".") < 0 ? sExtendedWith0 : sExtendedWith0.replaceAll("0*$", "").replaceAll("\\.$", "");
|
|
|
|
|
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (sExtended.length() > s.length()) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
s = s + "…";
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
2017-01-17 22:32:40 +01:00
|
|
|
|
if (root.exactMode == false) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final String cuttedNumber = s.split("\\.")[0];
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (cuttedNumber.length() > 8) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
return cuttedNumber.substring(0, 1) + "," + cuttedNumber.substring(1, 8) + "ℯ℮" + (cuttedNumber.length() - 1);
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
2016-12-05 19:58:49 +01:00
|
|
|
|
}
|
|
|
|
|
return s;
|
2016-07-12 22:26:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-09-12 16:30:51 +02:00
|
|
|
|
public Number clone() {
|
2017-02-14 20:02:03 +01:00
|
|
|
|
return new Number(root, term);
|
2016-07-12 22:26:54 +02:00
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
|
2018-10-04 23:39:19 +02:00
|
|
|
|
@Override
|
|
|
|
|
public Number clone(MathContext c) {
|
|
|
|
|
return new Number(c, term);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-18 14:33:25 +02:00
|
|
|
|
@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);
|
2016-09-18 14:33:25 +02:00
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
|
2017-02-02 12:49:31 +01:00
|
|
|
|
public int getNumberOfDecimalPlaces() {
|
2017-04-10 22:50:43 +02:00
|
|
|
|
return Math.max(0, term.stripTrailingZeros().scale());
|
2017-02-02 12:49:31 +01:00
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
|
2017-02-02 12:49:31 +01:00
|
|
|
|
public boolean isInteger() {
|
|
|
|
|
return getNumberOfDecimalPlaces() <= 0;
|
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
2016-09-19 18:48:27 +02:00
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
return toString().hashCode();
|
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
2016-09-19 18:48:27 +02:00
|
|
|
|
@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) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final BigDecimal nav = ((Number) o).getTerm();
|
|
|
|
|
final boolean na1 = term.compareTo(BigDecimal.ZERO) == 0;
|
|
|
|
|
final boolean na2 = nav.compareTo(BigDecimal.ZERO) == 0;
|
2016-11-25 22:40:43 +01:00
|
|
|
|
if (na1 == na2) {
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (na1 == true) {
|
2016-11-25 22:40:43 +01:00
|
|
|
|
return true;
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-11-25 22:40:43 +01:00
|
|
|
|
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
|
2017-02-14 20:02:03 +01:00
|
|
|
|
public MathContext getMathContext() {
|
2017-01-17 22:32:40 +01:00
|
|
|
|
return root;
|
2016-09-19 18:48:27 +02:00
|
|
|
|
}
|
2016-09-18 14:33:25 +02:00
|
|
|
|
|
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;
|
|
|
|
|
* }
|
|
|
|
|
*/
|
2017-01-31 22:29:49 +01:00
|
|
|
|
|
2016-12-05 22:57:11 +01:00
|
|
|
|
public boolean canBeFactorized() {
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (Utils.isIntegerValue(getTerm())) {
|
2016-12-05 22:57:11 +01:00
|
|
|
|
return getTerm().toBigIntegerExact().compareTo(BigInteger.valueOf(1)) > 1;
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
2016-12-05 22:57:11 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-09-24 18:47:30 +02:00
|
|
|
|
|
2017-07-02 23:09:44 +02:00
|
|
|
|
/**
|
|
|
|
|
* @author programmingpraxis
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2017-01-31 22:29:49 +01:00
|
|
|
|
public LinkedList<BigInteger> getFactors() {
|
2016-12-05 22:57:11 +01:00
|
|
|
|
BigInteger n = getTerm().toBigIntegerExact();
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final BigInteger two = BigInteger.valueOf(2);
|
2017-07-24 23:36:43 +02:00
|
|
|
|
final BigInteger zero = BigInteger.ZERO;
|
2017-01-31 22:29:49 +01:00
|
|
|
|
final LinkedList<BigInteger> fs = new LinkedList<>();
|
|
|
|
|
|
2017-07-24 23:36:43 +02:00
|
|
|
|
final int comparedToZero = n.compareTo(zero);
|
|
|
|
|
final int comparedToTwo = n.compareTo(two);
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (comparedToZero == 0) {
|
2017-07-24 23:36:43 +02:00
|
|
|
|
return fs;
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
|
|
|
|
if (comparedToTwo < 0) {
|
|
|
|
|
if (comparedToZero > 0) {
|
2017-07-24 23:36:43 +02:00
|
|
|
|
return fs;
|
2018-09-28 11:39:28 +02:00
|
|
|
|
} else {
|
2017-07-24 23:36:43 +02:00
|
|
|
|
fs.add(BigInteger.valueOf(-1));
|
|
|
|
|
n = n.multiply(BigInteger.valueOf(-1));
|
|
|
|
|
}
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
2017-07-24 23:36:43 +02:00
|
|
|
|
|
2018-09-28 11:39:28 +02:00
|
|
|
|
if (n.compareTo(two) < 0) {
|
2017-09-24 18:47:30 +02:00
|
|
|
|
throw new IllegalArgumentException("must be greater than one");
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
2017-01-31 22:29:49 +01: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) {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
if (n.mod(f).equals(BigInteger.ZERO)) {
|
|
|
|
|
fs.add(f);
|
|
|
|
|
n = n.divide(f);
|
2018-09-28 11:39:28 +02:00
|
|
|
|
} else {
|
2017-01-31 22:29:49 +01:00
|
|
|
|
f = f.add(two);
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-31 22:29:49 +01:00
|
|
|
|
fs.add(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fs;
|
2016-12-05 22:57:11 +01:00
|
|
|
|
}
|
2017-02-14 20:02:03 +01:00
|
|
|
|
|
2017-05-26 22:37:18 +02:00
|
|
|
|
@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();
|
2017-05-26 22:37:18 +02:00
|
|
|
|
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()) {
|
2019-11-16 01:32:47 +01:00
|
|
|
|
result.add(new BlockNumericChar(c));
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
|
|
|
|
for (final char c : numberParts[1].toCharArray()) {
|
2019-11-16 01:32:47 +01:00
|
|
|
|
bpec.appendBlockUnsafe(new BlockNumericChar(c));
|
2018-09-28 11:39:28 +02:00
|
|
|
|
} ;
|
2017-05-26 22:37:18 +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()) {
|
2019-11-16 01:32:47 +01:00
|
|
|
|
result.add(new BlockNumericChar(c));
|
2018-09-28 11:39:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-26 22:37:18 +02:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-06 10:31:34 +02:00
|
|
|
|
@Override
|
2019-08-10 20:51:29 +02:00
|
|
|
|
public <Argument, Result> Result accept(final Function.Visitor<Argument, Result> visitor, final Argument argument) {
|
|
|
|
|
return visitor.visit(this, argument);
|
2018-10-06 10:31:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-14 20:02:03 +01:00
|
|
|
|
@Override
|
2018-09-22 11:17:30 +02:00
|
|
|
|
public Function setParameter(final int index, final Function var) throws IndexOutOfBoundsException {
|
2017-02-14 20:02:03 +01:00
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2018-09-22 11:17:30 +02:00
|
|
|
|
public Function getParameter(final int index) throws IndexOutOfBoundsException {
|
2017-02-14 20:02:03 +01:00
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
|
}
|
2016-07-12 22:26:54 +02:00
|
|
|
|
}
|