All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.obermuhlner.math.big.BigFloat Maven / Gradle / Ivy

There is a newer version: 2.3.2
Show newest version
package ch.obermuhlner.math.big;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Objects;

/**
 * A wrapper around {@link BigDecimal} which simplifies the consistent usage of the {@link MathContext}
 * and provides a simpler API for calculations.
 *
 * 

Overview

* *

Every {@link BigFloat} instance has a reference to a {@link Context} that specifies the {@link MathContext} to be used for all calculations and values.

* *

The API for calculations is simplified and more consistent with the typical mathematical usage.

*
    *
  • Factory methods for values: *
      *
    • valueOf(BigFloat)
    • *
    • valueOf(BigDecimal)
    • *
    • valueOf(int)
    • *
    • valueOf(long)
    • *
    • valueOf(double)
    • *
    • valueOf(String)
    • *
    • pi()
    • *
    • e()
    • *
    *
  • *
  • All standard operators: *
      *
    • add(x)
    • *
    • subtract(x)
    • *
    • multiply(x)
    • *
    • remainder(x)
    • *
    • pow(y)
    • *
    • root(y)
    • *
    *
  • *
  • Calculation methods are overloaded for different value types: *
      *
    • add(BigFloat)
    • *
    • add(BigDecimal)
    • *
    • add(int)
    • *
    • add(long)
    • *
    • add(double)
    • *
    • ...
    • *
    *
  • *
  • Mathematical functions are written as they are traditionally are written: *
      *
    • abs(x)
    • *
    • log(x)
    • *
    • sin(x)
    • *
    • min(x1, x2, ...)
    • *
    • max(x1, x2, ...)
    • *
    • ...
    • *
    *
  • *
  • Support for advanced mathematical functions: *
      *
    • sqrt(x)
    • *
    • log(x)
    • *
    • exp(x)
    • *
    • sin(x)
    • *
    • cos(x)
    • *
    • tan(x)
    • *
    • ...
    • *
    *
  • *
  • Methods to access parts of a value: *
      *
    • getMantissa()
    • *
    • getExponent()
    • *
    • getIntegralPart()
    • *
    • getFractionalPart()
    • *
    *
  • *
  • Equals and Hashcode methods: *
      *
    • equals(Object) that returns whether two BigFloat values are mathematically the same
    • *
    • hashCode() consistent with equals(Object)
    • *
    *
  • *
  • Comparison methods: *
      *
    • isEqual(BigFloat)
    • *
    • isLessThan(BigFloat)
    • *
    • isLessThanOrEqual(BigFloat)
    • *
    • isGreaterThan(BigFloat)
    • *
    • isGreaterThanOrEqual(BigFloat)
    • *
    *
  • *
* *

Usage

* *

Before doing any calculations you need to create a Context specifying the precision used for all calculations.

*
 * Context context = BigFloat.context(100); // precision of 100 digits
 * Context anotherContext = BigFloat.context(new MathContext(10, RoundingMode.HALF_UP); // precision of 10 digits, rounding half up
 * 
* *

The Context can then be used to create the first value of the calculation:

*
 * BigFloat value1 = context.valueOf(640320);
 * 
* *

The BigFloat instance holds a reference to the Context. This context is then passed from calculation to calculation.

*
 * BigFloat value2 = context.valueOf(640320).pow(3).divide(24);
 * BigFloat value3 = BigFloat.sin(value2);
 * 
* *

The BigFloat result can be converted to other numerical types:

*
 * BigDecimal bigDecimalValue = value3.toBigDecimal();
 * double doubleValue = value3.toDouble();
 * long longValue = value3.toLong();
 * int intValue = value3.toInt();
 * 
*/ @SuppressWarnings("WeakerAccess") public class BigFloat implements Comparable, Serializable { private static final long serialVersionUID = -7323679117445486894L; /** * Represents a value that is not a number. * @see Double#NaN */ public static final BigFloat NaN = new SpecialBigFloat(SpecialBigFloat.Type.NaN); /** * Represents the positive infinity. * @see Double#POSITIVE_INFINITY */ public static final BigFloat POSITIVE_INFINITY = new SpecialBigFloat(SpecialBigFloat.Type.POSITIVE_INFINITY); /** * Represents the positive infinity. * @see Double#NEGATIVE_INFINITY */ public static final BigFloat NEGATIVE_INFINITY = new SpecialBigFloat(SpecialBigFloat.Type.NEGATIVE_INFINITY); private final BigDecimal value; private final Context context; private BigFloat(BigDecimal value, Context context) { this.value = value; this.context = context; } /** * Creates a {@link Context} with the specified precision and {@link RoundingMode#HALF_UP} rounding. * * @param precision the precision * * @return the {@link Context} */ public static Context context(int precision) { return new Context(new MathContext(precision)); } /** * Creates a {@link Context} with the specified {@link MathContext}. * * @param mathContext the {@link MathContext} * * @return the {@link Context} */ public static Context context(MathContext mathContext) { return new Context(mathContext); } /** * Returns the {@link BigFloat} that is this + x. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the value to add * * @return the resulting {@link BigFloat} * * @see BigDecimal#add(BigDecimal, MathContext) */ public BigFloat add(BigFloat x) { if (x.isSpecial()) return x.add(this); Context c = max(context, x.context); return c.valueOf(value.add(x.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is this + x. * * @param x the value to add * * @return the resulting {@link BigFloat} * * @see BigDecimal#add(BigDecimal, MathContext) */ public BigFloat add(BigDecimal x) { return add(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this + x. * * @param x the value to add * * @return the resulting {@link BigFloat} * * @see BigDecimal#add(BigDecimal, MathContext) */ public BigFloat add(int x) { return add(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this + x. * * @param x the value to add * * @return the resulting {@link BigFloat} * * @see BigDecimal#add(BigDecimal, MathContext) */ public BigFloat add(long x) { return add(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this + x. * * @param x the value to add * * @return the resulting {@link BigFloat} * * @see BigDecimal#add(BigDecimal, MathContext) */ public BigFloat add(double x) { return add(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this - x. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the value to subtract * * @return the resulting {@link BigFloat} * * @see BigDecimal#subtract(BigDecimal, MathContext) */ public BigFloat subtract(BigFloat x) { if (x.isSpecial()) return negate(x).add(this); Context c = max(context, x.context); return c.valueOf(value.subtract(x.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is this - x. * * @param x the value to subtract * * @return the resulting {@link BigFloat} * * @see BigDecimal#subtract(BigDecimal, MathContext) */ public BigFloat subtract(BigDecimal x) { return subtract(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this - x. * * @param x the value to subtract * * @return the resulting {@link BigFloat} * * @see BigDecimal#subtract(BigDecimal, MathContext) */ public BigFloat subtract(int x) { return subtract(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this - x. * * @param x the value to subtract * * @return the resulting {@link BigFloat} * * @see BigDecimal#subtract(BigDecimal, MathContext) */ public BigFloat subtract(long x) { return subtract(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this - x. * * @param x the value to subtract * * @return the resulting {@link BigFloat} * * @see BigDecimal#subtract(BigDecimal, MathContext) */ public BigFloat subtract(double x) { return subtract(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this * x. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the value to multiply * * @return the resulting {@link BigFloat} * * @see BigDecimal#multiply(BigDecimal, MathContext) */ public BigFloat multiply(BigFloat x) { if (x.isSpecial()) return x.multiply(this); Context c = max(context, x.context); return c.valueOf(value.multiply(x.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is this * x. * * @param x the value to multiply * * @return the resulting {@link BigFloat} * * @see BigDecimal#multiply(BigDecimal, MathContext) */ public BigFloat multiply(BigDecimal x) { return multiply(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this * x. * * @param x the value to multiply * * @return the resulting {@link BigFloat} * * @see BigDecimal#multiply(BigDecimal, MathContext) */ public BigFloat multiply(int x) { return multiply(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this * x. * * @param x the value to multiply * * @return the resulting {@link BigFloat} * * @see BigDecimal#multiply(BigDecimal, MathContext) */ public BigFloat multiply(long x) { return multiply(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this * x. * * @param x the value to multiply * * @return the resulting {@link BigFloat} * * @see BigDecimal#multiply(BigDecimal, MathContext) */ public BigFloat multiply(double x) { return multiply(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this / x. * *

If the two values do not have the same {@link Context}, * the result will contain the {@link Context} with the larger precision.

* * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#divide(BigDecimal, MathContext) */ public BigFloat divide(BigFloat x) { if (x.isSpecial()) { if (x == NaN) { return NaN; } else { return context.valueOf(0); } } if (this.isZero() && !x.isZero()) { return context.valueOf(0); } if (x.isZero()) { if (this.isZero()) { return NaN; // 0 or -0 / 0 = NaN } else if (this.isNegative()) { return NEGATIVE_INFINITY;// -N / 0 = -INF } else { return POSITIVE_INFINITY;// N / 0 = +INF } } Context c = max(context, x.context); return c.valueOf(value.divide(x.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is this / x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#divide(BigDecimal, MathContext) */ public BigFloat divide(BigDecimal x) { return divide(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this / x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#divide(BigDecimal, MathContext) */ public BigFloat divide(int x) { return divide(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this / x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#divide(BigDecimal, MathContext) */ public BigFloat divide(long x) { return divide(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this / x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#divide(BigDecimal, MathContext) */ public BigFloat divide(double x) { return divide(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is the remainder when dividing this by x. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#remainder(BigDecimal, MathContext) */ public BigFloat remainder(BigFloat x) { if (x.isSpecial()) { if (x == NaN) { return NaN; } else { return this; } } if (this.isZero() && !x.isZero()) { return context.valueOf(0); } if (x.isZero()) { return NaN; } Context c = max(context, x.context); return c.valueOf(value.remainder(x.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is the remainder when dividing this by x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#remainder(BigDecimal, MathContext) */ public BigFloat remainder(BigDecimal x) { return remainder(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is the remainder when dividing this by x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#remainder(BigDecimal, MathContext) */ public BigFloat remainder(int x) { return remainder(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is the remainder when dividing this by x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#remainder(BigDecimal, MathContext) */ public BigFloat remainder(long x) { return remainder(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is the remainder when dividing this by x. * * @param x the value to divide with * * @return the resulting {@link BigFloat} * * @see BigDecimal#remainder(BigDecimal, MathContext) */ public BigFloat remainder(double x) { return remainder(context.valueOf(x)); } /** * Returns the {@link BigFloat} that is this to the power of y. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param y the value of the power * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public BigFloat pow(BigFloat y) { if (y.isSpecial()) { if (this.isZero()) { if (y == POSITIVE_INFINITY) { return this; } if (y == NEGATIVE_INFINITY) { return POSITIVE_INFINITY; } } if (y == NEGATIVE_INFINITY) { return context.ZERO; } return y; } if (this.isZero()) { if (y.isNegative()) { return POSITIVE_INFINITY; } } Context c = max(context, y.context); return c.valueOf(BigDecimalMath.pow(this.value, y.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is this to the power of y. * * @param y the value of the power * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public BigFloat pow(BigDecimal y) { return pow(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is this to the power of y. * * @param y the value of the power * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public BigFloat pow(int y) { return pow(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is this to the power of y. * * @param y the value of the power * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public BigFloat pow(long y) { return pow(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is this to the power of y. * * @param y the value of the power * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public BigFloat pow(double y) { return pow(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is the yth root of this. * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param y the value of the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) */ public BigFloat root(BigFloat y) { if (y.isSpecial()) return y; Context c = max(context, y.context); return c.valueOf(BigDecimalMath.root(this.value, y.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is the yth root of this. * * @param y the value of the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) */ public BigFloat root(BigDecimal y) { return root(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is the yth root of this. * * @param y the value of the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) */ public BigFloat root(int y) { return root(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is the yth root of this. * * @param y the value of the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) */ public BigFloat root(long y) { return root(context.valueOf(y)); } /** * Returns the {@link BigFloat} that is the yth root of this. * * @param y the value of the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) */ public BigFloat root(double y) { return root(context.valueOf(y)); } @Override public int hashCode() { return value.stripTrailingZeros().hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BigFloat other = (BigFloat) obj; return value.compareTo(other.value) == 0; //return Objects.equals(value, other.value) && Objects.equals(context, other.context); } /** * Returns the signum function of this {@link BigFloat}. * * @return -1, 0, or 1 as the value of this {@link BigDecimal} is negative, zero, or positive. */ public int signum() { return value.signum(); } /** * Returns whether this {@link BigFloat} is negative. * * @return true if negative, false if 0 or positive */ public boolean isNegative() { return value.signum() < 0; } /** * Returns whether this {@link BigFloat} is 0. * * @return true if 0, false if negative or positive */ public boolean isZero() { return value.signum() == 0; } /** * Returns whether this {@link BigFloat} is positive. * * @return true if positive, false if 0 or negative */ public boolean isPositive() { return value.signum() > 0; } @Override public int compareTo(BigFloat other) { if (other.isSpecial()) { return -other.compareTo(this); } return value.compareTo(other.value); } /** * Returns whether this value is mathematically equal to the other value. * * @param other the other {@link BigFloat} to compare with * * @return true if both values are mathematically equal (equivalent to this.compareTo(other) == 0 * * @see #compareTo(BigFloat) */ public boolean isEqual(BigFloat other) { if (this == NaN || other == NaN) { return false; } return compareTo(other) == 0; } /** * Returns whether this value is mathematically less than to the other value. * * @param other the other {@link BigFloat} to compare with * * @return true this value is mathematically less than to the other value (equivalent to this.compareTo(other) < 0 * * @see #compareTo(BigFloat) */ public boolean isLessThan(BigFloat other) { if (this == NaN || other == NaN) { return false; } return compareTo(other) < 0; } /** * Returns whether this value is mathematically greater than to the other value. * * @param other the other {@link BigFloat} to compare with * * @return true this value is mathematically greater than to the other value (equivalent to this.compareTo(other) > 0 * * @see #compareTo(BigFloat) */ public boolean isGreaterThan(BigFloat other) { if (this == NaN || other == NaN) { return false; } return compareTo(other) > 0; } /** * Returns whether this value is mathematically less than or equal to the other value. * * @param other the other {@link BigFloat} to compare with * * @return true this value is mathematically less than or equal to the other value (equivalent to this.compareTo(other) <= 0 * * @see #compareTo(BigFloat) * @see #isLessThan(BigFloat) * @see #isEqual(BigFloat) */ public boolean isLessThanOrEqual(BigFloat other) { if (this == NaN || other == NaN) { return false; } return compareTo(other) <= 0; } /** * Returns whether this value is mathematically greater than or equal to the other value. * * @param other the other {@link BigFloat} to compare with * * @return true this value is mathematically greater than or equal to the other value (equivalent to this.compareTo(other) >= 0 * * @see #compareTo(BigFloat) * @see #isGreaterThan(BigFloat) * @see #isEqual(BigFloat) */ public boolean isGreaterThanOrEqual(BigFloat other) { if (this == NaN || other == NaN) { return false; } return compareTo(other) >= 0; } /** * Returns whether this value can be represented as int. * * @return true if the value can be represented as int value * * @see BigDecimalMath#isIntValue(BigDecimal) */ public boolean isIntValue() { return BigDecimalMath.isIntValue(value); } /** * Returns whether this specified {@link BigDecimal} value can be represented as double. * * @return true if the value can be represented as double value * * @see BigDecimalMath#isDoubleValue(BigDecimal) */ public boolean isDoubleValue() { return BigDecimalMath.isDoubleValue(value); } /** * Returns the mantissa of this value written as mantissa * 10exponent. * *

The mantissa is defined as having exactly 1 digit before the decimal point.

* * @return the mantissa * * @see #getExponent() * @see BigDecimalMath#mantissa(BigDecimal) */ public BigFloat getMantissa() { return context.valueOf(BigDecimalMath.mantissa(value)); } /** * Returns the exponent of this value written as mantissa * 10exponent. * *

The mantissa is defined as having exactly 1 digit before the decimal point.

* * @return the exponent * * @see #getMantissa() * @see BigDecimalMath#exponent(BigDecimal) */ public BigFloat getExponent() { return context.valueOf(BigDecimalMath.exponent(value)); } /** * Returns the integral part of this value (left of the decimal point). * * @return the integral part * * @see #getFractionalPart() * @see BigDecimalMath#fractionalPart(BigDecimal) */ public BigFloat getIntegralPart() { return context.valueOf(BigDecimalMath.integralPart(value)); } /** * Returns the fractional part of this value (right of the decimal point). * * @return the fractional part * * @see #getIntegralPart() * @see BigDecimalMath#fractionalPart(BigDecimal) */ public BigFloat getFractionalPart() { return context.valueOf(BigDecimalMath.fractionalPart(value)); } /** * Returns the {@link Context} of this value. * * @return the {@link Context} */ public Context getContext() { return context; } /** * Returns this value as a {@link BigDecimal} value. * * @return the {@link BigDecimal} value */ public BigDecimal toBigDecimal() { return value; } /** * Returns this value as a double value. * * @return the double value * * @see BigDecimal#doubleValue() */ public double toDouble() { return value.doubleValue(); } /** * Returns this value as a long value. * * @return the long value * * @see BigDecimal#longValue() */ public long toLong() { return value.longValue(); } /** * Returns this value as a int value. * * @return the int value * * @see BigDecimal#intValue() */ public int toInt() { return value.intValue(); } @Override public String toString() { return value.toString(); } protected boolean isSpecial() { return false; } /** * return special type of a value * @return {@link SpecialBigFloat.Type} */ protected SpecialBigFloat.Type type() { return SpecialBigFloat.Type.NORMAL; } public boolean isNaN() { return this == NaN; } public boolean isInfinity() { return this == POSITIVE_INFINITY || this == NEGATIVE_INFINITY; } /** * this class handle unrepresentable value in floating-point arithmetic * * @author Wireless4024 */ private static final class SpecialBigFloat extends BigFloat { private static final Context DUMMY_CONTEXT = BigFloat.context(MathContext.DECIMAL32); private final Type type; private SpecialBigFloat(Type type) { super(null, DUMMY_CONTEXT); this.type = type; } @Override protected boolean isSpecial() { return true; } @Override protected Type type() { return type; } @Override public BigFloat add(BigFloat x) { if (!x.isSpecial()) { return this; } if (this == POSITIVE_INFINITY && x == POSITIVE_INFINITY) { return POSITIVE_INFINITY; } if (this == NEGATIVE_INFINITY && x == NEGATIVE_INFINITY) { return NEGATIVE_INFINITY; } return NaN; } @Override public BigFloat subtract(BigFloat x) { if (!x.isSpecial()) { return this; } if (this == POSITIVE_INFINITY && x == NEGATIVE_INFINITY) { return POSITIVE_INFINITY; } if (this == NEGATIVE_INFINITY && x == POSITIVE_INFINITY) { return NEGATIVE_INFINITY; } return NaN; } @Override public BigFloat subtract(BigDecimal x) { return this; } @Override public BigFloat multiply(BigFloat x) { if (x.isZero() || x == NaN) { return NaN; } else if (x.isNegative()) { return negate(this); } else { return this; } } @Override public BigFloat divide(BigFloat x) { if (x == NaN || (this.isInfinity() && x.isInfinity())) { return NaN; } else if (x.isNegative()) { return negate(this); } else { return this; } } @Override public BigFloat remainder(BigFloat x) { return NaN; } @Override public BigFloat pow(BigFloat y) { if (y.isZero()) { return y.context.ONE; } if (y == NaN) { return NaN; } if (this.isInfinity() && y.isNegative()) { return y.context.ZERO; } if (this == NEGATIVE_INFINITY && y.isPositive()) { return POSITIVE_INFINITY; } return this; } @Override public BigFloat root(BigFloat y) { return this; } @Override public int hashCode() { return type.hashCode; } @Override public boolean equals(Object obj) { if (this == obj) return true; return obj instanceof BigFloat && ((BigFloat) obj).isSpecial() && ((BigFloat) obj).type() == this.type; } @Override public int signum() { return type == Type.POSITIVE_INFINITY ? 1 : -1; } @Override public boolean isNegative() { return signum() < 0; } @Override public boolean isZero() { return false;//nan or infinity is not a zero } @Override public boolean isPositive() { return signum() > 0; } @Override public int compareTo(BigFloat other) { return Type.compare(type, other.type()); } @Override public boolean isIntValue() { return false; } @Override public boolean isDoubleValue() { return false; } @Override public BigFloat getMantissa() { return this; } @Override public BigFloat getExponent() { return this; } @Override public BigFloat getIntegralPart() { return this; } @Override public BigFloat getFractionalPart() { return this; } @Override public Context getContext() { throw new UnsupportedOperationException(type + " has no context"); } @Override public BigDecimal toBigDecimal() { throw new UnsupportedOperationException(type + " has no corresponding BigDecimal representation"); } @Override public double toDouble() { return type.toDouble(); } @Override public long toLong() { return (long) toDouble(); } @Override public int toInt() { return (int) toDouble(); } @Override public String toString() { return type.toString(); } //optional static enum Type { NaN(Objects.hashCode(Double.NaN)), POSITIVE_INFINITY(Objects.hashCode(Double.POSITIVE_INFINITY)), NORMAL(Objects.hashCode(0)), NEGATIVE_INFINITY(Objects.hashCode(Double.NEGATIVE_INFINITY)); final int hashCode; Type(int hashCode){ this.hashCode=hashCode; } public static int compare(Type a, Type b) { //we can use double to compare //if (a == NaN && b == NaN) // return 0;//cuz NaN equals nothing even itself return Double.compare(a.toDouble(),b.toDouble()); } /** * convert type to double * @return double value that equivalent to {@link Type} */ public double toDouble() { switch (this) { case POSITIVE_INFINITY: return Double.POSITIVE_INFINITY; case NEGATIVE_INFINITY: return Double.NEGATIVE_INFINITY; case NaN: return Double.NaN; default: return 0; } } } } /** * Manages the {@link MathContext} and provides factory methods for {@link BigFloat} values. */ public static class Context implements Serializable{ private static final long serialVersionUID = -5787473786808803161L; public final BigFloat NEGATIVE_ONE; public final BigFloat ZERO; public final BigFloat ONE; private final MathContext mathContext; private Context(MathContext mathContext) { this.mathContext = mathContext; NEGATIVE_ONE = this.valueOf(-1); ZERO = this.valueOf(0); ONE = this.valueOf(1); } /** * Returns the {@link MathContext} of this context. * * @return the {@link MathContext} */ public MathContext getMathContext() { return mathContext; } /** * Returns the precision of this context. *

* This is equivalent to calling getMathContext().getPrecision(). * * @return the precision */ public int getPrecision() { return mathContext.getPrecision(); } /** * Returns the {@link RoundingMode} of this context. *

* This is equivalent to calling getMathContext().getRoundingMode(). * * @return the {@link RoundingMode} */ public RoundingMode getRoundingMode() { return mathContext.getRoundingMode(); } /** * Creates a {@link BigFloat} value with this context. * * @param value the source {@link BigFloat} value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(BigFloat value) { return value.isSpecial() ? value : new BigFloat(value.value.round(mathContext), this);//they are final } /** * Creates a {@link BigFloat} value with this context. * * @param value the source {@link BigDecimal} value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(BigDecimal value) { return new BigFloat(value.round(mathContext), this); } /** * Creates a {@link BigFloat} value with this context. * * @param value the source int value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(int value) { return new BigFloat(new BigDecimal(value, mathContext), this); } /** * parse unsigned value with this logic

value & 4294967295
* @param value an int value * @param unsigned if true value will parse as unsigned integer * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(int value, boolean unsigned) { if (!unsigned) { return new BigFloat(new BigDecimal(value, mathContext), this); } else { if (value > -1) return valueOf(value, false); return new BigFloat(new BigDecimal(Integer.MAX_VALUE) .add(new BigDecimal(value & Integer.MAX_VALUE)) .add(BigDecimal.ONE), this); } } /** * Creates a {@link BigFloat} value with this context. * * @param value the source long value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(long value) { return new BigFloat(new BigDecimal(value, mathContext), this); } /** * parse unsigned value with this logic
value & 18446744073709551615
* @param value an int value * @param unsigned if true value will parse as unsigned integer * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(long value, boolean unsigned) { if (!unsigned) { return new BigFloat(new BigDecimal(value, mathContext), this); } else { if (value > -1) return valueOf(value, false); return new BigFloat(new BigDecimal(Long.MAX_VALUE) .add(new BigDecimal(value & Long.MAX_VALUE)) .add(BigDecimal.ONE), this); } } /** * Creates a {@link BigFloat} value with this context. * * @param value the source double value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) */ public BigFloat valueOf(double value) { if (Double.isInfinite(value)) return value == Double.POSITIVE_INFINITY ? POSITIVE_INFINITY : NEGATIVE_INFINITY; else if (Double.isNaN(value)) return NaN; return new BigFloat(new BigDecimal(String.valueOf(value), mathContext), this); } /** * Creates a {@link BigFloat} value with this context. * * @param value the source String value * * @return the {@link BigFloat} value with this context (rounded to the precision of this context) * * @throws NumberFormatException if the value is not a valid number. */ public BigFloat valueOf(String value) { return new BigFloat(new BigDecimal(value, mathContext), this); } /** * Returns the constant pi with this context. * * @return pi with this context (rounded to the precision of this context) * * @see BigDecimalMath#pi(MathContext) */ public BigFloat pi() { return valueOf(BigDecimalMath.pi(mathContext)); } /** * Returns the constant e with this context. * * @return e with this context (rounded to the precision of this context) * * @see BigDecimalMath#e(MathContext) */ public BigFloat e() { return valueOf(BigDecimalMath.e(mathContext)); } /** * Returns the factorial of n with this context. * * @param n the value to calculate * * @return the factorial of n with this context (rounded to the precision of this context) * * @see BigDecimalMath#factorial(int) */ public BigFloat factorial(int n) { return valueOf(BigDecimalMath.factorial(n)); } @Override public int hashCode() { return mathContext.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Context other = (Context) obj; return mathContext.equals(other.mathContext); } @Override public String toString() { return mathContext.toString(); } } /** * Returns the {@link BigFloat} that is - this. * * @param x the value to negate * * @return the resulting {@link BigFloat} * * @see BigDecimal#negate(MathContext) */ public static BigFloat negate(BigFloat x) { if (x.isSpecial()) if (x.isInfinity()) return x == POSITIVE_INFINITY ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else return NaN; return x.context.valueOf(x.value.negate()); } /** * Returns the {@link BigFloat} that is the abs(this) (absolute value). * * @param x the value to make absolute * * @return the resulting {@link BigFloat} * * @see BigDecimal#abs(MathContext) */ public static BigFloat abs(BigFloat x) { if (x.isSpecial()) return x.isInfinity() ? POSITIVE_INFINITY : NaN; return x.context.valueOf(x.value.abs()); } /** * Returns the the maximum of two {@link BigFloat} values. * * @param value1 the first {@link BigFloat} value to compare * @param value2 the second {@link BigFloat} value to compare * * @return the maximum {@link BigFloat} value */ public static BigFloat max(BigFloat value1, BigFloat value2) { return value1.compareTo(value2) >= 0 ? value1 : value2; } /** * Returns the the maximum of n {@link BigFloat} values. * * @param value1 the first {@link BigFloat} value to compare * @param values the other {@link BigFloat}s value to compare * * @return the maximum {@link BigFloat} value */ public static BigFloat max(BigFloat value1, BigFloat... values) { BigFloat result = value1; for (BigFloat other : values) { result = max(result, other); } return result; } /** * Returns the the minimum of two {@link BigFloat} values. * * @param value1 the first {@link BigFloat} value to compare * @param value2 the second {@link BigFloat} value to compare * * @return the minimum {@link BigFloat} value */ public static BigFloat min(BigFloat value1, BigFloat value2) { return value1.compareTo(value2) < 0 ? value1 : value2; } /** * Returns the the minimum of n {@link BigFloat} values. * * @param value1 the first {@link BigFloat} value to compare * @param values the other {@link BigFloat}s value to compare * * @return the minimum {@link BigFloat} value */ public static BigFloat min(BigFloat value1, BigFloat... values) { BigFloat result = value1; for (BigFloat other : values) { result = min(result, other); } return result; } private static BigFloat logSpecial(BigFloat val){ if (val.isNaN() || val.isNegative()) return NaN; if (val == POSITIVE_INFINITY) return POSITIVE_INFINITY; if (val.isZero()) return NEGATIVE_INFINITY; return null; } /** * Returns the {@link BigFloat} that is log(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#log(BigDecimal, MathContext) */ public static BigFloat log(BigFloat x) { BigFloat temp = logSpecial(x); return temp != null ? temp : x.context.valueOf(BigDecimalMath.log(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is log2(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#log2(BigDecimal, MathContext) */ public static BigFloat log2(BigFloat x) { BigFloat temp = logSpecial(x); return temp != null ? temp : x.context.valueOf(BigDecimalMath.log2(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is log10(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#log10(BigDecimal, MathContext) */ public static BigFloat log10(BigFloat x) { BigFloat temp = logSpecial(x); return temp != null ? temp : x.context.valueOf(BigDecimalMath.log10(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is exp(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#exp(BigDecimal, MathContext) */ public static BigFloat exp(BigFloat x) { if(x.isSpecial()) return x != NEGATIVE_INFINITY ? x : x.context.ZERO; return x.context.valueOf(BigDecimalMath.exp(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is sqrt(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#sqrt(BigDecimal, MathContext) */ public static BigFloat sqrt(BigFloat x) { if (x.isNaN() || x.isNegative()) return NaN; if (x.isZero() || x.isInfinity()) return x; return x.context.valueOf(BigDecimalMath.sqrt(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is pow(x, y). * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the {@link BigFloat} value to take to the power * @param y the {@link BigFloat} value to serve as exponent * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public static BigFloat pow(BigFloat x, BigFloat y) { Context c = max(x.context, y.context); return c.valueOf(BigDecimalMath.pow(x.value, y.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is root(x, y). * *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

* * @param x the {@link BigFloat} value to calculate the n'th root * @param y the {@link BigFloat} defining the root * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) */ public static BigFloat root(BigFloat x, BigFloat y) { Context c = max(x.context, y.context); return c.valueOf(BigDecimalMath.root(x.value, y.value, c.mathContext)); } /** * Returns the {@link BigFloat} that is sin(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#sin(BigDecimal, MathContext) */ public static BigFloat sin(BigFloat x) { if(x.isSpecial()) return NaN; if(x.isZero()) return x; return x.context.valueOf(BigDecimalMath.sin(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is cos(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#cos(BigDecimal, MathContext) */ public static BigFloat cos(BigFloat x) { if(x.isSpecial()) return NaN; return x.context.valueOf(BigDecimalMath.cos(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is tan(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#tan(BigDecimal, MathContext) */ public static BigFloat tan(BigFloat x) { if(x.isSpecial()) return NaN; if(x.isZero()) return x; return x.context.valueOf(BigDecimalMath.tan(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is cot(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#cot(BigDecimal, MathContext) */ public static BigFloat cot(BigFloat x) { if(x.isSpecial()) return x; if(x.isZero()) return POSITIVE_INFINITY; return x.context.valueOf(BigDecimalMath.cot(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is asin(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#asin(BigDecimal, MathContext) */ public static BigFloat asin(BigFloat x) { if (x.isZero()) return x; return x.isNaN() || (!isRangeAbs1(x)) ? NaN : x.context.valueOf(BigDecimalMath.asin(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is acos(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#acos(BigDecimal, MathContext) */ public static BigFloat acos(BigFloat x) { return x.isNaN() || (!isRangeAbs1(x)) ? NaN : x.context.valueOf(BigDecimalMath.acos(x.value, x.context.mathContext)); } /** * @param x a bigfloat * @return if abs(x) <= 1 */ private static boolean isRangeAbs1(BigFloat x) { return isBetween(x.context.NEGATIVE_ONE, x.context.ONE, x); } /** * Returns the {@link BigFloat} that is atan(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#atan(BigDecimal, MathContext) */ public static BigFloat atan(BigFloat x) { return x.isSpecial() || x.isZero() ? x : x.context.valueOf(BigDecimalMath.atan(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is acot(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#acot(BigDecimal, MathContext) */ public static BigFloat acot(BigFloat x) { return x.isSpecial() ? x : x.context.valueOf(BigDecimalMath.acot(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is sinh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#sinh(BigDecimal, MathContext) */ public static BigFloat sinh(BigFloat x) { if (x.isSpecial() || x.isZero()) return x; return x.context.valueOf(BigDecimalMath.sinh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is cosh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#cosh(BigDecimal, MathContext) */ public static BigFloat cosh(BigFloat x) { if (x.isNaN()) return NaN; if (x.isInfinity()) return POSITIVE_INFINITY; if (x.isZero()) return x.context.ONE; return x.context.valueOf(BigDecimalMath.cosh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is tanh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#tanh(BigDecimal, MathContext) */ public static BigFloat tanh(BigFloat x) { if (x.isNaN() || x.isZero()) return x; if (x.isInfinity()) return x == POSITIVE_INFINITY ? x.context.ONE : x.context.NEGATIVE_ONE; return x.context.valueOf(BigDecimalMath.tanh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is coth(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#coth(BigDecimal, MathContext) */ public static BigFloat coth(BigFloat x) { if(x.isSpecial()) return x; return x.context.valueOf(BigDecimalMath.coth(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is asinh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#asinh(BigDecimal, MathContext) */ public static BigFloat asinh(BigFloat x) { if(x.isSpecial()) return x; return x.context.valueOf(BigDecimalMath.asinh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is acosh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#acosh(BigDecimal, MathContext) */ public static BigFloat acosh(BigFloat x) { return x.context.valueOf(BigDecimalMath.acosh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is atanh(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#atanh(BigDecimal, MathContext) */ public static BigFloat atanh(BigFloat x) { if(x.isSpecial()) return x; return x.context.valueOf(BigDecimalMath.atanh(x.value, x.context.mathContext)); } /** * Returns the {@link BigFloat} that is acoth(x). * * @param x the value * * @return the resulting {@link BigFloat} * * @see BigDecimalMath#acoth(BigDecimal, MathContext) */ public static BigFloat acoth(BigFloat x) { if(x.isSpecial()) return x; return x.context.valueOf(BigDecimalMath.acoth(x.value, x.context.mathContext)); } public static boolean isBetween(BigFloat min, BigFloat max, BigFloat value) { return value.compareTo(min) >= 0 && value.compareTo(max) <= 0; } private static Context max(Context left, Context right) { return left.mathContext.getPrecision() > right.mathContext.getPrecision() ? left : right; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy