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

287 lines
7.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}