Пример #1
0
 /**
  * Computes the value of this number raised to an integral power. Follows semantics of Java
  * Math.pow as closely as possible.
  *
  * @param exp the integer exponent
  * @return x raised to the integral power exp
  */
 public WB_DoubleDouble pow(final int exp) {
   if (exp == 0.0) {
     return valueOf(1.0);
   }
   WB_DoubleDouble r = new WB_DoubleDouble(this);
   WB_DoubleDouble s = valueOf(1.0);
   int n = Math.abs(exp);
   if (n > 1) {
     /* Use binary exponentiation */
     while (n > 0) {
       if ((n % 2) == 1) {
         s.selfMultiply(r);
       }
       n /= 2;
       if (n > 0) {
         r = r.sqr();
       }
     }
   } else {
     s = r;
   }
   /* Compute the reciprocal if n is negative. */
   if (exp < 0) {
     return s.reciprocal();
   }
   return s;
 }
Пример #2
0
 /**
  * Rounds this value to the nearest integer. The value is rounded to an integer by adding 1/2 and
  * taking the floor of the result. Special cases:
  *
  * <ul>
  *   <li>If this value is NaN, returns NaN.
  * </ul>
  *
  * @return this value rounded to the nearest integer
  */
 public WB_DoubleDouble rint() {
   if (isNaN()) {
     return this;
   }
   // may not be 100% correct
   final WB_DoubleDouble plus5 = this.add(0.5);
   return plus5.floor();
 }
Пример #3
0
 /**
  * Computes the positive square root of this value. If the number is NaN or negative, NaN is
  * returned.
  *
  * @return the positive square root of this number. If the argument is NaN or less than zero, the
  *     result is NaN.
  */
 public WB_DoubleDouble sqrt() {
   /*
    * Strategy: Use Karp's trick: if x is an approximation to sqrt(a), then
    *
    * sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx)
    *
    * The approximation is accurate to twice the accuracy of x. Also, the
    * multiplication (a*x) and [-]*x can be done with only half the
    * precision.
    */
   if (isZero()) {
     return valueOf(0.0);
   }
   if (isNegative()) {
     return NaN;
   }
   final double x = 1.0 / Math.sqrt(hi);
   final double ax = hi * x;
   final WB_DoubleDouble axdd = valueOf(ax);
   final WB_DoubleDouble diffSq = this.subtract(axdd.sqr());
   final double d2 = diffSq.hi * (x * 0.5);
   return axdd.add(d2);
 }
Пример #4
0
/**
 * Implements extended-precision floating-point numbers which maintain 106 bits (approximately 30
 * decimal digits) of precision.
 *
 * <p>A DoubleDouble uses a representation containing two double-precision values. A number x is
 * represented as a pair of doubles, x.hi and x.lo, such that the number represented by x is x.hi +
 * x.lo, where
 *
 * <p>|x.lo| <= 0.5*ulp(x.hi)
 *
 * <p>and ulp(y) means "unit in the last place of y". The basic arithmetic operations are
 * implemented using convenient properties of IEEE-754 floating-point arithmetic.
 *
 * <p>The range of values which can be represented is the same as in IEEE-754. The precision of the
 * representable numbers is twice as great as IEEE-754 double precision.
 *
 * <p>The correctness of the arithmetic algorithms relies on operations being performed with
 * standard IEEE-754 double precision and rounding. This is the Java standard arithmetic model, but
 * for performance reasons Java implementations are not constrained to using this standard by
 * default. Some processors (notably the Intel Pentium architecure) perform floating point
 * operations in (non-IEEE-754-standard) extended-precision. A JVM implementation may choose to use
 * the non-standard extended-precision as its default arithmetic mode. To prevent this from
 * happening, this code uses the Java <tt>strictfp</tt> modifier, which forces all operations to
 * take place in the standard IEEE-754 rounding model.
 *
 * <p>The API provides both a set of value-oriented operations and a set of mutating operations.
 * Value-oriented operations treat DoubleDouble values as immutable; operations on them return new
 * objects carrying the result of the operation. This provides a simple and safe semantics for
 * writing DoubleDouble expressions. However, there is a performance penalty for the object
 * allocations required. The mutable interface updates object values in-place. It provides optimum
 * memory performance, but requires care to ensure that aliasing errors are not created and constant
 * values are not changed.
 *
 * <p>This implementation uses algorithms originally designed variously by Knuth, Kahan, Dekker, and
 * Linnainmaa. Douglas Priest developed the first C implementation of these techniques. Other more
 * recent C++ implementation are due to Keith M. Briggs and David Bailey et al.
 *
 * @author Martin Davis
 */
public final strictfp class WB_DoubleDouble implements Serializable, Comparable<Object>, Cloneable {
  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = -2751466014056438637L;
  /** The value nearest to the constant Pi. */
  public static final WB_DoubleDouble PI =
      new WB_DoubleDouble(3.141592653589793116e+00, 1.224646799147353207e-16);
  /** The value nearest to the constant 2 * Pi. */
  public static final WB_DoubleDouble TWO_PI =
      new WB_DoubleDouble(6.283185307179586232e+00, 2.449293598294706414e-16);
  /** The value nearest to the constant Pi / 2. */
  public static final WB_DoubleDouble PI_2 =
      new WB_DoubleDouble(1.570796326794896558e+00, 6.123233995736766036e-17);
  /** The value nearest to the constant e (the natural logarithm base). */
  public static final WB_DoubleDouble E =
      new WB_DoubleDouble(2.718281828459045091e+00, 1.445646891729250158e-16);
  /** A value representing the result of an operation which does not return a valid number. */
  public static final WB_DoubleDouble NaN = new WB_DoubleDouble(Double.NaN, Double.NaN);
  /** The smallest representable relative difference between two {link @ DoubleDouble} values. */
  public static final double EPS = 1.23259516440783e-32; /* = 2^-106 */
  /** The Constant ZERO. */
  public static final WB_DoubleDouble ZERO = new WB_DoubleDouble(0.0, 0.0);

  /**
   * Creates the na n.
   *
   * @return the w b_ double double
   */
  private static WB_DoubleDouble createNaN() {
    return new WB_DoubleDouble(Double.NaN, Double.NaN);
  }

  /**
   * Converts the string argument to a DoubleDouble number.
   *
   * @param str a string containing a representation of a numeric value
   * @return the extended precision version of the value
   * @throws NumberFormatException if <tt>s</tt> is not a valid representation of a number
   */
  public static WB_DoubleDouble valueOf(final String str) throws NumberFormatException {
    return parse(str);
  }

  /**
   * Converts the <tt>double</tt> argument to a DoubleDouble number.
   *
   * @param x a numeric value
   * @return the extended precision version of the value
   */
  public static WB_DoubleDouble valueOf(final double x) {
    return new WB_DoubleDouble(x);
  }

  /** The value to split a double-precision value on during multiplication. */
  private static final double SPLIT = 134217729.0D; // 2^27+1, for IEEE double
  /** The high-order component of the double-double precision value. */
  private double hi = 0.0;
  /** The low-order component of the double-double precision value. */
  private double lo = 0.0;

  /** Creates a new DoubleDouble with value 0.0. */
  public WB_DoubleDouble() {
    init(0.0);
  }

  /**
   * Creates a new DoubleDouble with value x.
   *
   * @param x the value to initialize
   */
  public WB_DoubleDouble(final double x) {
    init(x);
  }

  /**
   * Creates a new DoubleDouble with value (hi, lo).
   *
   * @param hi the high-order component
   * @param lo the high-order component
   */
  public WB_DoubleDouble(final double hi, final double lo) {
    init(hi, lo);
  }

  /**
   * Creates a new DoubleDouble with value equal to the argument.
   *
   * @param dd the value to initialize
   */
  public WB_DoubleDouble(final WB_DoubleDouble dd) {
    init(dd);
  }

  /**
   * Creates a new DoubleDouble with value equal to the argument.
   *
   * @param str the value to initialize by
   * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
   */
  public WB_DoubleDouble(final String str) throws NumberFormatException {
    this(parse(str));
  }

  /**
   * Creates a new DoubleDouble with the value of the argument.
   *
   * @param dd the DoubleDouble value to copy
   * @return a copy of the input value
   */
  public static WB_DoubleDouble copy(final WB_DoubleDouble dd) {
    return new WB_DoubleDouble(dd);
  }

  /**
   * Creates and returns a copy of this value.
   *
   * @return a copy of this value
   */
  @Override
  public Object clone() {
    try {
      return super.clone();
    } catch (final CloneNotSupportedException ex) {
      // should never reach here
      return null;
    }
  }

  /**
   * Inits the.
   *
   * @param x the x
   */
  private void init(final double x) {
    init(x, 0.0);
  }

  /**
   * Inits the.
   *
   * @param hi the hi
   * @param lo the lo
   */
  private void init(final double hi, final double lo) {
    this.hi = hi;
    this.lo = lo;
  }

  /**
   * Inits the.
   *
   * @param dd the dd
   */
  private void init(final WB_DoubleDouble dd) {
    init(dd.hi, dd.lo);
  }

  /**
   * Returns a DoubleDouble whose value is <tt>(this + y)</tt>.
   *
   * @param y the addend
   * @return <tt>(this + y)</tt>
   */
  public WB_DoubleDouble add(final WB_DoubleDouble y) {
    return copy(this).selfAdd(y);
  }

  /**
   * Returns a DoubleDouble whose value is <tt>(this + y)</tt>.
   *
   * @param y the addend
   * @return <tt>(this + y)</tt>
   */
  public WB_DoubleDouble add(final double y) {
    return copy(this).selfAdd(y);
  }

  /**
   * Adds the argument to the value of <tt>this</tt>. To prevent altering constants, this method
   * <b>must only</b> be used on values known to be newly created.
   *
   * @param y the addend
   * @return this object, increased by y
   */
  public WB_DoubleDouble selfAdd(final WB_DoubleDouble y) {
    return selfAdd(y.hi, y.lo);
  }

  /**
   * Adds the argument to the value of <tt>this</tt>. To prevent altering constants, this method
   * <b>must only</b> be used on values known to be newly created.
   *
   * @param y the addend
   * @return this object, increased by y
   */
  public WB_DoubleDouble selfAdd(final double y) {
    return selfAdd(y, 0.0);
  }

  /**
   * Self add.
   *
   * @param yhi the yhi
   * @param ylo the ylo
   * @return the w b_ double double
   */
  private WB_DoubleDouble selfAdd(final double yhi, final double ylo) {
    double H, h, T, t, S, s, e, f;
    S = hi + yhi;
    T = lo + ylo;
    e = S - hi;
    f = T - lo;
    s = S - e;
    t = T - f;
    s = (yhi - e) + (hi - s);
    t = (ylo - f) + (lo - t);
    e = s + T;
    H = S + e;
    h = e + (S - H);
    e = t + h;
    final double zhi = H + e;
    final double zlo = e + (H - zhi);
    hi = zhi;
    lo = zlo;
    return this;
  }

  /**
   * Computes a new DoubleDouble object whose value is <tt>(this - y)</tt>.
   *
   * @param y the subtrahend
   * @return <tt>(this - y)</tt>
   */
  public WB_DoubleDouble subtract(final WB_DoubleDouble y) {
    return add(y.negate());
  }

  /**
   * Computes a new DoubleDouble object whose value is <tt>(this - y)</tt>.
   *
   * @param y the subtrahend
   * @return <tt>(this - y)</tt>
   */
  public WB_DoubleDouble subtract(final double y) {
    return add(-y);
  }

  /**
   * Subtracts the argument from the value of <tt>this</tt>. To prevent altering constants, this
   * method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the addend
   * @return this object, decreased by y
   */
  public WB_DoubleDouble selfSubtract(final WB_DoubleDouble y) {
    if (isNaN()) {
      return this;
    }
    return selfAdd(-y.hi, -y.lo);
  }

  /**
   * Subtracts the argument from the value of <tt>this</tt>. To prevent altering constants, this
   * method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the addend
   * @return this object, decreased by y
   */
  public WB_DoubleDouble selfSubtract(final double y) {
    if (isNaN()) {
      return this;
    }
    return selfAdd(-y, 0.0);
  }

  /**
   * Returns a DoubleDouble whose value is <tt>-this</tt>.
   *
   * @return <tt>-this</tt>
   */
  public WB_DoubleDouble negate() {
    if (isNaN()) {
      return this;
    }
    return new WB_DoubleDouble(-hi, -lo);
  }

  /**
   * Returns a new DoubleDouble whose value is <tt>(this * y)</tt>.
   *
   * @param y the multiplicand
   * @return <tt>(this * y)</tt>
   */
  public WB_DoubleDouble multiply(final WB_DoubleDouble y) {
    if (y.isNaN()) {
      return createNaN();
    }
    return copy(this).selfMultiply(y);
  }

  /**
   * Returns a new DoubleDouble whose value is <tt>(this * y)</tt>.
   *
   * @param y the multiplicand
   * @return <tt>(this * y)</tt>
   */
  public WB_DoubleDouble multiply(final double y) {
    if (Double.isNaN(y)) {
      return createNaN();
    }
    return copy(this).selfMultiply(y, 0.0);
  }

  /**
   * Multiplies this object by the argument, returning <tt>this</tt>. To prevent altering constants,
   * this method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the value to multiply by
   * @return this object, multiplied by y
   */
  public WB_DoubleDouble selfMultiply(final WB_DoubleDouble y) {
    return selfMultiply(y.hi, y.lo);
  }

  /**
   * Multiplies this object by the argument, returning <tt>this</tt>. To prevent altering constants,
   * this method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the value to multiply by
   * @return this object, multiplied by y
   */
  public WB_DoubleDouble selfMultiply(final double y) {
    return selfMultiply(y, 0.0);
  }

  /**
   * Self multiply.
   *
   * @param yhi the yhi
   * @param ylo the ylo
   * @return the w b_ double double
   */
  private WB_DoubleDouble selfMultiply(final double yhi, final double ylo) {
    double hx, tx, hy, ty, C, c;
    C = SPLIT * hi;
    hx = C - hi;
    c = SPLIT * yhi;
    hx = C - hx;
    tx = hi - hx;
    hy = c - yhi;
    C = hi * yhi;
    hy = c - hy;
    ty = yhi - hy;
    c = (((((hx * hy) - C) + (hx * ty)) + (tx * hy)) + (tx * ty)) + ((hi * ylo) + (lo * yhi));
    final double zhi = C + c;
    hx = C - zhi;
    final double zlo = c + hx;
    hi = zhi;
    lo = zlo;
    return this;
  }

  /**
   * Computes a new DoubleDouble whose value is <tt>(this / y)</tt>.
   *
   * @param y the divisor
   * @return a new object with the value <tt>(this / y)</tt>
   */
  public WB_DoubleDouble divide(final WB_DoubleDouble y) {
    double hc, tc, hy, ty, C, c, U, u;
    C = hi / y.hi;
    c = SPLIT * C;
    hc = c - C;
    u = SPLIT * y.hi;
    hc = c - hc;
    tc = C - hc;
    hy = u - y.hi;
    U = C * y.hi;
    hy = u - hy;
    ty = y.hi - hy;
    u = ((((hc * hy) - U) + (hc * ty)) + (tc * hy)) + (tc * ty);
    c = ((((hi - U) - u) + lo) - (C * y.lo)) / y.hi;
    u = C + c;
    final double zhi = u;
    final double zlo = (C - u) + c;
    return new WB_DoubleDouble(zhi, zlo);
  }

  /**
   * Computes a new DoubleDouble whose value is <tt>(this / y)</tt>.
   *
   * @param y the divisor
   * @return a new object with the value <tt>(this / y)</tt>
   */
  public WB_DoubleDouble divide(final double y) {
    if (Double.isNaN(y)) {
      return createNaN();
    }
    return copy(this).selfDivide(y, 0.0);
  }

  /**
   * Divides this object by the argument, returning <tt>this</tt>. To prevent altering constants,
   * this method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the value to divide by
   * @return this object, divided by y
   */
  public WB_DoubleDouble selfDivide(final WB_DoubleDouble y) {
    return selfDivide(y.hi, y.lo);
  }

  /**
   * Divides this object by the argument, returning <tt>this</tt>. To prevent altering constants,
   * this method <b>must only</b> be used on values known to be newly created.
   *
   * @param y the value to divide by
   * @return this object, divided by y
   */
  public WB_DoubleDouble selfDivide(final double y) {
    return selfDivide(y, 0.0);
  }

  /**
   * Self divide.
   *
   * @param yhi the yhi
   * @param ylo the ylo
   * @return the w b_ double double
   */
  private WB_DoubleDouble selfDivide(final double yhi, final double ylo) {
    double hc, tc, hy, ty, C, c, U, u;
    C = hi / yhi;
    c = SPLIT * C;
    hc = c - C;
    u = SPLIT * yhi;
    hc = c - hc;
    tc = C - hc;
    hy = u - yhi;
    U = C * yhi;
    hy = u - hy;
    ty = yhi - hy;
    u = ((((hc * hy) - U) + (hc * ty)) + (tc * hy)) + (tc * ty);
    c = ((((hi - U) - u) + lo) - (C * ylo)) / yhi;
    u = C + c;
    hi = u;
    lo = (C - u) + c;
    return this;
  }

  /**
   * Returns a DoubleDouble whose value is <tt>1 / this</tt>.
   *
   * @return the reciprocal of this value
   */
  public WB_DoubleDouble reciprocal() {
    double hc, tc, hy, ty, C, c, U, u;
    C = 1.0 / hi;
    c = SPLIT * C;
    hc = c - C;
    u = SPLIT * hi;
    hc = c - hc;
    tc = C - hc;
    hy = u - hi;
    U = C * hi;
    hy = u - hy;
    ty = hi - hy;
    u = ((((hc * hy) - U) + (hc * ty)) + (tc * hy)) + (tc * ty);
    c = ((((1.0 - U) - u)) - (C * lo)) / hi;
    final double zhi = C + c;
    final double zlo = (C - zhi) + c;
    return new WB_DoubleDouble(zhi, zlo);
  }

  /**
   * Returns the largest (closest to positive infinity) value that is not greater than the argument
   * and is equal to a mathematical integer. Special cases:
   *
   * <ul>
   *   <li>If this value is NaN, returns NaN.
   * </ul>
   *
   * @return the largest (closest to positive infinity) value that is not greater than the argument
   *     and is equal to a mathematical integer.
   */
  public WB_DoubleDouble floor() {
    if (isNaN()) {
      return NaN;
    }
    final double fhi = Math.floor(hi);
    double flo = 0.0;
    // Hi is already integral. Floor the low word
    if (fhi == hi) {
      flo = Math.floor(lo);
    }
    // do we need to renormalize here?
    return new WB_DoubleDouble(fhi, flo);
  }

  /**
   * Returns the smallest (closest to negative infinity) value that is not less than the argument
   * and is equal to a mathematical integer. Special cases:
   *
   * <ul>
   *   <li>If this value is NaN, returns NaN.
   * </ul>
   *
   * @return the smallest (closest to negative infinity) value that is not less than the argument
   *     and is equal to a mathematical integer.
   */
  public WB_DoubleDouble ceil() {
    if (isNaN()) {
      return NaN;
    }
    final double fhi = Math.ceil(hi);
    double flo = 0.0;
    // Hi is already integral. Ceil the low word
    if (fhi == hi) {
      flo = Math.ceil(lo);
      // do we need to renormalize here?
    }
    return new WB_DoubleDouble(fhi, flo);
  }

  /**
   * Returns an integer indicating the sign of this value.
   *
   * <ul>
   *   <li>if this value is > 0, returns 1
   *   <li>if this value is < 0, returns -1
   *   <li>if this value is = 0, returns 0
   *   <li>if this value is NaN, returns 0
   * </ul>
   *
   * @return an integer indicating the sign of this value
   */
  public int signum() {
    if (isPositive()) {
      return 1;
    }
    if (isNegative()) {
      return -1;
    }
    return 0;
  }

  /**
   * Rounds this value to the nearest integer. The value is rounded to an integer by adding 1/2 and
   * taking the floor of the result. Special cases:
   *
   * <ul>
   *   <li>If this value is NaN, returns NaN.
   * </ul>
   *
   * @return this value rounded to the nearest integer
   */
  public WB_DoubleDouble rint() {
    if (isNaN()) {
      return this;
    }
    // may not be 100% correct
    final WB_DoubleDouble plus5 = this.add(0.5);
    return plus5.floor();
  }

  /**
   * Returns the integer which is largest in absolute value and not further from zero than this
   * value. Special cases:
   *
   * <ul>
   *   <li>If this value is NaN, returns NaN.
   * </ul>
   *
   * @return the integer which is largest in absolute value and not further from zero than this
   *     value
   */
  public WB_DoubleDouble trunc() {
    if (isNaN()) {
      return NaN;
    }
    if (isPositive()) {
      return floor();
    } else {
      return ceil();
    }
  }

  /**
   * Returns the absolute value of this value. Special cases:
   *
   * <ul>
   *   <li>If this value is NaN, it is returned.
   * </ul>
   *
   * @return the absolute value of this value
   */
  public WB_DoubleDouble abs() {
    if (isNaN()) {
      return NaN;
    }
    if (isNegative()) {
      return negate();
    }
    return new WB_DoubleDouble(this);
  }

  /**
   * Computes the square of this value.
   *
   * @return the square of this value.
   */
  public WB_DoubleDouble sqr() {
    return this.multiply(this);
  }

  /**
   * Computes the square of this value.
   *
   * @param x the x
   * @return the square of this value.
   */
  public static WB_DoubleDouble sqr(final double x) {
    return valueOf(x).selfMultiply(x);
  }

  /**
   * Computes the positive square root of this value. If the number is NaN or negative, NaN is
   * returned.
   *
   * @return the positive square root of this number. If the argument is NaN or less than zero, the
   *     result is NaN.
   */
  public WB_DoubleDouble sqrt() {
    /*
     * Strategy: Use Karp's trick: if x is an approximation to sqrt(a), then
     *
     * sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx)
     *
     * The approximation is accurate to twice the accuracy of x. Also, the
     * multiplication (a*x) and [-]*x can be done with only half the
     * precision.
     */
    if (isZero()) {
      return valueOf(0.0);
    }
    if (isNegative()) {
      return NaN;
    }
    final double x = 1.0 / Math.sqrt(hi);
    final double ax = hi * x;
    final WB_DoubleDouble axdd = valueOf(ax);
    final WB_DoubleDouble diffSq = this.subtract(axdd.sqr());
    final double d2 = diffSq.hi * (x * 0.5);
    return axdd.add(d2);
  }

  /**
   * Sqrt.
   *
   * @param x the x
   * @return the w b_ double double
   */
  public static WB_DoubleDouble sqrt(final double x) {
    return valueOf(x).sqrt();
  }

  /**
   * Computes the value of this number raised to an integral power. Follows semantics of Java
   * Math.pow as closely as possible.
   *
   * @param exp the integer exponent
   * @return x raised to the integral power exp
   */
  public WB_DoubleDouble pow(final int exp) {
    if (exp == 0.0) {
      return valueOf(1.0);
    }
    WB_DoubleDouble r = new WB_DoubleDouble(this);
    WB_DoubleDouble s = valueOf(1.0);
    int n = Math.abs(exp);
    if (n > 1) {
      /* Use binary exponentiation */
      while (n > 0) {
        if ((n % 2) == 1) {
          s.selfMultiply(r);
        }
        n /= 2;
        if (n > 0) {
          r = r.sqr();
        }
      }
    } else {
      s = r;
    }
    /* Compute the reciprocal if n is negative. */
    if (exp < 0) {
      return s.reciprocal();
    }
    return s;
  }

  /*------------------------------------------------------------
   *   Conversion Functions
   *------------------------------------------------------------
   */
  /**
   * Converts this value to the nearest double-precision number.
   *
   * @return the nearest double-precision number to this value
   */
  public double doubleValue() {
    return hi + lo;
  }

  /**
   * Converts this value to the nearest integer.
   *
   * @return the nearest integer to this value
   */
  public int intValue() {
    return (int) hi;
  }

  /*------------------------------------------------------------
   *   Predicates
   *------------------------------------------------------------
   */
  /**
   * Tests whether this value is equal to 0.
   *
   * @return true if this value is equal to 0
   */
  public boolean isZero() {
    return (hi == 0.0) && (lo == 0.0);
  }

  /**
   * Tests whether this value is less than 0.
   *
   * @return true if this value is less than 0
   */
  public boolean isNegative() {
    return (hi < 0.0) || ((hi == 0.0) && (lo < 0.0));
  }

  /**
   * Tests whether this value is greater than 0.
   *
   * @return true if this value is greater than 0
   */
  public boolean isPositive() {
    return (hi > 0.0) || ((hi == 0.0) && (lo > 0.0));
  }

  /**
   * Tests whether this value is NaN.
   *
   * @return true if this value is NaN
   */
  public boolean isNaN() {
    return Double.isNaN(hi);
  }

  /**
   * Tests whether this value is equal to another <tt>DoubleDouble</tt> value.
   *
   * @param y a DoubleDouble value
   * @return true if this value = y
   */
  public boolean equals(final WB_DoubleDouble y) {
    return (hi == y.hi) && (lo == y.lo);
  }

  /**
   * Tests whether this value is greater than another <tt>DoubleDouble</tt> value.
   *
   * @param y a DoubleDouble value
   * @return true if this value > y
   */
  public boolean gt(final WB_DoubleDouble y) {
    return (hi > y.hi) || ((hi == y.hi) && (lo > y.lo));
  }

  /**
   * Tests whether this value is greater than or equals to another <tt>DoubleDouble</tt> value.
   *
   * @param y a DoubleDouble value
   * @return true if this value >= y
   */
  public boolean ge(final WB_DoubleDouble y) {
    return (hi > y.hi) || ((hi == y.hi) && (lo >= y.lo));
  }

  /**
   * Tests whether this value is less than another <tt>DoubleDouble</tt> value.
   *
   * @param y a DoubleDouble value
   * @return true if this value < y
   */
  public boolean lt(final WB_DoubleDouble y) {
    return (hi < y.hi) || ((hi == y.hi) && (lo < y.lo));
  }

  /**
   * Tests whether this value is less than or equal to another <tt>DoubleDouble</tt> value.
   *
   * @param y a DoubleDouble value
   * @return true if this value <= y
   */
  public boolean le(final WB_DoubleDouble y) {
    return (hi < y.hi) || ((hi == y.hi) && (lo <= y.lo));
  }

  /**
   * Compares two DoubleDouble objects numerically.
   *
   * @param o the o
   * @return -1,0 or 1 depending on whether this value is less than, equal to or greater than the
   *     value of <tt>o</tt>
   */
  @Override
  public int compareTo(final Object o) {
    final WB_DoubleDouble other = (WB_DoubleDouble) o;
    if (hi < other.hi) {
      return -1;
    }
    if (hi > other.hi) {
      return 1;
    }
    if (lo < other.lo) {
      return -1;
    }
    if (lo > other.lo) {
      return 1;
    }
    return 0;
  }

  /*------------------------------------------------------------
   *   Output
   *------------------------------------------------------------
   */
  /** The Constant MAX_PRINT_DIGITS. */
  private static final int MAX_PRINT_DIGITS = 32;
  /** The Constant TEN. */
  private static final WB_DoubleDouble TEN = WB_DoubleDouble.valueOf(10.0);
  /** The Constant ONE. */
  private static final WB_DoubleDouble ONE = WB_DoubleDouble.valueOf(1.0);
  /** The Constant SCI_NOT_EXPONENT_CHAR. */
  private static final String SCI_NOT_EXPONENT_CHAR = "E";
  /** The Constant SCI_NOT_ZERO. */
  private static final String SCI_NOT_ZERO = "0.0E0";

  /**
   * Dumps the components of this number to a string.
   *
   * @return a string showing the components of the number
   */
  public String dump() {
    return "DD<" + hi + ", " + lo + ">";
  }

  /**
   * Returns a string representation of this number, in either standard or scientific notation. If
   * the magnitude of the number is in the range [ 10<sup>-3</sup>, 10<sup>8</sup> ] standard
   * notation will be used. Otherwise, scientific notation will be used.
   *
   * @return a string representation of this number
   */
  @Override
  public String toString() {
    final int mag = magnitude(hi);
    if ((mag >= -3) && (mag <= 20)) {
      return toStandardNotation();
    }
    return toSciNotation();
  }

  /**
   * Returns the string representation of this value in standard notation.
   *
   * @return the string representation in standard notation
   */
  public String toStandardNotation() {
    final String specialStr = getSpecialNumberString();
    if (specialStr != null) {
      return specialStr;
    }
    final int[] magnitude = new int[1];
    final String sigDigits = extractSignificantDigits(true, magnitude);
    final int decimalPointPos = magnitude[0] + 1;
    String num = sigDigits;
    // add a leading 0 if the decimal point is the first char
    if (sigDigits.charAt(0) == '.') {
      num = "0" + sigDigits;
    } else if (decimalPointPos < 0) {
      num = "0." + stringOfChar('0', -decimalPointPos) + sigDigits;
    } else if (sigDigits.indexOf('.') == -1) {
      // no point inserted - sig digits must be smaller than magnitude of
      // number
      // add zeroes to end to make number the correct size
      final int numZeroes = decimalPointPos - sigDigits.length();
      final String zeroes = stringOfChar('0', numZeroes);
      num = sigDigits + zeroes + ".0";
    }
    if (this.isNegative()) {
      return "-" + num;
    }
    return num;
  }

  /**
   * Returns the string representation of this value in scientific notation.
   *
   * @return the string representation in scientific notation
   */
  public String toSciNotation() {
    // special case zero, to allow as
    if (isZero()) {
      return SCI_NOT_ZERO;
    }
    final String specialStr = getSpecialNumberString();
    if (specialStr != null) {
      return specialStr;
    }
    final int[] magnitude = new int[1];
    final String digits = extractSignificantDigits(false, magnitude);
    final String expStr = SCI_NOT_EXPONENT_CHAR + magnitude[0];
    // should never have leading zeroes
    // MD - is this correct? Or should we simply strip them if they are
    // present?
    if (digits.charAt(0) == '0') {
      throw new IllegalStateException("Found leading zero: " + digits);
    }
    // add decimal point
    String trailingDigits = "";
    if (digits.length() > 1) {
      trailingDigits = digits.substring(1);
    }
    final String digitsWithDecimal = digits.charAt(0) + "." + trailingDigits;
    if (this.isNegative()) {
      return "-" + digitsWithDecimal + expStr;
    }
    return digitsWithDecimal + expStr;
  }

  /**
   * Extracts the significant digits in the decimal representation of the argument. A decimal point
   * may be optionally inserted in the string of digits (as long as its position lies within the
   * extracted digits - if not, the caller must prepend or append the appropriate zeroes and decimal
   * point).
   *
   * @param insertDecimalPoint the insert decimal point
   * @param magnitude the magnitude
   * @return the string containing the significant digits and possibly a decimal point
   */
  private String extractSignificantDigits(final boolean insertDecimalPoint, final int[] magnitude) {
    WB_DoubleDouble y = this.abs();
    // compute *correct* magnitude of y
    int mag = magnitude(y.hi);
    final WB_DoubleDouble scale = TEN.pow(mag);
    y = y.divide(scale);
    // fix magnitude if off by one
    if (y.gt(TEN)) {
      y = y.divide(TEN);
      mag += 1;
    } else if (y.lt(ONE)) {
      y = y.multiply(TEN);
      mag -= 1;
    }
    final int decimalPointPos = mag + 1;
    final StringBuffer buf = new StringBuffer();
    final int numDigits = MAX_PRINT_DIGITS - 1;
    for (int i = 0; i <= numDigits; i++) {
      if (insertDecimalPoint && (i == decimalPointPos)) {
        buf.append('.');
      }
      final int digit = (int) y.hi;
      // System.out.println("printDump: [" + i + "] digit: " + digit +
      // "  y: " + y.dump() + "  buf: " + buf);
      /** This should never happen, due to heuristic checks on remainder below */
      if ((digit < 0) || (digit > 9)) {
        // System.out.println("digit > 10 : " + digit);
        // throw new
        // IllegalStateException("Internal errror: found digit = " +
        // digit);
      }
      /**
       * If a negative remainder is encountered, simply terminate the extraction. This is robust,
       * but maybe slightly inaccurate. My current hypothesis is that negative remainders only occur
       * for very small lo components, so the inaccuracy is tolerable
       */
      if (digit < 0) {
        break;
        // throw new
        // IllegalStateException("Internal errror: found digit = " +
        // digit);
      }
      boolean rebiasBy10 = false;
      char digitChar = 0;
      if (digit > 9) {
        // set flag to re-bias after next 10-shift
        rebiasBy10 = true;
        // output digit will end up being '9'
        digitChar = '9';
      } else {
        digitChar = (char) ('0' + digit);
      }
      buf.append(digitChar);
      y = (y.subtract(WB_DoubleDouble.valueOf(digit)).multiply(TEN));
      if (rebiasBy10) {
        y.selfAdd(TEN);
      }
      boolean continueExtractingDigits = true;
      /**
       * Heuristic check: if the remaining portion of y is non-positive, assume that output is
       * complete
       */
      // if (y.hi <= 0.0)
      // if (y.hi < 0.0)
      // continueExtractingDigits = false;
      /**
       * Check if remaining digits will be 0, and if so don't output them. Do this by comparing the
       * magnitude of the remainder with the expected precision.
       */
      final int remMag = magnitude(y.hi);
      if ((remMag < 0) && (Math.abs(remMag) >= (numDigits - i))) {
        continueExtractingDigits = false;
      }
      if (!continueExtractingDigits) {
        break;
      }
    }
    magnitude[0] = mag;
    return buf.toString();
  }

  /**
   * Creates a string of a given length containing the given character.
   *
   * @param ch the character to be repeated
   * @param len the len of the desired string
   * @return the string
   */
  private static String stringOfChar(final char ch, final int len) {
    final StringBuffer buf = new StringBuffer();
    for (int i = 0; i < len; i++) {
      buf.append(ch);
    }
    return buf.toString();
  }

  /**
   * Returns the string for this value if it has a known representation. (E.g. NaN or 0.0)
   *
   * @return the string for this special number null if the number is not a special number
   */
  private String getSpecialNumberString() {
    if (isZero()) {
      return "0.0";
    }
    if (isNaN()) {
      return "NaN ";
    }
    return null;
  }

  /**
   * Determines the decimal magnitude of a number. The magnitude is the exponent of the greatest
   * power of 10 which is less than or equal to the number.
   *
   * @param x the number to find the magnitude of
   * @return the decimal magnitude of x
   */
  private static int magnitude(final double x) {
    final double xAbs = Math.abs(x);
    final double xLog10 = Math.log(xAbs) / Math.log(10);
    int xMag = (int) Math.floor(xLog10);
    /**
     * Since log computation is inexact, there may be an off-by-one error in the computed magnitude.
     * Following tests that magnitude is correct, and adjusts it if not
     */
    final double xApprox = Math.pow(10, xMag);
    if ((xApprox * 10) <= xAbs) {
      xMag += 1;
    }
    return xMag;
  }

  /*------------------------------------------------------------
   *   Input
   *------------------------------------------------------------
   */
  /**
   * Converts a string representation of a real number into a DoubleDouble value. The format
   * accepted is similar to the standard Java real number syntax. It is defined by the following
   * regular expression:
   *
   * <pre>
   * [<tt>+</tt>|<tt>-</tt>] {<i>digit</i>} [ <tt>.</tt> {<i>digit</i>} ] [ ( <tt>e</tt> | <tt>E</tt> ) [<tt>+</tt>|<tt>-</tt>
   * ] {<i>digit</i>}+
   *
   * </pre>
   *
   * @param str the string to parse
   * @return the value of the parsed number
   * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
   */
  public static WB_DoubleDouble parse(final String str) throws NumberFormatException {
    int i = 0;
    final int strlen = str.length();
    // skip leading whitespace
    while (Character.isWhitespace(str.charAt(i))) {
      i++;
    }
    // check for sign
    boolean isNegative = false;
    if (i < strlen) {
      final char signCh = str.charAt(i);
      if ((signCh == '-') || (signCh == '+')) {
        i++;
        if (signCh == '-') {
          isNegative = true;
        }
      }
    }
    // scan all digits and accumulate into an integral value
    // Keep track of the location of the decimal point (if any) to allow
    // scaling later
    final WB_DoubleDouble val = new WB_DoubleDouble();
    int numDigits = 0;
    int numBeforeDec = 0;
    int exp = 0;
    while (true) {
      if (i >= strlen) {
        break;
      }
      final char ch = str.charAt(i);
      i++;
      if (Character.isDigit(ch)) {
        final double d = ch - '0';
        val.selfMultiply(TEN);
        // MD: need to optimize this
        val.selfAdd(d);
        numDigits++;
        continue;
      }
      if (ch == '.') {
        numBeforeDec = numDigits;
        continue;
      }
      if ((ch == 'e') || (ch == 'E')) {
        final String expStr = str.substring(i);
        // this should catch any format problems with the exponent
        try {
          exp = Integer.parseInt(expStr);
        } catch (final NumberFormatException ex) {
          throw new NumberFormatException("Invalid exponent " + expStr + " in string " + str);
        }
        break;
      }
      throw new NumberFormatException(
          "Unexpected character '" + ch + "' at position " + i + " in string " + str);
    }
    WB_DoubleDouble val2 = val;
    // scale the number correctly
    final int numDecPlaces = numDigits - numBeforeDec - exp;
    if (numDecPlaces == 0) {
      val2 = val;
    } else if (numDecPlaces > 0) {
      final WB_DoubleDouble scale = TEN.pow(numDecPlaces);
      val2 = val.divide(scale);
    } else if (numDecPlaces < 0) {
      final WB_DoubleDouble scale = TEN.pow(-numDecPlaces);
      val2 = val.multiply(scale);
    }
    // apply leading sign, if any
    if (isNegative) {
      return val2.negate();
    }
    return val2;
  }
}
Пример #5
0
 /**
  * Returns a new DoubleDouble whose value is <tt>(this * y)</tt>.
  *
  * @param y the multiplicand
  * @return <tt>(this * y)</tt>
  */
 public WB_DoubleDouble multiply(final WB_DoubleDouble y) {
   if (y.isNaN()) {
     return createNaN();
   }
   return copy(this).selfMultiply(y);
 }
Пример #6
0
 /**
  * Computes a new DoubleDouble object whose value is <tt>(this - y)</tt>.
  *
  * @param y the subtrahend
  * @return <tt>(this - y)</tt>
  */
 public WB_DoubleDouble subtract(final WB_DoubleDouble y) {
   return add(y.negate());
 }
Пример #7
0
 /**
  * Converts a string representation of a real number into a DoubleDouble value. The format
  * accepted is similar to the standard Java real number syntax. It is defined by the following
  * regular expression:
  *
  * <pre>
  * [<tt>+</tt>|<tt>-</tt>] {<i>digit</i>} [ <tt>.</tt> {<i>digit</i>} ] [ ( <tt>e</tt> | <tt>E</tt> ) [<tt>+</tt>|<tt>-</tt>
  * ] {<i>digit</i>}+
  *
  * </pre>
  *
  * @param str the string to parse
  * @return the value of the parsed number
  * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
  */
 public static WB_DoubleDouble parse(final String str) throws NumberFormatException {
   int i = 0;
   final int strlen = str.length();
   // skip leading whitespace
   while (Character.isWhitespace(str.charAt(i))) {
     i++;
   }
   // check for sign
   boolean isNegative = false;
   if (i < strlen) {
     final char signCh = str.charAt(i);
     if ((signCh == '-') || (signCh == '+')) {
       i++;
       if (signCh == '-') {
         isNegative = true;
       }
     }
   }
   // scan all digits and accumulate into an integral value
   // Keep track of the location of the decimal point (if any) to allow
   // scaling later
   final WB_DoubleDouble val = new WB_DoubleDouble();
   int numDigits = 0;
   int numBeforeDec = 0;
   int exp = 0;
   while (true) {
     if (i >= strlen) {
       break;
     }
     final char ch = str.charAt(i);
     i++;
     if (Character.isDigit(ch)) {
       final double d = ch - '0';
       val.selfMultiply(TEN);
       // MD: need to optimize this
       val.selfAdd(d);
       numDigits++;
       continue;
     }
     if (ch == '.') {
       numBeforeDec = numDigits;
       continue;
     }
     if ((ch == 'e') || (ch == 'E')) {
       final String expStr = str.substring(i);
       // this should catch any format problems with the exponent
       try {
         exp = Integer.parseInt(expStr);
       } catch (final NumberFormatException ex) {
         throw new NumberFormatException("Invalid exponent " + expStr + " in string " + str);
       }
       break;
     }
     throw new NumberFormatException(
         "Unexpected character '" + ch + "' at position " + i + " in string " + str);
   }
   WB_DoubleDouble val2 = val;
   // scale the number correctly
   final int numDecPlaces = numDigits - numBeforeDec - exp;
   if (numDecPlaces == 0) {
     val2 = val;
   } else if (numDecPlaces > 0) {
     final WB_DoubleDouble scale = TEN.pow(numDecPlaces);
     val2 = val.divide(scale);
   } else if (numDecPlaces < 0) {
     final WB_DoubleDouble scale = TEN.pow(-numDecPlaces);
     val2 = val.multiply(scale);
   }
   // apply leading sign, if any
   if (isNegative) {
     return val2.negate();
   }
   return val2;
 }
Пример #8
0
 /**
  * Extracts the significant digits in the decimal representation of the argument. A decimal point
  * may be optionally inserted in the string of digits (as long as its position lies within the
  * extracted digits - if not, the caller must prepend or append the appropriate zeroes and decimal
  * point).
  *
  * @param insertDecimalPoint the insert decimal point
  * @param magnitude the magnitude
  * @return the string containing the significant digits and possibly a decimal point
  */
 private String extractSignificantDigits(final boolean insertDecimalPoint, final int[] magnitude) {
   WB_DoubleDouble y = this.abs();
   // compute *correct* magnitude of y
   int mag = magnitude(y.hi);
   final WB_DoubleDouble scale = TEN.pow(mag);
   y = y.divide(scale);
   // fix magnitude if off by one
   if (y.gt(TEN)) {
     y = y.divide(TEN);
     mag += 1;
   } else if (y.lt(ONE)) {
     y = y.multiply(TEN);
     mag -= 1;
   }
   final int decimalPointPos = mag + 1;
   final StringBuffer buf = new StringBuffer();
   final int numDigits = MAX_PRINT_DIGITS - 1;
   for (int i = 0; i <= numDigits; i++) {
     if (insertDecimalPoint && (i == decimalPointPos)) {
       buf.append('.');
     }
     final int digit = (int) y.hi;
     // System.out.println("printDump: [" + i + "] digit: " + digit +
     // "  y: " + y.dump() + "  buf: " + buf);
     /** This should never happen, due to heuristic checks on remainder below */
     if ((digit < 0) || (digit > 9)) {
       // System.out.println("digit > 10 : " + digit);
       // throw new
       // IllegalStateException("Internal errror: found digit = " +
       // digit);
     }
     /**
      * If a negative remainder is encountered, simply terminate the extraction. This is robust,
      * but maybe slightly inaccurate. My current hypothesis is that negative remainders only occur
      * for very small lo components, so the inaccuracy is tolerable
      */
     if (digit < 0) {
       break;
       // throw new
       // IllegalStateException("Internal errror: found digit = " +
       // digit);
     }
     boolean rebiasBy10 = false;
     char digitChar = 0;
     if (digit > 9) {
       // set flag to re-bias after next 10-shift
       rebiasBy10 = true;
       // output digit will end up being '9'
       digitChar = '9';
     } else {
       digitChar = (char) ('0' + digit);
     }
     buf.append(digitChar);
     y = (y.subtract(WB_DoubleDouble.valueOf(digit)).multiply(TEN));
     if (rebiasBy10) {
       y.selfAdd(TEN);
     }
     boolean continueExtractingDigits = true;
     /**
      * Heuristic check: if the remaining portion of y is non-positive, assume that output is
      * complete
      */
     // if (y.hi <= 0.0)
     // if (y.hi < 0.0)
     // continueExtractingDigits = false;
     /**
      * Check if remaining digits will be 0, and if so don't output them. Do this by comparing the
      * magnitude of the remainder with the expected precision.
      */
     final int remMag = magnitude(y.hi);
     if ((remMag < 0) && (Math.abs(remMag) >= (numDigits - i))) {
       continueExtractingDigits = false;
     }
     if (!continueExtractingDigits) {
       break;
     }
   }
   magnitude[0] = mag;
   return buf.toString();
 }