View Javadoc
1   package calculator.functions;
2   
3   import java.math.BigDecimal;
4   import java.math.MathContext;
5   import java.util.ArrayList;
6   
7   import calculator.Expression;
8   import calculator.IllegalConstruction;
9   import calculator.atoms.*;
10  import calculator.operations.Divides;
11  import ch.obermuhlner.math.big.BigDecimalMath;
12  
13  /**
14   * This class represents the arithmetic binary operation "log(x, base)".
15   */
16  public class Log extends BinaryFunction {
17  
18  	public Log(Expression base, Expression number) throws IllegalConstruction {
19  		super(base, number);
20  		symbol = "log";
21  	}
22  
23  	@Override
24  	public Real op(Real base, Real n) {
25  
26  		if (base.isNan() || n.isNan()) { // NaN / x = NaN
27  			return Real.nan();
28  		}
29  
30  		if (n.isMinusInf() || n.getValue().doubleValue() < 0
31  				|| base.isMinusInf() || base.getValue().doubleValue() < 0) {
32  			throw new IllegalArgumentException("Logarithm of negative number");
33  		}
34  
35  		int precision = 0;
36  		if (base.getValue().precision() > n.getValue().precision())
37  			precision = base.getValue().precision();
38  		else
39  			precision = n.getValue().precision();
40  
41  		Real logBase, logN = null;
42  		if (base.isPlusInf()) {
43  			logBase = Real.plusInf();
44  		} else {
45  			logBase = new Real(BigDecimalMath.log(base.getValue(), new MathContext(precision)));
46  		}
47  
48  		if (n.isPlusInf()) {
49  			logN = Real.plusInf();
50  		} else {
51  			logN = new Real(BigDecimalMath.log(n.getValue(), new MathContext(precision)));
52  		}
53  
54  		// uses the log_b(n) = log_e(n)/log_e(b)
55  
56  		Divides d;
57  		try {
58  			d = new Divides(new ArrayList<>());
59  
60  			return d.op(logN, logBase);
61  		} catch (IllegalConstruction e) {
62  			// won't happen
63  		}
64  		return Real.nan();
65  
66  	}
67  
68  	@Override
69  	public Complex op(Complex base, Complex n) {
70  
71  		// uses the log_b(n) = log_e(n)/log_e(b)
72  
73  		org.apache.commons.numbers.complex.Complex logBase = base.getValue().log();
74  		org.apache.commons.numbers.complex.Complex logN = n.getValue().log();
75  
76  		return new Complex(logN.divide(logBase));
77  
78  	}
79  
80  	@Override
81  	public Real op(IntegerAtom base, IntegerAtom n) {
82  		// uses the log_b(n) = log_e(n)/log_e(b)
83  
84  		if (base.getValue() <= 0 || n.getValue() <= 0) {
85  			throw new IllegalArgumentException("Logarithm of negative number");
86  		}
87  
88  		BigDecimal logBase = BigDecimalMath.log(new BigDecimal(base.getValue()), Real.context);
89  		BigDecimal logN = BigDecimalMath.log(new BigDecimal(n.getValue()), Real.context);
90  
91  		return new Real(logN.divide(logBase, Real.context));
92  
93  	}
94  
95  	@Override
96  	public Real op(Rationnal base, Rationnal n) {
97  
98  		if (base.getValue().doubleValue() <= 0 || n.getValue().doubleValue() <= 0) {
99  			throw new IllegalArgumentException("Logarithm of negative number");
100 		}
101 
102 		// uses the log_b(n) = log_e(n)/log_e(b)
103 		BigDecimal logBase = BigDecimalMath.log(new BigDecimal(base.getValue().doubleValue()), Real.context);
104 		BigDecimal logN = BigDecimalMath.log(new BigDecimal(n.getValue().doubleValue()), Real.context);
105 
106 		return new Real(logN.divide(logBase, Real.context));
107 	}
108 }