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

com.upokecenter.numbers.EDecimals Maven / Gradle / Ivy

Go to download

A Java implementation that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components, and supports arithmetic with these numbers.

The newest version!
package com.upokecenter.numbers;

  /**
   * A class that implements additional operations on arbitrary-precision decimal
   * numbers. Many of them are listed as miscellaneous operations in the
   * General Decimal Arithmetic Specification version 1.70.
   */
  public final class EDecimals {
private EDecimals() {
}
    private static final int DecimalRadix = 10;

    /**
     * Returns the number 10, the decimal radix.
     * @param ec Specifies an arithmetic context for rounding the number 10. Can be
     * null.
     * @return The number 10, or the closest representable number to 10 in the
     * arithmetic context.
     */
    public static EDecimal Radix(EContext ec) {
      return EDecimal.FromInt32(DecimalRadix).RoundToPrecision(ec);
    }

    /**
     * Creates an arbitrary-precision decimal number from a 32-bit signed integer.
     * @param i32 The parameter {@code i32} is a 32-bit signed integer.
     * @param ec An arithmetic context to control the precision, rounding, and
     * exponent range of the result. Can be null.
     * @return An arbitrary-precision decimal number with the closest representable
     * value to the given integer.
     */
    public static EDecimal Int32ToEDecimal(int i32, EContext ec) {
      // NOTE: Not a miscellaneous operation in the General Decimal
      // Arithmetic Specification 1.70, but required since some of the
      // miscellaneous operations here return integers
      return EDecimal.FromInt32(i32).RoundToPrecision(ec);
    }

    /**
     * Converts a boolean value (either true or false) to an arbitrary-precision
     * decimal number.
     * @param b Either true or false.
     * @param ec A context used for rounding the result. Can be null.
     * @return Either 1 if {@code b} is true, or 0 if {@code b} is false.. The
     * result will be rounded as specified by the given context, if any.
     */
    public static EDecimal BooleanToEDecimal(boolean b, EContext ec) {
      // NOTE: Not a miscellaneous operation in the General Decimal
      // Arithmetic Specification 1.70, but required since some of the
      // miscellaneous operations here return booleans
      return EDecimal.FromInt32(b ? 1 : 0).RoundToPrecision(ec);
    }

    /**
     * Returns whether the given arbitrary-precision number object is in a
     * canonical form. For the current version of EDecimal, all EDecimal
     * objects are in a canonical form.
     * @param ed An arbitrary-precision number object.
     * @return Always {@code true}.
     */

    public static boolean IsCanonical(EDecimal ed) {
      // Deliberately unused because all objects are in a canonical
      // form regardless of their value. Removing the parameter
      // or renaming it to be a "discard" parameter would be a
      // breaking change, though.
      return true;
    }

    /**
     * Returns whether the given arbitrary-precision number object is neither null
     * nor infinity nor not-a-number (NaN).
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} if the given arbitrary-precision number object
     * is neither null nor infinity nor not-a-number (NaN), or {@code
     * false} otherwise.
     */
    public static boolean IsFinite(EDecimal ed) {
      return ed != null && ed.isFinite();
    }

    /**
     * Returns whether the given arbitrary-precision number object is positive or
     * negative infinity.
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} if the given arbitrary-precision number object
     * is positive or negative infinity, or {@code false} otherwise.
     */
    public static boolean IsInfinite(EDecimal ed) {
      return ed != null && ed.IsInfinity();
    }

    /**
     * Returns whether the given arbitrary-precision number object is a
     * not-a-number (NaN).
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} or {@code false}.
     */
    public static boolean IsNaN(EDecimal ed) {
      return ed != null && ed.IsNaN();
    }

    /**
     * Returns whether the given number is a normal number. A subnormal
     * number is a nonzero finite number whose Exponent property (or
     * the number's exponent when that number is expressed in scientific
     * notation with one digit before the radix point) is less than the
     * minimum possible exponent for that number. A normal number is
     * nonzero and finite, but not subnormal.
     * @param ed An arbitrary-precision number object.
     * @param ec A context specifying the exponent range of arbitrary-precision
     * numbers. Can be null. If AdjustExponent of the given context is
     * {@code true}, a nonzero number is normal if the number's exponent
     * (when that number is expressed in scientific notation with one
     * nonzero digit before the radix point) is at least the given
     * context's EMax property (e.g., if EMax is -100, 2.3456 * 10
     * -99 is normal, but 2.3456 * 10 -102 is not).
     * If AdjustExponent of the given context is {@code false}, a nonzero
     * number is subnormal if the number's Exponent property is at least
     * given context's EMax property (e.g., if EMax is -100, 23456 * 10
     * -99 is normal, but 23456 * 10 -102 is not).
     * @return Either {@code true} if the given number is subnormal, or {@code
     * false} otherwise. Returns {@code true} if the given context is null
     * or HasExponentRange of the given context is {@code false}.
     */
    public static boolean IsNormal(EDecimal ed, EContext ec) {
      return ed != null && ed.isFinite() && !ed.isZero() && !IsSubnormal(ed, ec);
    }

    /**
     * Returns whether the given arbitrary-precision number object is a quiet
     * not-a-number (NaN).
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} or {@code false}.
     */
    public static boolean IsQuietNaN(EDecimal ed) {
      return ed != null && ed.IsQuietNaN();
    }

    /**
     * Returns whether the given arbitrary-precision number object is negative
     * (including negative infinity, negative not-a-number.get(NaN), or
     * negative zero).
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} or {@code false}.
     */
    public static boolean IsSigned(EDecimal ed) {
      return ed != null && ed.isNegative();
    }

    /**
     * Returns whether the given arbitrary-precision number object is a signaling
     * not-a-number (NaN).
     * @param ed An arbitrary-precision number object.
     * @return Either {@code true} or {@code false}.
     */
    public static boolean IsSignalingNaN(EDecimal ed) {
      return ed != null && ed.IsSignalingNaN();
    }

    private static final String[] NumberClasses = {
      "+Normal", "-Normal",
      "+Subnormal", "-Subnormal",
      "+Zero", "-Zero",
      "+Infinity", "-Infinity",
      "NaN", "sNaN",
    };

    /**
     * Converts a number class identifier (ranging from 0 through 9) to a text
     * string. An arbitrary-precision number object can belong in one of
     * ten number classes.
     * @param nc An integer identifying a number class.
     * @return A text string identifying the given number class as follows: 0 =
     *  "+Normal"; 1 = "-Normal", 2 = "+Subnormal", 3 = "-Subnormal", 4 =
     *  "+Zero", 5 = "-Zero", 6 = "+Infinity", 7 = "-Infinity", 8 = "NaN", 9
     *  = "sNaN".
     * @throws IllegalArgumentException The parameter {@code nc} is less than 0 or greater
     * than 9.
     */
    public static String NumberClassString(int nc) {
      if (nc < 0) {
        throw new IllegalArgumentException("nc(" + nc +
          ") is not greater or equal to 0");
      }
      if (nc > 9) {
        throw new IllegalArgumentException("nc(" + nc +
          ") is not less or equal to 9");
      }
      return NumberClasses[nc];
    }

    /**
     * Finds the number class for an arbitrary-precision decimal number object.
     * @param ed An arbitrary-precision decimal number object.
     * @param ec A context object that specifies the precision and exponent range
     * of arbitrary-precision numbers. This is used only to distinguish
     * between normal and subnormal numbers. Can be null.
     * @return A 32-bit signed integer identifying the given number object, number
     * class as follows: 0 = positive normal; 1 = negative normal, 2 =
     * positive subnormal, 3 = negative subnormal, 4 = positive zero, 5 =
     * negative zero, 6 = positive infinity, 7 = negative infinity, 8 =
     * quiet not-a-number (NaN), 9 = signaling NaN.
     * @throws NullPointerException The parameter {@code ed} is null.
     */
    public static int NumberClass(EDecimal ed, EContext ec) {
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed.IsQuietNaN()) {
        return 8;
      }
      if (ed.IsNaN()) {
        return 9;
      }
      if (ed.IsInfinity()) {
        return ed.isNegative() ? 7 : 6;
      }
      if (ed.isZero()) {
        return ed.isNegative() ? 5 : 4;
      }
      return IsSubnormal(ed, ec) ? (ed.isNegative() ? 3 : 2) :
        (ed.isNegative() ? 1 : 0);
    }

    /**
     * Returns whether the given number is a subnormal number. A
     * subnormal number is a nonzero finite number whose Exponent
     * property (or the number's exponent when that number is expressed in
     * scientific notation with one digit before the radix point) is less
     * than the minimum possible exponent for that number.
     * @param ed An arbitrary-precision number object.
     * @param ec A context specifying the exponent range of arbitrary-precision
     * numbers. Can be null. If AdjustExponent of the given context is
     * {@code true}, a nonzero number is subnormal if the number's exponent
     * (when that number is expressed in scientific notation with one
     * nonzero digit before the radix point) is less than the given
     * context's EMax property (e.g., if EMax is -100, 2.3456 * 10
     * -102 is subnormal, but 2.3456 * 10 -99 is
     * not). If AdjustExponent of the given context is {@code false}, a
     * nonzero number is subnormal if the number's Exponent property is
     * less than the given context's EMax property (e.g., if EMax is -100,
     * 23456 * 10 -102 is subnormal, but 23456 * 10
     * -99 is not).
     * @return Either {@code true} if the given number is subnormal, or {@code
     * false} otherwise. Returns {@code false} if the given context is null
     * or HasExponentRange of the given context is {@code false}.
     * @throws NullPointerException The parameter {@code ed} is null.
     */
    public static boolean IsSubnormal(EDecimal ed, EContext ec) {
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed.isFinite() && ec != null && !ed.isZero() && ec.getHasExponentRange()) {
        if (ec.getAdjustExponent()) {
          return ed.getExponent().Add(ed.Precision().Subtract(1)).compareTo(
              ec.getEMin()) < 0;
        } else {
          return ed.getExponent().compareTo(ec.getEMin()) < 0;
        }
      }
      return false;
    }

    /**
     * Returns whether the given arbitrary-precision number object is zero
     * (positive zero or negative zero).
     * @param ed An arbitrary-precision number object.
     * @return {@code true} if the given number has a value of zero (positive zero
     * or negative zero); otherwise, {@code false}.
     */
    public static boolean IsZero(EDecimal ed) {
      return ed != null && ed.isZero();
    }

    /**
     * Returns the base-10 exponent of an arbitrary-precision decimal number (when
     * that number is expressed in scientific notation with one digit
     * before the radix point). For example, returns 3 for the numbers
     * 6.66E + 3 and 666E + 1.
     * @param ed An arbitrary-precision decimal number.
     * @param ec An arithmetic context to control the precision, rounding, and
     * exponent range of the result. Can be null.
     * @return The base-10 exponent of the given number (when that number is
     * expressed in scientific notation with one nonzero digit before the
     * radix point). Signals DivideByZero and returns negative infinity if
     * {@code ed} is zero. Returns positive infinity if {@code ed} is
     * positive infinity or negative infinity.
     * @throws NullPointerException The parameter {@code ed} is null.
     */
    public static EDecimal LogB(EDecimal ed, EContext ec) {
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed.IsNaN()) {
        return ed.RoundToPrecision(ec);
      }
      if (ed.IsInfinity()) {
        return EDecimal.PositiveInfinity;
      }
      if (ed.isZero()) {
        return EDecimal.FromInt32(-1).Divide(EDecimal.Zero, ec);
      }
      EInteger ei = ed.getExponent().Add(ed.Precision().Subtract(1));
      return EDecimal.FromEInteger(ei).RoundToPrecision(ec);
    }

    /**
     * Finds an arbitrary-precision decimal number whose decimal point is moved a
     * given number of places.
     * @param ed An arbitrary-precision decimal number.
     * @param ed2 The number of decimal places to move the decimal point of "ed".
     * This must be an integer with an exponent of 0.
     * @param ec An arithmetic context to control the precision, rounding, and
     * exponent range of the result. Can be null.
     * @return The given arbitrary-precision decimal number whose decimal point is
     * moved the given number of places. Signals an invalid operation and
     * returns not-a-number (NaN) if {@code ed2} is infinity or NaN, has an
     * Exponent property other than 0. Signals an invalid operation and
     * returns not-a-number (NaN) if {@code ec} defines a limited precision
     * and exponent range and if {@code ed2} 's absolute value is greater
     * than twice the sum of the context's EMax property and its Precision
     * property.
     * @throws NullPointerException The parameter {@code ed} or {@code ed2} is
     * null.
     */
    public static EDecimal ScaleB(EDecimal ed, EDecimal ed2, EContext ec) {
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed2 == null) {
        throw new NullPointerException("ed2");
      }
      if (ed.IsNaN() || ed2.IsNaN()) {
        return ed.Add(ed2, ec);
      }
      if (!ed2.isFinite() || ed2.getExponent().signum() != 0) {
        return InvalidOperation(ec);
      }
      EInteger scale = ed2.getMantissa();
      if (ec != null && ec.getHasMaxPrecision() && ec.getHasExponentRange()) {
        EInteger exp = ec.getEMax().Add(ec.getPrecision()).Multiply(2);
        if (scale.Abs().compareTo(exp.Abs()) > 0) {
          return InvalidOperation(ec);
        }
      }
      if (ed.IsInfinity()) {
        return ed;
      }
      if (scale.isZero()) {
        return ed.RoundToPrecision(ec);
      }
      EDecimal ret = EDecimal.Create(
          ed.getUnsignedMantissa(),
          ed.getExponent().Add(scale));
      if (ed.isNegative()) {
        ret = ret.Negate();
      }
      return ret.RoundToPrecision(ec);
    }

    /**
     * Shifts the digits of an arbitrary-precision decimal number's significand.
     * @param ed An arbitrary-precision number containing the significand to shift.
     * @param ed2 An arbitrary-precision number indicating the number of digits to
     * shift the first operand's significand. Must be an integer with an
     * exponent of 0. If this parameter is positive, the significand is
     * shifted to the left by the given number of digits. If this parameter
     * is negative, the significand is shifted to the right by the given
     * number of digits.
     * @param ec An arithmetic context to control the precision of
     * arbitrary-precision numbers. Can be null.
     * @return An arbitrary-precision decimal number whose significand is shifted
     * the given number of digits. Signals an invalid operation and returns
     * NaN (not-a-number) if {@code ed2} is a signaling NaN or if {@code
     * ed2} is not an integer, is negative, has an exponent other than 0,
     * or has an absolute value that exceeds the maximum precision
     * specified in the context.
     * @throws NullPointerException The parameter {@code ed} or {@code ed2} is
     * null.
     */
    public static EDecimal Shift(EDecimal ed, EDecimal ed2, EContext ec) {
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed2 == null) {
        throw new NullPointerException("ed2");
      }
      if (ed.IsNaN() || ed2.IsNaN()) {
        return ed.Add(ed2, ec);
      }
      if (!ed2.isFinite() || ed2.getExponent().signum() != 0) {
        return InvalidOperation(ec);
      }
      EInteger shift = ed2.getMantissa();
      if (ec != null) {
        if (shift.Abs().compareTo(ec.getPrecision()) > 0) {
          return InvalidOperation(ec);
        }
      }
      if (ed.IsInfinity()) {
        // NOTE: Must check for validity of second
        // parameter first, before checking if first
        // parameter is infinity here
        return ed;
      }
      EInteger mant = ed.getUnsignedMantissa();
      if (mant.isZero()) {
        return ed.RoundToPrecision(ec);
      }
      EInteger mantprec = ed.Precision();
      EInteger radix = EInteger.FromInt32(DecimalRadix);
      if (shift.signum() < 0) {
        if (shift.Abs().compareTo(mantprec) < 0) {
          EInteger divisor = radix.Pow(shift.Abs());
          mant = mant.Divide(divisor);
        } else {
          mant = EInteger.FromInt32(0);
        }
        EDecimal ret = EDecimal.Create(mant, ed.getExponent());
        return ed.isNegative() ? ret.Negate() : ret;
      } else {
        EInteger mult = radix.Pow(shift);
        mant = mant.Multiply(mult);
        if (ec != null && ec.getHasMaxPrecision()) {
          EInteger mod = radix.Pow(ec.getPrecision());
          mant = mant.Remainder(mod);
        }
        EDecimal ret = EDecimal.Create(mant, ed.getExponent());
        return ed.isNegative() ? ret.Negate() : ret;
      }
    }

    /**
     * Rotates the digits of an arbitrary-precision decimal number's significand.
     * @param ed An arbitrary-precision number containing the significand to
     * rotate. If this significand contains more digits than the precision,
     * the most-significant digits are chopped off the significand before
     * the rotation begins.
     * @param ed2 An arbitrary-precision number indicating the number of digits to
     * rotate the first operand's significand. Must be an integer with an
     * exponent of 0. If this parameter is positive, the significand is
     * shifted to the left by the given number of digits and the
     * most-significant digits shifted out of the significand become the
     * least-significant digits instead. If this parameter is negative, the
     * significand is shifted to the right by the given number of digits
     * and the least-significant digits shifted out of the significand
     * become the most-significant digits instead.
     * @param ec An arithmetic context to control the precision of
     * arbitrary-precision numbers. If this parameter is null or specifies
     * an unlimited precision, this method has the same behavior as {@code
     * Shift}.
     * @return An arbitrary-precision decimal number whose significand is rotated
     * the given number of digits. Signals an invalid operation and returns
     * NaN (not-a-number) if {@code ed2} is a signaling NaN or if {@code
     * ed2} is not an integer, is negative, has an exponent other than 0,
     * or has an absolute value that exceeds the maximum precision
     * specified in the context.
     * @throws NullPointerException The parameter {@code ed2} or {@code ed} is
     * null.
     */
    public static EDecimal Rotate(EDecimal ed, EDecimal ed2, EContext ec) {
      if (ec == null || !ec.getHasMaxPrecision()) {
        return Shift(ed, ed2, ec);
      }
      if (ed2 == null) {
        throw new NullPointerException("ed2");
      }
      if (ed == null) {
        throw new NullPointerException("ed");
      }
      if (ed.IsNaN() || ed2.IsNaN()) {
        return ed.Add(ed2, ec);
      }
      if (!ed2.isFinite() || ed2.getExponent().signum() != 0) {
        return InvalidOperation(ec);
      }
      EInteger shift = ed2.getMantissa();
      if (shift.Abs().compareTo(ec.getPrecision()) > 0) {
        return InvalidOperation(ec);
      }
      if (ed.IsInfinity()) {
        // NOTE: Must check for validity of second
        // parameter first, before checking if first
        // parameter is infinity here
        return ed;
      }
      EInteger mant = ed.getUnsignedMantissa();
      EInteger mantprec = ed.Precision();
      if (ec != null && ec.getHasMaxPrecision() &&
        mantprec.compareTo(ec.getPrecision()) > 0) {
        mant = mant.Remainder(
            EInteger.FromInt32(DecimalRadix).Pow(ec.getPrecision()));
        mantprec = ec.getPrecision();
      }
      if (mant.isZero()) {
        return ed.RoundToPrecision(ec);
      }
      EInteger rightShift = shift.signum() < 0 ? shift.Abs() :
        ec.getPrecision().Subtract(shift);
      EInteger leftShift = ec.getPrecision().Subtract(rightShift);
      EInteger mantRight = EInteger.FromInt32(0);
      EInteger mantLeft = EInteger.FromInt32(0);
      EInteger radix = EInteger.FromInt32(DecimalRadix);
      // Right shift
      if (rightShift.compareTo(mantprec) < 0) {
        EInteger divisor = radix.Pow(rightShift);
        mantRight = mant.Divide(divisor);
      } else {
        mantRight = EInteger.FromInt32(0);
      }
      // Left shift
      if (leftShift.isZero()) {
        mantLeft = mant;
      } else if (leftShift.compareTo(ec.getPrecision()) == 0) {
        mantLeft = EInteger.FromInt32(0);
      } else {
        EInteger mult = radix.Pow(leftShift);
        mantLeft = mant.Multiply(mult);
        EInteger mod = radix.Pow(ec.getPrecision());
        mantLeft = mantLeft.Remainder(mod);
      }
      EDecimal ret = EDecimal.Create(mantRight.Add(mantLeft), ed.getExponent());
      return ed.isNegative() ? ret.Negate() : ret;
    }

    /**
     * Compares the values of one arbitrary-precision number object and another
     * object, imposing a total ordering on all possible values. In this
     * method: 
  • For objects with the same value, the one with the * higher exponent has a greater "absolute value".
  • Negative * zero is less than positive zero.
  • Quiet NaN has a higher * "absolute value" than signaling NaN. If both objects are quiet NaN * or both are signaling NaN, the one with the higher diagnostic * information has a greater "absolute value".
  • NaN has a * higher "absolute value" than infinity.
  • Infinity has a * higher "absolute value" than any finite number.
  • Negative * numbers are less than positive numbers.
* @param ed The first arbitrary-precision number to compare. * @param other The second arbitrary-precision number to compare. * @param ec An arithmetic context. Flags will be set in this context only if * {@code HasFlags} and {@code IsSimplified} of the context are true * and only if an operand needed to be rounded before carrying out the * operation. Can be null. * @return The number 0 if both objects are null or equal, or -1 if the first * object is null or less than the other object, or 1 if the first * object is greater or the other object is null. Does not signal flags * if either value is signaling NaN. */ public static int CompareTotal(EDecimal ed, EDecimal other, EContext ec) { return (ed == null) ? (other == null ? 0 : -1) : ((other == null) ? 1 : ed.CompareToTotal(other, ec)); } /** * Compares the absolute values of two arbitrary-precision number objects, * imposing a total ordering on all possible values (ignoring their * signs). In this method:
  • For objects with the same value, * the one with the higher exponent has a greater "absolute * value".
  • Negative zero and positive zero are considered * equal.
  • Quiet NaN has a higher "absolute value" than * signaling NaN. If both objects are quiet NaN or both are signaling * NaN, the one with the higher diagnostic information has a greater * "absolute value".
  • NaN has a higher "absolute value" than * infinity.
  • Infinity has a higher "absolute value" than any * finite number.
* @param ed The first arbitrary-precision number to compare. * @param other The second arbitrary-precision number to compare. * @param ec An arithmetic context. Flags will be set in this context only if * {@code HasFlags} and {@code IsSimplified} of the context are true * and only if an operand needed to be rounded before carrying out the * operation. Can be null. * @return The number 0 if both objects are null or equal (ignoring their * signs), or -1 if the first object is null or less than the other * value (ignoring their signs), or 1 if the first object is greater * (ignoring their signs) or the other object is null. Does not signal * flags if either value is signaling NaN. */ public static int CompareTotalMagnitude( EDecimal ed, EDecimal other, EContext ec) { return (ed == null) ? (other == null ? 0 : -1) : ((other == null) ? 1 : ed.CompareToTotalMagnitude(other, ec)); } /** * Creates a copy of the given arbitrary-precision number object. * @param ed An arbitrary-precision number object to copy. * @return A copy of the given arbitrary-precision number object. * @throws NullPointerException The parameter {@code ed} is null. */ public static EDecimal Copy(EDecimal ed) { if (ed == null) { throw new NullPointerException("ed"); } return ed.Copy(); } /** * Returns a canonical version of the given arbitrary-precision number object. * In this method, this method behaves like the Copy method. * @param ed An arbitrary-precision number object. * @return A copy of the parameter {@code ed}. */ public static EDecimal Canonical(EDecimal ed) { return Copy(ed); } /** * Returns an arbitrary-precision number object with the same value as the * given number object but with a nonnegative sign (that is, the given * number object's absolute value). * @param ed An arbitrary-precision number object. * @return An arbitrary-precision number object with the same value as the * given number object but with a nonnegative sign. * @throws NullPointerException The parameter {@code ed} is null. */ public static EDecimal CopyAbs(EDecimal ed) { if (ed == null) { throw new NullPointerException("ed"); } return Copy(ed.Abs()); } /** * Returns an arbitrary-precision number object with the sign reversed from the * given number object. * @param ed An arbitrary-precision number object. * @return An arbitrary-precision number object with the sign reversed from the * given number object. * @throws NullPointerException The parameter {@code ed} is null. */ public static EDecimal CopyNegate(EDecimal ed) { if (ed == null) { throw new NullPointerException("ed"); } return Copy(ed.Negate()); } /** * Returns an arbitrary-precision number object with the same value as the * first given number object but with a the same sign (positive or * negative) as the second given number object. * @param ed An arbitrary-precision number object with the value the result * will have. * @param other The parameter {@code other} is an arbitrary-precision decimal * floating-point number. * @return An arbitrary-precision number object with the same value as the * first given number object but with a the same sign (positive or * negative) as the second given number object. * @throws NullPointerException The parameter {@code ed} or {@code other} is * null. */ public static EDecimal CopySign(EDecimal ed, EDecimal other) { if (ed == null) { throw new NullPointerException("ed"); } if (other == null) { throw new NullPointerException("other"); } return ed.isNegative() == other.isNegative() ? Copy(ed) : CopyNegate(ed); } private static EDecimal InvalidOperation(EContext ec) { return EDecimal.SignalingNaN.Plus(ec); } /** * Returns whether two arbitrary-precision numbers have the same exponent, they * both are not-a-number (NaN), or they both are infinity (positive * and/or negative). * @param ed1 The first arbitrary-precision number. * @param ed2 The second arbitrary-precision number. * @return Either {@code true} if the given arbitrary-precision numbers have * the same exponent, they both are not-a-number (NaN), or they both * are infinity (positive and/or negative); otherwise, {@code false}. */ public static boolean SameQuantum(EDecimal ed1, EDecimal ed2) { if (ed1 == null || ed2 == null) { return false; } if (ed1.isFinite() && ed2.isFinite()) { return ed1.getExponent().equals(ed2.getExponent()); } else { return (ed1.IsNaN() && ed2.IsNaN()) || (ed1.IsInfinity() && ed2.IsInfinity()); } } /** * Returns an arbitrary-precision number with the same value as this one but * with certain trailing zeros removed from its significand. If the * number's exponent is 0, it is returned unchanged (but may be rounded * depending on the arithmetic context); if that exponent is greater 0, * its trailing zeros are removed from the significand (then rounded if * necessary); if that exponent is less than 0, its trailing zeros are * removed from the significand until the exponent reaches 0 (then the * number is rounded if necessary). * @param ed1 An arbitrary-precision number. * @param ec An arithmetic context to control the precision, rounding, and * exponent range of the result. Can be null. * @return An arbitrary-precision number with the same value as this one but * with certain trailing zeros removed from its significand. If {@code * ed1} is not-a-number (NaN) or infinity, it is generally returned * unchanged. */ public static EDecimal Trim(EDecimal ed1, EContext ec) { EDecimal ed = ed1; if (ed1 == null) { return InvalidOperation(ec); } if (ed.IsSignalingNaN()) { return EDecimal.CreateNaN( ed.getUnsignedMantissa(), true, ed.isNegative(), ec); } if (ed.isFinite()) { if (ed.isZero()) { return (ed.isNegative() ? EDecimal.NegativeZero : EDecimal.Zero).RoundToPrecision(ec); } else if (ed.getExponent().signum() > 0) { return ed.Reduce(ec); } else if (ed.getExponent().signum() == 0) { return ed.RoundToPrecision(ec); } else { EInteger exp = ed.getExponent(); EInteger mant = ed.getUnsignedMantissa(); boolean neg = ed.isNegative(); boolean trimmed = false; EInteger radixint = EInteger.FromInt32(DecimalRadix); while (exp.signum() < 0 && mant.signum() > 0) { EInteger[] divrem = mant.DivRem(radixint); int rem = divrem[1].ToInt32Checked(); if (rem != 0) { break; } mant = divrem[0]; exp = exp.Add(1); trimmed = true; } if (!trimmed) { return ed.RoundToPrecision(ec); } EDecimal ret = EDecimal.Create(mant, exp); if (neg) { ret = ret.Negate(); } return ret.RoundToPrecision(ec); } } else { return ed1.Plus(ec); } } /** * Returns an arbitrary-precision decimal number with the same value as this * object but with the given exponent, expressed as an * arbitrary-precision decimal number.

Note that this is not always * the same as rounding to a given number of decimal places, since it * can fail if the difference between this value's exponent and the * desired exponent is too big, depending on the maximum precision. If * rounding to a number of decimal places is desired, it's better to * use the RoundToExponent and RoundToIntegral methods instead.

*

Remark: This method can be used to implement fixed-point * decimal arithmetic, in which a fixed number of digits come after the * decimal point. A fixed-point decimal arithmetic in which no digits * come after the decimal point (a desired exponent of 0) is considered * an "integer arithmetic" .

* @param ed An arbitrary-precision decimal number whose exponent is to be * changed. * @param scale The desired exponent of the result, expressed as an * arbitrary-precision decimal number. The exponent is the number of * fractional digits in the result, expressed as a negative number. Can * also be positive, which eliminates lower-order places from the * number. For example, -3 means round to the thousandth (10^-3, * 0.0001), and 3 means round to the thousands-place (10^3, 1000). A * value of 0 rounds the number to an integer. * @param ec The parameter {@code ec} is an EContext object. * @return An arbitrary-precision decimal number with the same value as this * object but with the exponent changed. Signals FlagInvalid and * returns not-a-number (NaN) if the result can't fit the given * precision without rounding, or if the arithmetic context defines an * exponent range and the given exponent is outside that range. */ public static EDecimal Rescale(EDecimal ed, EDecimal scale, EContext ec) { if (ed == null || scale == null) { return InvalidOperation(ec); } if (!scale.isFinite()) { return ed.Quantize(scale, ec); } if (scale.getExponent().isZero()) { return ed.Quantize(EDecimal.Create(EInteger.FromInt32(1), scale.getMantissa()), ec); } else { EContext tec = ec == null ? null : ec.WithTraps(0).WithBlankFlags(); EDecimal rv = scale.RoundToExponentExact(0, tec); if (!rv.isFinite() || (tec.getFlags() & EContext.FlagInexact) != 0) { if (ec != null && ec.isSimplified()) { // In simplified arithmetic, round scale to trigger // appropriate error conditions scale = scale.RoundToPrecision(ec); } return InvalidOperation(ec); } EDecimal rounded = scale.Quantize(0, tec); return ed.Quantize( EDecimal.Create(EInteger.FromInt32(1), rounded.getMantissa()), ec); } } // Logical Operations /** * Performs a logical AND operation on two decimal numbers in the form of * logical operands. A logical operand is a non-negative * base-10 number with an Exponent property of 0 and no other base-10 * digits than 0 or 1 (examples include 01001 and 111001, * but not 02001 or 99999). The logical AND operation * sets each digit of the result to 1 if the corresponding digits of * each logical operand are both 1, and to 0 otherwise. For example, * 01001 AND 111010 = 01000. * @param ed1 The first logical operand to the logical AND operation. * @param ed2 The second logical operand to the logical AND operation. * @param ec An arithmetic context to control the maximum precision of * arbitrary-precision numbers. If a logical operand passed to this * method has more digits than the maximum precision specified in this * context, the operand's most significant digits that exceed that * precision are discarded. This parameter can be null. * @return The result of the logical AND operation as a logical operand. * Signals an invalid operation and returns not-a-number (NaN) if * {@code ed1}, {@code ed2}, or both are not logical operands. */ public static EDecimal And(EDecimal ed1, EDecimal ed2, EContext ec) { byte[] logi1 = FromLogical(ed1, ec, 10); if (logi1 == null) { return InvalidOperation(ec); } byte[] logi2 = FromLogical(ed2, ec, 10); if (logi2 == null) { return InvalidOperation(ec); } byte[] smaller = logi1.length < logi2.length ? logi1 : logi2; byte[] bigger = logi1.length < logi2.length ? logi2 : logi1; for (int i = 0; i < smaller.length; ++i) { smaller[i] &= bigger[i]; } return EDecimal.FromEInteger(ToLogical(smaller, 10)).RoundToPrecision(ec); } /** * Performs a logical NOT operation on an arbitrary-precision decimal number in * the form of a logical operand. A logical operand is a * non-negative base-10 number with an Exponent property of 0 and no * other base-10 digits than 0 or 1 (examples include 01001 and * 111001 , but not 02001 or 99999). The logical * NOT operation sets each digit of the result to 1 if the * corresponding digit is 0, and to 0 otherwise; it can set no more * digits than the maximum precision, however. For example, if the * maximum precision is 8 digits, then NOT 111010 = 11000101. * @param ed1 The logical operand to the logical NOT operation. * @param ec An arithmetic context to control the maximum precision of * arbitrary-precision numbers. If a logical operand passed to this * method has more digits than the maximum precision specified in this * context, the operand's most significant digits that exceed that * precision are discarded. This parameter cannot be null and must * specify a maximum precision (unlimited precision contexts are not * allowed). * @return The result of the logical NOT operation as a logical operand. * Signals an invalid operation and returns not-a-number (NaN) if * {@code ed1} is not a logical operand. */ public static EDecimal Invert(EDecimal ed1, EContext ec) { if (ec == null || !ec.getHasMaxPrecision()) { return InvalidOperation(ec); } byte[] smaller = FromLogical(ed1, ec, 10); if (smaller == null) { return InvalidOperation(ec); } EInteger ei = EInteger.FromInt32(1).ShiftLeft(ec.getPrecision()).Subtract(1); byte[] bigger = ei.ToBytes(true); for (int i = 0; i < smaller.length; ++i) { bigger[i] ^= smaller[i]; } return EDecimal.FromEInteger(ToLogical(bigger, 10)).RoundToPrecision( ec); } /** * Performs a logical exclusive-OR (XOR) operation on two decimal numbers in * the form of logical operands. A logical operand is a * non-negative base-10 number with an exponent of 0 and no other * base-10 digits than 0 or 1 (examples include 01001 and * 111001, but not 02001 or 99999). The logical * exclusive-OR operation sets each digit of the result to 1 if either * corresponding digit of the logical operands, but not both, is 1, and * to 0 otherwise. For example, 01001 XOR 111010 = 101010. * @param ed1 The first logical operand to the logical exclusive-OR operation. * @param ed2 The second logical operand to the logical exclusive-OR operation. * @param ec An arithmetic context to control the maximum precision of * arbitrary-precision numbers. If a logical operand passed to this * method has more digits than the maximum precision specified in this * context, the operand's most significant digits that exceed that * precision are discarded. This parameter can be null. * @return An arbitrary-precision decimal floating-point number. */ public static EDecimal Xor(EDecimal ed1, EDecimal ed2, EContext ec) { byte[] logi1 = FromLogical(ed1, ec, 10); if (logi1 == null) { return InvalidOperation(ec); } byte[] logi2 = FromLogical(ed2, ec, 10); if (logi2 == null) { return InvalidOperation(ec); } byte[] smaller = logi1.length < logi2.length ? logi1 : logi2; byte[] bigger = logi1.length < logi2.length ? logi2 : logi1; for (int i = 0; i < smaller.length; ++i) { bigger[i] ^= smaller[i]; } return EDecimal.FromEInteger(ToLogical(bigger, 10)).RoundToPrecision( ec); } /** * Performs a logical OR operation on two decimal numbers in the form of * logical operands. A logical operand is a non-negative * base-10 number with an Exponent property of 0 and no other base-10 * digits than 0 or 1 (examples include 01001 and 111001, * but not 02001 or 99999). The logical OR operation * sets each digit of the result to 1 if either or both of the * corresponding digits of the logical operands are 1, and to 0 * otherwise. For example, 01001 OR 111010 = 111011. * @param ed1 The first logical operand to the logical OR operation. * @param ed2 The second logical operand to the logical OR operation. * @param ec An arithmetic context to control the maximum precision of * arbitrary-precision numbers. If a logical operand passed to this * method has more digits than the maximum precision specified in this * context, the operand's most significant digits that exceed that * precision are discarded. This parameter can be null. * @return The result of the logical OR operation as a logical operand. Signals * an invalid operation and returns not-a-number (NaN) if {@code ed1}, * {@code ed2}, or both are not logical operands. */ public static EDecimal Or(EDecimal ed1, EDecimal ed2, EContext ec) { byte[] logi1 = FromLogical(ed1, ec, 10); if (logi1 == null) { return InvalidOperation(ec); } byte[] logi2 = FromLogical(ed2, ec, 10); if (logi2 == null) { return InvalidOperation(ec); } byte[] smaller = logi1.length < logi2.length ? logi1 : logi2; byte[] bigger = logi1.length < logi2.length ? logi2 : logi1; for (int i = 0; i < smaller.length; ++i) { bigger[i] |= smaller[i]; } return EDecimal.FromEInteger(ToLogical(bigger, 10)).RoundToPrecision( ec); } static EInteger ToLogical(byte[] bytes, int iradix) { if (bytes == null) { throw new NullPointerException("bytes"); } EInteger ret = EInteger.FromInt32(0); int i; for (i = bytes.length - 1; i >= 0; --i) { int b = bytes[i]; for (int j = 7; j >= 0; --j) { ret = ((bytes[i] & (1 << j)) != 0) ? ret.Multiply(iradix).Add(1) : ret.Multiply(iradix); } } return ret; } static byte[] FromLogical(EInteger um, EContext ec, int iradix) { if (um == null || um.signum() < 0) { return null; } if (um.signum() == 0) { return new byte[] { 0 }; } EInteger ret = EInteger.FromInt32(0); EInteger prec = um.GetDigitCountAsEInteger(); EInteger maxprec = (ec != null && ec.getHasMaxPrecision()) ? ec.getPrecision() : null; EInteger bytecount = prec.ShiftRight(3).Add(1); if (bytecount.compareTo(0x7fffffff) > 0) { return null; // Out of memory } int bitindex = 0; byte[] bytes = new byte[bytecount.ToInt32Checked()]; EInteger radixint = EInteger.FromInt32(iradix); while (um.signum() > 0) { EInteger[] divrem = um.DivRem(radixint); int rem = divrem[1].ToInt32Checked(); um = divrem[0]; if (rem == 1) { // Don't collect bits beyond max precision if (maxprec == null || maxprec.compareTo(bitindex) > 0) { int byteindex = bitindex >> 3; int mask = 1 << (bitindex & 7); bytes[byteindex] |= (byte)mask; } } else if (rem != 0) { return null; } ++bitindex; } return bytes; } static byte[] FromLogical(EDecimal ed, EContext ec, int iradix) { if (ed == null) { return null; } if (ec != null && ec.isPrecisionInBits() && iradix != 2) { // Round to bit precision if necessary and if the radix isn't binary ed = ed.RoundToPrecision(ec); } return (!ed.isFinite() || ed.isNegative() || ed.getExponent().signum() != 0 || ed.getMantissa().signum() < 0) ? null : FromLogical( ed.getUnsignedMantissa(), ec, iradix); } static byte[] FromLogical(EFloat ed, EContext ec, int iradix) { if (ed == null) { return null; } // NOTE: Precision of EFloat is already in bits, so no need to check for // IsPrecisionInBits here return (!ed.isFinite() || ed.isNegative() || ed.getExponent().signum() != 0 || ed.getMantissa().signum() < 0) ? null : FromLogical( ed.getUnsignedMantissa(), ec, iradix); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy