/**
   * Return the x-value corresponding to a vertical asymptote between two bounds. If the x-value
   * does not exist, return Double.NaN.
   *
   * @param left the left bound
   * @param right the right bound
   * @return the x-value
   */
  protected double findVA(double left, double right) {
    double step = (right - left) / 10, firstY, nextY, firstX = left, nextX;

    do {
      nextX = firstX + step;
      firstY = evaluate(firstX);
      nextY = evaluate(nextX);

      if ((isPositive(firstY) != isPositive(nextY))
          || (Double.isNaN(firstY) != Double.isNaN(nextY))
          || (isPositive(differentiate(firstX)) != isPositive(differentiate(nextX)))) {
        step /= -10;
      }

      if (firstX > right) {
        return Double.NaN;
      }

      if (detectConvergence(firstX, nextX)) {
        if (Double.isNaN(Math.abs(nextY))
            || Double.isNaN(Math.abs(firstY))
            || Math.abs(nextY) > 100
            || Math.abs(firstY) > 100) {
          return firstX;
        } else {
          step = (right - left) / 10;
          nextX = advancePastConvergence(nextX, nextY, step);
        }
      }

      firstX = nextX;
    } while (!(firstX - step > right));
    return Double.NaN;
  }
  /**
   * Compare two doubles for equality by checking their relative difference. This method computes
   * the difference between two values and checks that against the larger value using the desired
   * relative difference.
   *
   * @param num1 the first number to be tested
   * @param num2 the second number to be tested
   * @param relDiff the fraction of the larger number that the difference must be less than
   * @return whether or not the two values are essentially equal
   */
  public static boolean compareDoubles(double num1, double num2, double relDiff) {
    if (Double.isInfinite(num1) && Double.isInfinite(num2)) // check for infinity
    {
      return Double.isNaN(num1 - num2); // will result in NaN only if they are the same sign
    }

    double diff = Math.abs(num2 - num1);
    double max = (Math.abs(num2) > Math.abs(num1)) ? Math.abs(num2) : Math.abs(num1);
    if (max == 0.0) // if max is somehow exactly equal to zero
    {
      return compareToZero(diff, ZERO_EPSILON);
    } else {
      return diff / max < relDiff;
    }
  }
  /**
   * Evaluate the derivative of a function at a given x-value with or without an approximation.
   *
   * @param x the x-value
   * @param useApprox whether or not to use an approximation
   * @return f'(x)
   */
  public double differentiate(double x, boolean useApprox) {
    if (useApprox) {
      final double STEP = Math.pow(10, -5);
      double rightApprox, leftApprox;

      rightApprox = (evaluate(x + STEP) - evaluate(x)) / STEP;
      leftApprox = (evaluate(x - STEP) - evaluate(x)) / -STEP;

      if (Math.abs(rightApprox - leftApprox) < Math.pow(10, -2)) {
        return (rightApprox + leftApprox) / 2;
      } else {
        return Double.NaN;
      }
    } else {
      return differentiate().evaluate(x);
    }
  }
 /**
  * Compare a double to zero using an epsilon value. Intended to be less restrictive than
  * compareDoubles.
  *
  * @param num the number to be tested
  * @param epsilon the value the number must be less than
  * @return whether or not the number is essentially zero
  */
 public static boolean compareToZero(double num, double epsilon) {
   return Math.abs(num) < epsilon;
 }