001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.runtime.java.math;
032:
033: import java.math.*;
034: import net.sf.retrotranslator.registry.Advanced;
035:
036: /**
037: * @author Taras Puchko
038: */
039: public class _BigDecimal {
040:
041: public static final BigDecimal ZERO = BigDecimal.valueOf(0);
042: public static final BigDecimal ONE = BigDecimal.valueOf(1);
043: public static final BigDecimal TEN = BigDecimal.valueOf(10);
044:
045: private static final BigInteger[] FIVE_POWERS = new BigInteger[32];
046:
047: static {
048: FIVE_POWERS[0] = BigInteger.valueOf(5);
049: for (int i = 1; i < FIVE_POWERS.length; i++) {
050: FIVE_POWERS[i] = FIVE_POWERS[i - 1]
051: .multiply(FIVE_POWERS[0]);
052: }
053: }
054:
055: public static BigInteger convertConstructorArguments(int value) {
056: return BigInteger.valueOf(value);
057: }
058:
059: public static BigInteger convertConstructorArguments(long value) {
060: return BigInteger.valueOf(value);
061: }
062:
063: public static String convertConstructorArguments(char[] in,
064: int offset, int len) {
065: return new String(in, offset, len);
066: }
067:
068: public static String convertConstructorArguments(char[] in) {
069: return new String(in);
070: }
071:
072: public static BigDecimal divide(BigDecimal dividend,
073: BigDecimal divisor) {
074: BigInteger p = dividend.unscaledValue();
075: BigInteger q = divisor.unscaledValue();
076: if (q.signum() == 0) {
077: throw new ArithmeticException("Division by zero");
078: }
079: long preferredScale = (long) dividend.scale() - divisor.scale();
080: if (p.signum() == 0) {
081: return getZero(preferredScale);
082: }
083: BigInteger gcd = p.gcd(q);
084: p = p.divide(gcd);
085: q = q.divide(gcd);
086: if (q.signum() < 0) {
087: p = p.negate();
088: q = q.negate();
089: }
090: int x = q.getLowestSetBit();
091: int y = log5(q.shiftRight(x));
092: BigInteger value = x > y ? multiplyBy5Power(p, x - y) : p
093: .shiftLeft(y - x);
094: int scale = castScaleToInt(preferredScale + Math.max(x, y));
095: return scale >= 0 ? new BigDecimal(value, scale)
096: : new BigDecimal(value, 0).movePointLeft(scale);
097: }
098:
099: public static BigDecimal[] divideAndRemainder(BigDecimal dividend,
100: BigDecimal divisor) {
101: BigDecimal[] result = new BigDecimal[2];
102: BigDecimal quotient = divideToIntegralValue(dividend, divisor);
103: result[0] = quotient;
104: result[1] = dividend.subtract(quotient.multiply(divisor));
105: return result;
106: }
107:
108: public static BigDecimal divideToIntegralValue(BigDecimal dividend,
109: BigDecimal divisor) {
110: BigDecimal quotient = dividend.divide(divisor, 0,
111: BigDecimal.ROUND_DOWN);
112: if (dividend.scale() > divisor.scale()) {
113: quotient = quotient.setScale(dividend.scale()
114: - divisor.scale());
115: }
116: return quotient;
117: }
118:
119: public static BigDecimal pow(BigDecimal bigDecimal, int n) {
120: if (n == 0) {
121: return ONE;
122: }
123: if (n < 0 || n > 999999999) {
124: throw new ArithmeticException("Invalid operation");
125: }
126: long scale = bigDecimal.scale() * (long) n;
127: return bigDecimal.signum() == 0 ? getZero(scale)
128: : new BigDecimal(bigDecimal.unscaledValue().pow(n),
129: castScaleToInt(scale));
130: }
131:
132: public static BigDecimal remainder(BigDecimal dividend,
133: BigDecimal divisor) {
134: return dividend.subtract(divideToIntegralValue(dividend,
135: divisor).multiply(divisor));
136: }
137:
138: @Advanced("BigDecimal.setScale")
139: public static BigDecimal setScale(BigDecimal bigDecimal,
140: int newScale, int roundingMode) {
141: if (newScale >= 0) {
142: return bigDecimal.setScale(newScale, roundingMode);
143: }
144: return bigDecimal.movePointRight(newScale).setScale(0,
145: roundingMode).movePointLeft(newScale);
146: }
147:
148: public static String toPlainString(BigDecimal bigDecimal) {
149: return bigDecimal.toString();
150: }
151:
152: public static BigDecimal valueOf(double val) {
153: return new BigDecimal(Double.toString(val));
154: }
155:
156: public static BigDecimal valueOf(long val) {
157: return BigDecimal.valueOf(val, 0);
158: }
159:
160: private static int castScaleToInt(long scale) {
161: if (scale > Integer.MAX_VALUE) {
162: throw new ArithmeticException("Underflow");
163: }
164: if (scale < Integer.MIN_VALUE) {
165: throw new ArithmeticException("Overflow");
166: }
167: return (int) scale;
168: }
169:
170: private static BigDecimal getZero(long scale) {
171: return BigDecimal.valueOf(0, (int) Math.max(Integer.MIN_VALUE,
172: Math.min(Integer.MAX_VALUE, scale)));
173: }
174:
175: private static int log5(BigInteger x) {
176: int result = 0;
177: int power = 1;
178: while (true) {
179: BigInteger[] quotientAndReminder = x
180: .divideAndRemainder(FIVE_POWERS[power - 1]);
181: if (quotientAndReminder[1].signum() == 0) {
182: x = quotientAndReminder[0];
183: result += power;
184: power = Math.min(power + 1, FIVE_POWERS.length);
185: } else if (power > 1) {
186: power /= 2;
187: } else if (x.bitLength() == 1) {
188: return result;
189: } else {
190: throw new ArithmeticException(
191: "Non-terminating decimal expansion");
192: }
193: }
194: }
195:
196: private static BigInteger multiplyBy5Power(BigInteger x, int power) {
197: return power <= FIVE_POWERS.length ? x
198: .multiply(FIVE_POWERS[power - 1]) : x
199: .multiply(FIVE_POWERS[0].pow(power));
200: }
201:
202: }
|