1
2 package calculator.atoms;
3
4 import java.math.BigDecimal;
5 import java.math.MathContext;
6 import java.math.RoundingMode;
7
8 import calculator.Expression;
9 import calculator.IllegalConstruction;
10 import calculator.operations.Operation;
11 import calculator.atoms.visitor.AtomVisitor;
12 import calculator.functions.BinaryFunction;
13 import calculator.functions.UnaryFunction;
14 import visitor.Visitor;
15
16 /**
17 * Real is a concrete class that represents arithmetic (Real) numbers,
18 * which are Atoms, a special kind of Expressions.
19 *
20 * @see Expression
21 * @see Operation
22 */
23 public class Real implements Atom {
24
25 public static int scale = 64;
26 public static MathContext context = new MathContext(scale + 1, RoundingMode.HALF_EVEN);
27
28 /*
29 * the actual Real value
30 * in case of a special real value it is used to determine which special real
31 * it represents
32 */
33 private final BigDecimal value;
34
35 /*
36 * A boolean flag used to know if the Real is a special value
37 * if the flag is true, there is 3 possibilities :
38 * value = 1 => the Real represents +\inf
39 * value = -1 => the Real represents -\inf
40 * value = 0 => the Real represents a NaN
41 */
42 private boolean special = false;
43
44 /**
45 * getter method to obtain the value contained in the object
46 *
47 * @return The integer number contained in the object
48 */
49 public BigDecimal getValue() {
50 return value;
51 }
52
53 /**
54 * Constructor method for a string
55 *
56 * @param s The string to be represented in the Real
57 */
58 public /* constructor */ Real(String s) {
59 BigDecimal temp = new BigDecimal(s, context);
60 value = temp.setScale(Real.scale, RoundingMode.HALF_EVEN);
61 }
62
63 /**
64 * Constructor method for a BigDecimal
65 *
66 * @param d the BigDecimal to be represented in the Real
67 */
68 public /* constructor */ Real(BigDecimal d) {
69 value = d.setScale(Real.scale, RoundingMode.HALF_EVEN);
70 }
71
72 /**
73 * Constructor method for a double
74 *
75 * @param d The double to be represented in the Real
76 */
77 public /* constructor */ Real(double d) {
78 BigDecimal temp = BigDecimal.valueOf(d);
79 value = temp.setScale(Real.scale, RoundingMode.HALF_EVEN);
80 }
81
82 /**
83 * Constructor method
84 *
85 * @param i The int value to be contained in the object
86 */
87 public /* constructor */ Real(int i) {
88 BigDecimal temp = BigDecimal.valueOf(i);
89 value = temp.setScale(Real.scale, RoundingMode.HALF_EVEN);
90 }
91
92 /**
93 * Constructor for special Reals
94 *
95 * @param v either 1
96 * @throws IllegalConstruction
97 */
98 private /* constructor */ Real(boolean s, int v) {
99 BigDecimal temp = BigDecimal.valueOf(v);
100 value = temp.setScale(Real.scale, RoundingMode.HALF_EVEN);
101 special = s;
102 }
103
104 /**
105 * Returns a NaN Real
106 *
107 * @return A new Real number representing a NaN
108 */
109 public static Real nan() {
110 return new Real(true, 0);
111 };
112
113 /**
114 * Returns a Real representing +infinity
115 *
116 * @return A new Real number representing +infinity
117 */
118 public static Real plusInf() {
119 return new Real(true, 1);
120 };
121
122 /**
123 * Returns a Real representing -infinity
124 *
125 * @return A new Real number representing -infinity
126 */
127 public static Real minusInf() {
128 return new Real(true, -1);
129 };
130
131 /**
132 * Returns if the Real is representing -infinity
133 *
134 * @return if the Real is representing -infinity
135 */
136 public boolean isMinusInf() {
137 return special && value.doubleValue() == -1;
138 }
139
140 /**
141 * Returns if the Real is representing +infinity
142 *
143 * @return if the Real is representing +infinity
144 */
145 public boolean isPlusInf() {
146 return special && value.doubleValue() == 1;
147 }
148
149 /**
150 * Returns if the Real is representing NaN
151 *
152 * @return if the Real is representing NaN
153 */
154 public boolean isNan() {
155 return special && value.doubleValue() == 0;
156 }
157
158 /**
159 * accept method to implement the visitor design pattern to traverse arithmetic
160 * expressions.
161 * Each real number will pass itself to the Atomvisitor object to get processed
162 * by the Atomvisitor.
163 *
164 * @param v The Atomvisitor object
165 */
166 @Override
167 public void accept(AtomVisitor v) {
168 v.visit(this);
169 }
170
171 /**
172 * accept method to implement the visitor design pattern to traverse arithmetic
173 * expressions.
174 * Each real number will pass itself to the visitor object to get processed by
175 * the
176 * visitor.
177 *
178 * @param v The visitor object
179 */
180 @Override
181 public void accept(Visitor v) {
182 v.visit(this);
183 }
184
185 /**
186 * Two Real expressions are equal if the values they contain are equal
187 *
188 * @param o The object to compare to
189 * @return A boolean representing the result of the equality test
190 */
191 @Override
192 public boolean equals(Object o) {
193 // No object should be equal to null (not including this check can result in an
194 // exception if a Real is tested against null)
195 if (o == null)
196 return false;
197
198 // If the object is compared to itself then return true
199 if (o == this) {
200 return true;
201 }
202
203 // If the object is of another type then return false
204 if (!(o instanceof Real)) {
205 return false;
206 }
207 // return the equality between BigDecimals
208 return this.value.equals(((Real) o).getValue()) && special == ((Real) o).special;
209 // return this.value.compareTo(((Real) o).value) == 0;
210 }
211
212 /**
213 * The method hashCode needs to be overridden it the equals method is
214 * overridden;
215 * otherwise there may be problems when you use your object in hashed
216 * collections
217 * such as HashMap, HashSet, LinkedHashSet.
218 *
219 * @return The result of computing the hash.
220 */
221 @Override
222 public int hashCode() {
223 return value.intValue();
224 }
225
226 /**
227 * applies an operation between two Reals
228 *
229 * @param o the operation to apply
230 * @param a the other Real
231 * @return The result of the application of o on a and this instance
232 */
233 @Override
234 public Real apply(Operation o, Atom a) {
235 return o.op(this, (Real) a);
236 }
237
238 @Override
239 public Atom apply(BinaryFunction f, Atom a) {
240 return f.op(this, (Real) a);
241 }
242
243 @Override
244 public Real apply(UnaryFunction o) {
245 return o.op(this);
246 }
247
248 @Override
249 public String toString() { return value.stripTrailingZeros().toPlainString(); }
250 }