~ubuntu-branches/ubuntu/lucid/groovy/lucid

1.3.2 by Torsten Werner
Import upstream version 1.6.3
1
/*
2
 * Copyright 2003-2007 the original author or authors.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.codehaus.groovy.runtime.typehandling;
18
19
import java.math.BigDecimal;
20
21
/**
22
 * BigDecimal NumberMath operations
23
 * 
24
 * @author Steve Goetze
25
 */
26
public class BigDecimalMath extends NumberMath {
27
28
	//This is an arbitrary value, picked as a reasonable choice for a rounding point
29
	//for typical user math.
30
	public static final int MAX_DIVISION_SCALE = 10;
31
	
32
	public static final BigDecimalMath INSTANCE = new BigDecimalMath();
33
	
34
	private BigDecimalMath() {}
35
36
	protected Number absImpl(Number number) {
37
		return toBigDecimal(number).abs();
38
	}
39
	
40
	public Number addImpl(Number left, Number right) {
41
		return toBigDecimal(left).add(toBigDecimal(right));
42
	}
43
44
	public Number subtractImpl(Number left, Number right) {
45
		return toBigDecimal(left).subtract(toBigDecimal(right));
46
	}
47
48
	public Number multiplyImpl(Number left, Number right) {
49
		return toBigDecimal(left).multiply(toBigDecimal(right));
50
	}
51
52
	public Number divideImpl(Number left, Number right) {
53
		//Hack until Java 1.5 BigDecimal is available.  For now, pick
54
		//a result scale which is the maximum of the scale of the
55
		//two operands and an arbitrary maximum (similar to what a
56
		//handheld calculator would do).  Then, normalize the result
57
		//by removing any trailing zeros.
58
		BigDecimal bigLeft = toBigDecimal(left);
59
		BigDecimal bigRight = toBigDecimal(right);
60
		int scale = Math.max(bigLeft.scale(), bigRight.scale());
61
		return normalize(bigLeft.divide(bigRight, Math.max(scale, MAX_DIVISION_SCALE), BigDecimal.ROUND_HALF_UP));
62
	}
63
	
64
	public int compareToImpl(Number left, Number right) {
65
		return toBigDecimal(left).compareTo(toBigDecimal(right));
66
	}
67
	
68
	private BigDecimal normalize(BigDecimal number) {
69
        // we have to take care of the case number==0, because 0 can have every
70
        // scale and the test in the while loop would never end
71
        if (number.signum()==0) {
72
            // the smallest scale for 0 is 0
73
            return number.setScale(0);
74
        }
75
        // rescale until we found the smallest possible scale
76
		try {
77
			while (true) {
78
				number = number.setScale(number.scale()-1);
79
			} 
80
		} catch (ArithmeticException e) {
81
			return number;
82
		}
83
	}
84
85
    protected Number unaryMinusImpl(Number left) {
86
        return toBigDecimal(left).negate();
87
    }
88
}