2017-07-28 11:38:22 -07:00
|
|
|
package org.nwapw.abacus.number;
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
2017-08-07 17:58:18 -07:00
|
|
|
import java.math.MathContext;
|
2017-07-28 11:38:22 -07:00
|
|
|
|
2017-08-01 10:49:50 -07:00
|
|
|
/**
|
|
|
|
* A number that uses a BigDecimal to store its value,
|
|
|
|
* leading to infinite possible precision.
|
|
|
|
*/
|
2017-08-05 13:54:06 -07:00
|
|
|
public class PreciseNumber extends NumberInterface {
|
2017-07-28 11:38:22 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The number one.
|
|
|
|
*/
|
2017-08-04 09:55:24 -07:00
|
|
|
public static final PreciseNumber ONE = new PreciseNumber(BigDecimal.ONE);
|
2017-07-28 11:38:22 -07:00
|
|
|
/**
|
|
|
|
* The number zero.
|
|
|
|
*/
|
2017-08-04 09:55:24 -07:00
|
|
|
public static final PreciseNumber ZERO = new PreciseNumber(BigDecimal.ZERO);
|
2017-07-28 11:38:22 -07:00
|
|
|
/**
|
|
|
|
* The number ten.
|
|
|
|
*/
|
2017-08-04 09:55:24 -07:00
|
|
|
public static final PreciseNumber TEN = new PreciseNumber(BigDecimal.TEN);
|
2017-07-28 11:38:22 -07:00
|
|
|
|
2017-08-07 17:58:18 -07:00
|
|
|
/**
|
|
|
|
* The number of extra significant figures kept in calculations before rounding for output.
|
|
|
|
*/
|
|
|
|
private static int numExtraInternalSigFigs = 15;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MathContext that is used when rounding a number prior to output.
|
|
|
|
*/
|
|
|
|
private static MathContext outputContext = new MathContext(30);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MathContext that is actually used in calculations.
|
|
|
|
*/
|
|
|
|
private static MathContext internalContext = new MathContext(outputContext.getPrecision()+numExtraInternalSigFigs);
|
|
|
|
|
2017-07-28 14:55:01 -07:00
|
|
|
/**
|
|
|
|
* The value of the PreciseNumber.
|
|
|
|
*/
|
|
|
|
BigDecimal value;
|
2017-07-28 11:38:22 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a precise number from the given string.
|
2017-07-30 21:11:32 -07:00
|
|
|
*
|
2017-07-28 11:38:22 -07:00
|
|
|
* @param string a string representation of the number meeting the same conditions
|
|
|
|
* as the BidDecimal(String) constructor.
|
|
|
|
*/
|
2017-07-30 21:11:32 -07:00
|
|
|
public PreciseNumber(String string) {
|
2017-07-28 11:38:22 -07:00
|
|
|
value = new BigDecimal(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a precise number from the given BigDecimal.
|
2017-07-30 21:11:32 -07:00
|
|
|
*
|
2017-07-28 11:38:22 -07:00
|
|
|
* @param value a BigDecimal object representing the value of the number.
|
|
|
|
*/
|
2017-07-30 21:11:32 -07:00
|
|
|
public PreciseNumber(BigDecimal value) {
|
2017-07-28 11:38:22 -07:00
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-07-28 20:04:13 -07:00
|
|
|
public int getMaxPrecision() {
|
2017-08-07 17:58:18 -07:00
|
|
|
return internalContext.getPrecision();
|
2017-07-28 11:38:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface multiplyInternal(NumberInterface multiplier) {
|
2017-07-31 13:25:23 -07:00
|
|
|
return new PreciseNumber(this.value.multiply(((PreciseNumber) multiplier).value));
|
2017-07-28 11:38:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface divideInternal(NumberInterface divisor) {
|
2017-08-07 17:58:18 -07:00
|
|
|
return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, internalContext));
|
2017-07-28 11:38:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface addInternal(NumberInterface summand) {
|
2017-07-28 11:38:22 -07:00
|
|
|
return new PreciseNumber(value.add(((PreciseNumber) summand).value));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface subtractInternal(NumberInterface subtrahend) {
|
2017-07-28 11:38:22 -07:00
|
|
|
return new PreciseNumber(value.subtract(((PreciseNumber) subtrahend).value));
|
|
|
|
}
|
|
|
|
|
2017-08-05 18:22:43 -07:00
|
|
|
@Override
|
|
|
|
public NumberInterface intPowInternal(int exponent) {
|
|
|
|
if (exponent == 0) {
|
|
|
|
return PreciseNumber.ONE;
|
|
|
|
}
|
|
|
|
boolean takeReciprocal = exponent < 0;
|
|
|
|
exponent = Math.abs(exponent);
|
|
|
|
NumberInterface power = this;
|
|
|
|
for (int currentExponent = 1; currentExponent < exponent; currentExponent++) {
|
|
|
|
power = power.multiply(this);
|
|
|
|
}
|
|
|
|
if (takeReciprocal) {
|
|
|
|
power = PreciseNumber.ONE.divide(power);
|
|
|
|
}
|
|
|
|
return power;
|
|
|
|
}
|
|
|
|
|
2017-07-28 11:38:22 -07:00
|
|
|
@Override
|
|
|
|
public int compareTo(NumberInterface number) {
|
|
|
|
return value.compareTo(((PreciseNumber) number).value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int signum() {
|
|
|
|
return value.signum();
|
|
|
|
}
|
|
|
|
|
2017-07-31 13:25:23 -07:00
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface ceilingInternal() {
|
2017-08-02 12:00:56 -07:00
|
|
|
String str = value.toPlainString();
|
|
|
|
int decimalIndex = str.indexOf('.');
|
2017-08-04 13:20:57 -07:00
|
|
|
if (decimalIndex != -1) {
|
2017-08-02 12:00:56 -07:00
|
|
|
return this.floor().add(ONE);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface floorInternal() {
|
2017-08-02 12:00:56 -07:00
|
|
|
String str = value.toPlainString();
|
|
|
|
int decimalIndex = str.indexOf('.');
|
2017-08-04 13:20:57 -07:00
|
|
|
if (decimalIndex != -1) {
|
2017-08-07 13:41:45 -07:00
|
|
|
NumberInterface floor = new PreciseNumber(str.substring(0, decimalIndex));
|
|
|
|
if(signum() == -1){
|
|
|
|
floor = floor.subtract(ONE);
|
|
|
|
}
|
|
|
|
return floor;
|
2017-08-02 12:00:56 -07:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface fractionalPartInternal() {
|
2017-08-07 13:41:45 -07:00
|
|
|
return this.subtractInternal(floorInternal());
|
2017-07-31 13:25:23 -07:00
|
|
|
}
|
|
|
|
|
2017-08-01 15:36:54 -07:00
|
|
|
@Override
|
2017-08-02 12:00:56 -07:00
|
|
|
public int intValue() {
|
|
|
|
return value.intValue();
|
2017-07-31 13:25:23 -07:00
|
|
|
}
|
|
|
|
|
2017-07-28 11:38:22 -07:00
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface negateInternal() {
|
2017-07-28 11:38:22 -07:00
|
|
|
return new PreciseNumber(value.negate());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-05 13:54:06 -07:00
|
|
|
public NumberInterface promoteToInternal(Class<? extends NumberInterface> toClass) {
|
2017-07-30 21:11:32 -07:00
|
|
|
if (toClass == this.getClass()) {
|
2017-07-28 11:38:22 -07:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2017-08-07 17:58:18 -07:00
|
|
|
return value.round(outputContext).toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public NumberInterface getMaxError(){
|
|
|
|
return new PreciseNumber(value.ulp()).multiplyInternal(TEN.intPowInternal(value.precision()-internalContext.getPrecision()));
|
2017-07-28 11:38:22 -07:00
|
|
|
}
|
|
|
|
}
|