Пример #1
0
  /**
   * Returns {@code true} if there is no double value strictly between the arguments or the reltaive
   * difference between them is smaller or equal to the given tolerance.
   *
   * @param x First value.
   * @param y Second value.
   * @param eps Amount of allowed relative error.
   * @return {@code true} if the values are two adjacent floating point numbers or they are within
   *     range of each other.
   * @since 3.1
   */
  public static boolean equalsWithRelativeTolerance(double x, double y, double eps) {
    if (equals(x, y, 1)) {
      return true;
    }

    final double absoluteMax = FastMath.max(FastMath.abs(x), FastMath.abs(y));
    final double relativeDifference = FastMath.abs((x - y) / absoluteMax);

    return relativeDifference <= eps;
  }
  /**
   * Evaluates the continued fraction at the value x.
   *
   * <p>The implementation of this method is based on equations 14-17 of:
   *
   * <ul>
   *   <li>Eric W. Weisstein. "Continued Fraction." From MathWorld--A Wolfram Web Resource. <a
   *       target="_blank" href="http://mathworld.wolfram.com/ContinuedFraction.html">
   *       http://mathworld.wolfram.com/ContinuedFraction.html</a>
   * </ul>
   *
   * The recurrence relationship defined in those equations can result in very large intermediate
   * results which can result in numerical overflow. As a means to combat these overflow conditions,
   * the intermediate results are scaled whenever they threaten to become numerically unstable.
   *
   * @param x the evaluation point.
   * @param epsilon maximum error allowed.
   * @param maxIterations maximum number of convergents
   * @return the value of the continued fraction evaluated at x.
   * @throws ConvergenceException if the algorithm fails to converge.
   */
  public double evaluate(double x, double epsilon, int maxIterations) {
    double p0 = 1.0;
    double p1 = getA(0, x);
    double q0 = 0.0;
    double q1 = 1.0;
    double c = p1 / q1;
    int n = 0;
    double relativeError = Double.MAX_VALUE;
    while (n < maxIterations && relativeError > epsilon) {
      ++n;
      double a = getA(n, x);
      double b = getB(n, x);
      double p2 = a * p1 + b * p0;
      double q2 = a * q1 + b * q0;
      boolean infinite = false;
      if (Double.isInfinite(p2) || Double.isInfinite(q2)) {
        /*
         * Need to scale. Try successive powers of the larger of a or b
         * up to 5th power. Throw ConvergenceException if one or both
         * of p2, q2 still overflow.
         */
        double scaleFactor = 1d;
        double lastScaleFactor = 1d;
        final int maxPower = 5;
        final double scale = FastMath.max(a, b);
        if (scale <= 0) { // Can't scale
          throw new ConvergenceException(
              LocalizedFormats.CONTINUED_FRACTION_INFINITY_DIVERGENCE, x);
        }
        infinite = true;
        for (int i = 0; i < maxPower; i++) {
          lastScaleFactor = scaleFactor;
          scaleFactor *= scale;
          if (a != 0.0 && a > b) {
            p2 = p1 / lastScaleFactor + (b / scaleFactor * p0);
            q2 = q1 / lastScaleFactor + (b / scaleFactor * q0);
          } else if (b != 0) {
            p2 = (a / scaleFactor * p1) + p0 / lastScaleFactor;
            q2 = (a / scaleFactor * q1) + q0 / lastScaleFactor;
          }
          infinite = Double.isInfinite(p2) || Double.isInfinite(q2);
          if (!infinite) {
            break;
          }
        }
      }

      if (infinite) {
        // Scaling failed
        throw new ConvergenceException(LocalizedFormats.CONTINUED_FRACTION_INFINITY_DIVERGENCE, x);
      }

      double r = p2 / q2;

      if (Double.isNaN(r)) {
        throw new ConvergenceException(LocalizedFormats.CONTINUED_FRACTION_NAN_DIVERGENCE, x);
      }
      relativeError = FastMath.abs(r / c - 1.0);

      // prepare for next iteration
      c = p2 / q2;
      p0 = p1;
      p1 = p2;
      q0 = q1;
      q1 = q2;
    }

    if (n >= maxIterations) {
      throw new MaxCountExceededException(
          LocalizedFormats.NON_CONVERGENT_CONTINUED_FRACTION, maxIterations, x);
    }

    return c;
  }