/** * 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; }