Log.java

package calculator.functions;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;

import calculator.Expression;
import calculator.IllegalConstruction;
import calculator.atoms.*;
import calculator.operations.Divides;
import ch.obermuhlner.math.big.BigDecimalMath;

/**
 * This class represents the arithmetic binary operation "log(x, base)".
 */
public class Log extends BinaryFunction {

	public Log(Expression base, Expression number) throws IllegalConstruction {
		super(base, number);
		symbol = "log";
	}

	@Override
	public Real op(Real base, Real n) {

		if (base.isNan() || n.isNan()) { // NaN / x = NaN
			return Real.nan();
		}

		if (n.isMinusInf() || n.getValue().doubleValue() < 0
				|| base.isMinusInf() || base.getValue().doubleValue() < 0) {
			throw new IllegalArgumentException("Logarithm of negative number");
		}

		int precision = 0;
		if (base.getValue().precision() > n.getValue().precision())
			precision = base.getValue().precision();
		else
			precision = n.getValue().precision();

		Real logBase, logN = null;
		if (base.isPlusInf()) {
			logBase = Real.plusInf();
		} else {
			logBase = new Real(BigDecimalMath.log(base.getValue(), new MathContext(precision)));
		}

		if (n.isPlusInf()) {
			logN = Real.plusInf();
		} else {
			logN = new Real(BigDecimalMath.log(n.getValue(), new MathContext(precision)));
		}

		// uses the log_b(n) = log_e(n)/log_e(b)

		Divides d;
		try {
			d = new Divides(new ArrayList<>());

			return d.op(logN, logBase);
		} catch (IllegalConstruction e) {
			// won't happen
		}
		return Real.nan();

	}

	@Override
	public Complex op(Complex base, Complex n) {

		// uses the log_b(n) = log_e(n)/log_e(b)

		org.apache.commons.numbers.complex.Complex logBase = base.getValue().log();
		org.apache.commons.numbers.complex.Complex logN = n.getValue().log();

		return new Complex(logN.divide(logBase));

	}

	@Override
	public Real op(IntegerAtom base, IntegerAtom n) {
		// uses the log_b(n) = log_e(n)/log_e(b)

		if (base.getValue() <= 0 || n.getValue() <= 0) {
			throw new IllegalArgumentException("Logarithm of negative number");
		}

		BigDecimal logBase = BigDecimalMath.log(new BigDecimal(base.getValue()), Real.context);
		BigDecimal logN = BigDecimalMath.log(new BigDecimal(n.getValue()), Real.context);

		return new Real(logN.divide(logBase, Real.context));

	}

	@Override
	public Real op(Rationnal base, Rationnal n) {

		if (base.getValue().doubleValue() <= 0 || n.getValue().doubleValue() <= 0) {
			throw new IllegalArgumentException("Logarithm of negative number");
		}

		// uses the log_b(n) = log_e(n)/log_e(b)
		BigDecimal logBase = BigDecimalMath.log(new BigDecimal(base.getValue().doubleValue()), Real.context);
		BigDecimal logN = BigDecimalMath.log(new BigDecimal(n.getValue().doubleValue()), Real.context);

		return new Real(logN.divide(logBase, Real.context));
	}
}