1 package org.apache.velocity.runtime.parser.node;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.List;
27 import java.util.ArrayList;
28
29 /**
30 * Utility-class for all arithmetic-operations.<br><br>
31 *
32 * All operations (+ - / *) return a Number which type is the type of the bigger argument.<br>
33 * Example:<br>
34 * <code>add ( new Integer(10), new Integer(1))</code> will return an <code>Integer</code>-Object with the value 11<br>
35 * <code>add ( new Long(10), new Integer(1))</code> will return an <code>Long</code>-Object with the value 11<br>
36 * <code>add ( new Integer(10), new Float(1))</code> will return an <code>Float</code>-Object with the value 11<br><br>
37 *
38 * Overflow checking:<br>
39 * For integral values (byte, short, int) there is an implicit overflow correction (the next "bigger"
40 * type will be returned). For example, if you call <code>add (new Integer (Integer.MAX_VALUE), 1)</code> a
41 * <code>Long</code>-object will be returned with the correct value of <code>Integer.MAX_VALUE+1</code>.<br>
42 * In addition to that the methods <code>multiply</code>,<code>add</code> and <code>substract</code> implement overflow
43 * checks for <code>long</code>-values. That means that if an overflow occurs while working with long values a BigInteger
44 * will be returned.<br>
45 * For all other operations and types (such as Float and Double) there is no overflow checking.
46 *
47 * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
48 * @since 1.5
49 */
50 public abstract class MathUtils
51 {
52
53 /**
54 * A BigDecimal representing the number 0
55 */
56 protected static final BigDecimal DECIMAL_ZERO = new BigDecimal ( BigInteger.ZERO );
57
58 /**
59 * The constants are used to determine in which context we have to calculate.
60 */
61 protected static final int BASE_LONG = 0;
62 protected static final int BASE_FLOAT = 1;
63 protected static final int BASE_DOUBLE = 2;
64 protected static final int BASE_BIGINTEGER = 3;
65 protected static final int BASE_BIGDECIMAL = 4;
66
67 /**
68 * The <code>Class</code>-object is key, the maximum-value is the value
69 */
70 protected static final Map ints = new HashMap();
71 static
72 {
73 ints.put (Byte.class, BigDecimal.valueOf (Byte.MAX_VALUE));
74 ints.put (Short.class, BigDecimal.valueOf (Short.MAX_VALUE));
75 ints.put (Integer.class, BigDecimal.valueOf (Integer.MAX_VALUE));
76 ints.put (Long.class, BigDecimal.valueOf (Long.MAX_VALUE));
77 ints.put (BigInteger.class, BigDecimal.valueOf (-1));
78 }
79
80 /**
81 * The "size" of the number-types - ascending.
82 */
83 protected static final List typesBySize = new ArrayList();
84 static
85 {
86 typesBySize.add (Byte.class);
87 typesBySize.add (Short.class);
88 typesBySize.add (Integer.class);
89 typesBySize.add (Long.class);
90 typesBySize.add (Float.class);
91 typesBySize.add (Double.class);
92 }
93
94 /**
95 * Convert the given Number to a BigDecimal
96 * @param n
97 * @return The number as BigDecimal
98 */
99 public static BigDecimal toBigDecimal (Number n)
100 {
101
102 if (n instanceof BigDecimal)
103 {
104 return (BigDecimal)n;
105 }
106
107 if (n instanceof BigInteger)
108 {
109 return new BigDecimal ( (BigInteger)n );
110 }
111
112 return new BigDecimal (n.doubleValue());
113
114 }
115
116 /**
117 * Convert the given Number to a BigInteger
118 * @param n
119 * @return The number as BigInteger
120 */
121 public static BigInteger toBigInteger (Number n)
122 {
123
124 if (n instanceof BigInteger)
125 {
126 return (BigInteger)n;
127 }
128
129 return BigInteger.valueOf (n.longValue());
130
131 }
132
133 /**
134 * Compare the given Number to 0.
135 * @param n
136 * @return True if number is 0.
137 */
138 public static boolean isZero (Number n)
139 {
140 if (isInteger( n ) )
141 {
142 if (n instanceof BigInteger)
143 {
144 return ((BigInteger)n).compareTo (BigInteger.ZERO) == 0;
145 }
146 return n.doubleValue() == 0;
147 }
148 if (n instanceof Float)
149 {
150 return n.floatValue() == 0f;
151 }
152 if (n instanceof Double)
153 {
154 return n.doubleValue() == 0d;
155 }
156 return toBigDecimal( n ).compareTo( DECIMAL_ZERO) == 0;
157 }
158
159 /**
160 * Test, whether the given object is an integer value
161 * (Byte, Short, Integer, Long, BigInteger)
162 * @param n
163 * @return True if n is an integer.
164 */
165 public static boolean isInteger (Number n)
166 {
167 return ints.containsKey (n.getClass());
168 }
169
170 /**
171 * Wrap the given primitive into the given class if the value is in the
172 * range of the destination type. If not the next bigger type will be chosen.
173 * @param value
174 * @param type
175 * @return Number object representing the primitive.
176 */
177 public static Number wrapPrimitive (long value, Class type)
178 {
179 if (type == Byte.class)
180 {
181 if (value > Byte.MAX_VALUE || value < Byte.MIN_VALUE)
182 {
183 type = Short.class;
184 }
185 else
186 {
187 // TODO: JDK 1.4+ -> valueOf()
188 return new Byte ((byte)value);
189 }
190 }
191 if (type == Short.class)
192 {
193 if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
194 {
195 type = Integer.class;
196 }
197 else
198 {
199 // TODO: JDK 1.4+ -> valueOf()
200 return new Short((short)value);
201 }
202 }
203 if (type == Integer.class)
204 {
205 if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)
206 {
207 type = Long.class;
208 }
209 else
210 {
211 // TODO: JDK 1.4+ -> valueOf()
212 return new Integer ((int)value);
213 }
214 }
215 if (type == Long.class)
216 {
217 // TODO: JDK 1.4+ -> valueOf()
218 return new Long (value);
219 }
220 return BigInteger.valueOf( value);
221 }
222
223 /**
224 * Wrap the result in the object of the bigger type.
225 *
226 * @param value result of operation (as a long) - used to check size
227 * @param op1 first operand of binary operation
228 * @param op2 second operand of binary operation
229 * @return Number object of appropriate size to fit the value and operators
230 */
231 private static Number wrapPrimitive (long value, Number op1, Number op2)
232 {
233 if ( typesBySize.indexOf( op1.getClass()) > typesBySize.indexOf( op2.getClass()))
234 {
235 return wrapPrimitive( value, op1.getClass());
236 }
237 return wrapPrimitive( value, op2.getClass());
238 }
239
240 /**
241 * Find the common Number-type to be used in calculations.
242 *
243 * @param op1 first operand of binary operation
244 * @param op2 second operand of binary operation
245 * @return constant indicating type of Number to use in calculations
246 */
247 private static int findCalculationBase (Number op1, Number op2)
248 {
249
250 boolean op1Int = isInteger(op1);
251 boolean op2Int = isInteger(op2);
252
253 if ( (op1 instanceof BigDecimal || op2 instanceof BigDecimal) ||
254 ( (!op1Int || !op2Int) && (op1 instanceof BigInteger || op2 instanceof BigInteger)) )
255 {
256 return BASE_BIGDECIMAL;
257 }
258
259 if (op1Int && op2Int) {
260 if (op1 instanceof BigInteger || op2 instanceof BigInteger)
261 {
262 return BASE_BIGINTEGER;
263 }
264 return BASE_LONG;
265 }
266
267 if ((op1 instanceof Double) || (op2 instanceof Double))
268 {
269 return BASE_DOUBLE;
270 }
271 return BASE_FLOAT;
272 }
273
274 /**
275 * Add two numbers and return the correct value / type.
276 * Overflow detection is done for integer values (byte, short, int, long) only!
277 * @param op1
278 * @param op2
279 * @return Addition result.
280 */
281 public static Number add (Number op1, Number op2)
282 {
283
284 int calcBase = findCalculationBase( op1, op2);
285 switch (calcBase)
286 {
287 case BASE_BIGINTEGER:
288 return toBigInteger( op1 ).add( toBigInteger( op2 ));
289 case BASE_LONG:
290 long l1 = op1.longValue();
291 long l2 = op2.longValue();
292 long result = l1+l2;
293
294 // Overflow check
295 if ((result ^ l1) < 0 && (result ^ l2) < 0)
296 {
297 return toBigInteger( op1).add( toBigInteger( op2));
298 }
299 return wrapPrimitive( result, op1, op2);
300 case BASE_FLOAT:
301 return new Float (op1.floatValue()+op2.floatValue());
302 case BASE_DOUBLE:
303 return new Double (op1.doubleValue()+op2.doubleValue());
304
305 // Default is BigDecimal operation
306 default:
307 return toBigDecimal( op1 ).add( toBigDecimal( op2 ));
308 }
309 }
310
311 /**
312 * Subtract two numbers and return the correct value / type.
313 * Overflow detection is done for integer values (byte, short, int, long) only!
314 * @param op1
315 * @param op2
316 * @return Subtraction result.
317 */
318 public static Number subtract (Number op1, Number op2) {
319
320 int calcBase = findCalculationBase( op1, op2);
321 switch (calcBase) {
322 case BASE_BIGINTEGER:
323 return toBigInteger( op1 ).subtract( toBigInteger( op2 ));
324 case BASE_LONG:
325 long l1 = op1.longValue();
326 long l2 = op2.longValue();
327 long result = l1-l2;
328
329 // Overflow check
330 if ((result ^ l1) < 0 && (result ^ ~l2) < 0) {
331 return toBigInteger( op1).subtract( toBigInteger( op2));
332 }
333 return wrapPrimitive( result, op1, op2);
334 case BASE_FLOAT:
335 return new Float (op1.floatValue()-op2.floatValue());
336 case BASE_DOUBLE:
337 return new Double (op1.doubleValue()-op2.doubleValue());
338
339 // Default is BigDecimal operation
340 default:
341 return toBigDecimal( op1 ).subtract( toBigDecimal( op2 ));
342 }
343 }
344
345 /**
346 * Multiply two numbers and return the correct value / type.
347 * Overflow detection is done for integer values (byte, short, int, long) only!
348 * @param op1
349 * @param op2
350 * @return Multiplication result.
351 */
352 public static Number multiply (Number op1, Number op2) {
353
354 int calcBase = findCalculationBase( op1, op2);
355 switch (calcBase) {
356 case BASE_BIGINTEGER:
357 return toBigInteger( op1 ).multiply( toBigInteger( op2 ));
358 case BASE_LONG:
359 long l1 = op1.longValue();
360 long l2 = op2.longValue();
361 long result = l1*l2;
362
363 // Overflow detection
364 if ((l2 != 0) && (result / l2 != l1)) {
365 return toBigInteger( op1).multiply( toBigInteger( op2));
366 }
367 return wrapPrimitive( result, op1, op2);
368 case BASE_FLOAT:
369 return new Float (op1.floatValue()*op2.floatValue());
370 case BASE_DOUBLE:
371 return new Double (op1.doubleValue()*op2.doubleValue());
372
373 // Default is BigDecimal operation
374 default:
375 return toBigDecimal( op1 ).multiply( toBigDecimal( op2 ));
376 }
377 }
378
379 /**
380 * Divide two numbers. The result will be returned as Integer-type if and only if
381 * both sides of the division operator are Integer-types. Otherwise a Float, Double,
382 * or BigDecimal will be returned.
383 * @param op1
384 * @param op2
385 * @return Division result.
386 */
387 public static Number divide (Number op1, Number op2) {
388
389 int calcBase = findCalculationBase( op1, op2);
390 switch (calcBase) {
391 case BASE_BIGINTEGER:
392 BigInteger b1 = toBigInteger( op1 );
393 BigInteger b2 = toBigInteger( op2 );
394 return b1.divide( b2);
395
396 case BASE_LONG:
397 long l1 = op1.longValue();
398 long l2 = op2.longValue();
399 return wrapPrimitive( l1 / l2, op1, op2);
400
401 case BASE_FLOAT:
402 return new Float (op1.floatValue()/op2.floatValue());
403 case BASE_DOUBLE:
404 return new Double (op1.doubleValue()/op2.doubleValue());
405
406 // Default is BigDecimal operation
407 default:
408 return toBigDecimal( op1 ).divide( toBigDecimal( op2 ), BigDecimal.ROUND_HALF_DOWN);
409 }
410 }
411
412 /**
413 * Modulo two numbers.
414 * @param op1
415 * @param op2
416 * @return Modulo result.
417 *
418 * @throws ArithmeticException If at least one parameter is a BigDecimal
419 */
420 public static Number modulo (Number op1, Number op2) throws ArithmeticException {
421
422 int calcBase = findCalculationBase( op1, op2);
423 switch (calcBase) {
424 case BASE_BIGINTEGER:
425 return toBigInteger( op1 ).mod( toBigInteger( op2 ));
426 case BASE_LONG:
427 return wrapPrimitive( op1.longValue() % op2.longValue(), op1, op2);
428 case BASE_FLOAT:
429 return new Float (op1.floatValue() % op2.floatValue());
430 case BASE_DOUBLE:
431 return new Double (op1.doubleValue() % op2.doubleValue());
432
433 // Default is BigDecimal operation
434 default:
435 throw new ArithmeticException( "Cannot calculate the modulo of BigDecimals.");
436 }
437 }
438
439 /**
440 * Compare two numbers.
441 * @param op1
442 * @param op2
443 * @return 1 if n1 > n2, -1 if n1 < n2 and 0 if equal.
444 */
445 public static int compare (Number op1, Number op2) {
446
447 int calcBase = findCalculationBase( op1, op2);
448 switch (calcBase) {
449 case BASE_BIGINTEGER:
450 return toBigInteger( op1 ).compareTo( toBigInteger( op2 ));
451 case BASE_LONG:
452 long l1 = op1.longValue();
453 long l2 = op2.longValue();
454 if (l1 < l2) {
455 return -1;
456 }
457 if (l1 > l2) {
458 return 1;
459 }
460 return 0;
461 case BASE_FLOAT:
462 float f1 = op1.floatValue();
463 float f2 = op2.floatValue();
464 if (f1 < f2) {
465 return -1;
466 }
467 if (f1 > f2) {
468 return 1;
469 }
470 return 0;
471 case BASE_DOUBLE:
472 double d1 = op1.doubleValue();
473 double d2 = op2.doubleValue();
474 if (d1 < d2) {
475 return -1;
476 }
477 if (d1 > d2) {
478 return 1;
479 }
480 return 0;
481
482 // Default is BigDecimal operation
483 default:
484 return toBigDecimal( op1 ).compareTo( toBigDecimal ( op2 ));
485 }
486 }
487 }