/** * Test if x is an approximate real root. * * @param x approximate real root. * @param f univariate polynomial, non-zero. * @param fp univariate polynomial, non-zero, deriviative of f. * @param eps requested interval length. * @return true if x is a decimal approximation of a real v with f(v) = 0 with |d-v| < eps, * else false. */ public boolean isApproximateRoot( BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp, BigDecimal eps) { if (x == null) { throw new IllegalArgumentException("null root not allowed"); } if (f == null || f.isZERO() || f.isConstant() || eps == null) { return true; } BigDecimal dc = BigDecimal.ONE; // only for clarity // f(x) BigDecimal fx = PolyUtil.<BigDecimal>evaluateMain(dc, f, x); // System.out.println("fx = " + fx); if (fx.isZERO()) { return true; } // f'(x) BigDecimal fpx = PolyUtil.<BigDecimal>evaluateMain(dc, fp, x); // f'(d) // System.out.println("fpx = " + fpx); if (fpx.isZERO()) { return false; } BigDecimal d = fx.divide(fpx); if (d.isZERO()) { return true; } if (d.abs().compareTo(eps) <= 0) { return true; } System.out.println("x = " + x); System.out.println("d = " + d); return false; }
/** * Approximate real root. * * @param iv real root isolating interval with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, v real. */ public BigDecimal approximateRoot(Interval<C> iv, GenPolynomial<C> f, C eps) throws NoConvergenceException { if (iv == null) { throw new IllegalArgumentException("null interval not allowed"); } BigDecimal d = iv.toDecimal(); if (f == null || f.isZERO() || f.isConstant() || eps == null) { return d; } if (iv.length().compareTo(eps) < 0) { return d; } BigDecimal left = new BigDecimal(iv.left.getRational()); BigDecimal right = new BigDecimal(iv.right.getRational()); BigDecimal e = new BigDecimal(eps.getRational()); BigDecimal q = new BigDecimal("0.25"); // System.out.println("left = " + left); // System.out.println("right = " + right); e = e.multiply(d); // relative error // System.out.println("e = " + e); BigDecimal dc = BigDecimal.ONE; // polynomials with decimal coefficients GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); GenPolynomial<BigDecimal> df = PolyUtil.<C>decimalFromRational(dfac, f); GenPolynomial<C> fp = PolyUtil.<C>baseDeriviative(f); GenPolynomial<BigDecimal> dfp = PolyUtil.<C>decimalFromRational(dfac, fp); // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) int i = 0; final int MITER = 50; int dir = 0; while (i++ < MITER) { BigDecimal fx = PolyUtil.<BigDecimal>evaluateMain(dc, df, d); // f(d) if (fx.isZERO()) { return d; } BigDecimal fpx = PolyUtil.<BigDecimal>evaluateMain(dc, dfp, d); // f'(d) if (fpx.isZERO()) { throw new NoConvergenceException("zero deriviative should not happen"); } BigDecimal x = fx.divide(fpx); BigDecimal dx = d.subtract(x); // System.out.println("dx = " + dx); if (d.subtract(dx).abs().compareTo(e) <= 0) { return dx; } while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) { // dx < left: dx - left < 0 // dx > right: dx - right > 0 // System.out.println("trying to leave interval"); if (i++ > MITER) { // dx > right: dx - right > 0 throw new NoConvergenceException("no convergence after " + i + " steps"); } if (i > MITER / 2 && dir == 0) { BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); d = sd; x = sd.getZERO(); logger.info("trying new random starting point " + d); i = 0; dir = 1; } if (i > MITER / 2 && dir == 1) { BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); d = sd; x = sd.getZERO(); logger.info("trying new random starting point " + d); // i = 0; dir = 2; // end } x = x.multiply(q); // x * 1/4 dx = d.subtract(x); // System.out.println(" x = " + x); // System.out.println("dx = " + dx); } d = dx; } throw new NoConvergenceException("no convergence after " + i + " steps"); }