java - Logarithm of a BigDecimal -
how can calculate logarithm of bigdecimal? know of algorithms can use?
my googling far has come (useless) idea of converting double , using math.log.
i provide precision of answer required.
edit: base do. if it's easier in base x, i'll that.
java number cruncher: java programmer's guide numerical computing provides solution using newton's method. source code book available here. following has been taken chapter 12.5 big decmial functions (p330 & p331):
/** * compute natural logarithm of x given scale, x > 0. */ public static bigdecimal ln(bigdecimal x, int scale) { // check x > 0. if (x.signum() <= 0) { throw new illegalargumentexception("x <= 0"); } // number of digits left of decimal point. int magnitude = x.tostring().length() - x.scale() - 1; if (magnitude < 3) { return lnnewton(x, scale); } // compute magnitude*ln(x^(1/magnitude)). else { // x^(1/magnitude) bigdecimal root = introot(x, magnitude, scale); // ln(x^(1/magnitude)) bigdecimal lnroot = lnnewton(root, scale); // magnitude*ln(x^(1/magnitude)) return bigdecimal.valueof(magnitude).multiply(lnroot) .setscale(scale, bigdecimal.round_half_even); } } /** * compute natural logarithm of x given scale, x > 0. * use newton's algorithm. */ private static bigdecimal lnnewton(bigdecimal x, int scale) { int sp1 = scale + 1; bigdecimal n = x; bigdecimal term; // convergence tolerance = 5*(10^-(scale+1)) bigdecimal tolerance = bigdecimal.valueof(5) .movepointleft(sp1); // loop until approximations converge // (two successive approximations within tolerance). { // e^x bigdecimal etox = exp(x, sp1); // (e^x - n)/e^x term = etox.subtract(n) .divide(etox, sp1, bigdecimal.round_down); // x - (e^x - n)/e^x x = x.subtract(term); thread.yield(); } while (term.compareto(tolerance) > 0); return x.setscale(scale, bigdecimal.round_half_even); } /** * compute integral root of x given scale, x >= 0. * use newton's algorithm. * @param x value of x * @param index integral root value * @param scale desired scale of result * @return result value */ public static bigdecimal introot(bigdecimal x, long index, int scale) { // check x >= 0. if (x.signum() < 0) { throw new illegalargumentexception("x < 0"); } int sp1 = scale + 1; bigdecimal n = x; bigdecimal = bigdecimal.valueof(index); bigdecimal im1 = bigdecimal.valueof(index-1); bigdecimal tolerance = bigdecimal.valueof(5) .movepointleft(sp1); bigdecimal xprev; // initial approximation x/index. x = x.divide(i, scale, bigdecimal.round_half_even); // loop until approximations converge // (two successive approximations equal after rounding). { // x^(index-1) bigdecimal xtoim1 = intpower(x, index-1, sp1); // x^index bigdecimal xtoi = x.multiply(xtoim1) .setscale(sp1, bigdecimal.round_half_even); // n + (index-1)*(x^index) bigdecimal numerator = n.add(im1.multiply(xtoi)) .setscale(sp1, bigdecimal.round_half_even); // (index*(x^(index-1)) bigdecimal denominator = i.multiply(xtoim1) .setscale(sp1, bigdecimal.round_half_even); // x = (n + (index-1)*(x^index)) / (index*(x^(index-1))) xprev = x; x = numerator .divide(denominator, sp1, bigdecimal.round_down); thread.yield(); } while (x.subtract(xprev).abs().compareto(tolerance) > 0); return x; } /** * compute e^x given scale. * break x whole , fraction parts , * compute (e^(1 + fraction/whole))^whole using taylor's formula. * @param x value of x * @param scale desired scale of result * @return result value */ public static bigdecimal exp(bigdecimal x, int scale) { // e^0 = 1 if (x.signum() == 0) { return bigdecimal.valueof(1); } // if x negative, return 1/(e^-x). else if (x.signum() == -1) { return bigdecimal.valueof(1) .divide(exp(x.negate(), scale), scale, bigdecimal.round_half_even); } // compute whole part of x. bigdecimal xwhole = x.setscale(0, bigdecimal.round_down); // if there isn't whole part, compute , return e^x. if (xwhole.signum() == 0) return exptaylor(x, scale); // compute fraction part of x. bigdecimal xfraction = x.subtract(xwhole); // z = 1 + fraction/whole bigdecimal z = bigdecimal.valueof(1) .add(xfraction.divide( xwhole, scale, bigdecimal.round_half_even)); // t = e^z bigdecimal t = exptaylor(z, scale); bigdecimal maxlong = bigdecimal.valueof(long.max_value); bigdecimal result = bigdecimal.valueof(1); // compute , return t^whole using intpower(). // if whole > long.max_value, first compute products // of e^long.max_value. while (xwhole.compareto(maxlong) >= 0) { result = result.multiply( intpower(t, long.max_value, scale)) .setscale(scale, bigdecimal.round_half_even); xwhole = xwhole.subtract(maxlong); thread.yield(); } return result.multiply(intpower(t, xwhole.longvalue(), scale)) .setscale(scale, bigdecimal.round_half_even); }
Comments
Post a Comment