001: package org.bouncycastle.math.ec;
002:
003: import java.math.BigInteger;
004:
005: /**
006: * Class representing a simple version of a big decimal. A
007: * <code>SimpleBigDecimal</code> is basically a
008: * {@link java.math.BigInteger BigInteger} with a few digits on the right of
009: * the decimal point. The number of (binary) digits on the right of the decimal
010: * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
011: * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
012: * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
013: * taking part in the same arithmetic operation must have equal scale. The
014: * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
015: * <code>SimpleBigDecimal</code> with double scale.
016: */
017: class SimpleBigDecimal
018: //extends Number // not in J2ME - add compatibility class?
019: {
020: private static final long serialVersionUID = 1L;
021:
022: private final BigInteger bigInt;
023: private final int scale;
024:
025: /**
026: * Returns a <code>SimpleBigDecimal</code> representing the same numerical
027: * value as <code>value</code>.
028: * @param value The value of the <code>SimpleBigDecimal</code> to be
029: * created.
030: * @param scale The scale of the <code>SimpleBigDecimal</code> to be
031: * created.
032: * @return The such created <code>SimpleBigDecimal</code>.
033: */
034: public static SimpleBigDecimal getInstance(BigInteger value,
035: int scale) {
036: return new SimpleBigDecimal(value.shiftLeft(scale), scale);
037: }
038:
039: /**
040: * Constructor for <code>SimpleBigDecimal</code>. The value of the
041: * constructed <code>SimpleBigDecimal</code> equals <code>bigInt /
042: * 2<sup>scale</sup></code>.
043: * @param bigInt The <code>bigInt</code> value parameter.
044: * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
045: */
046: public SimpleBigDecimal(BigInteger bigInt, int scale) {
047: if (scale < 0) {
048: throw new IllegalArgumentException(
049: "scale may not be negative");
050: }
051:
052: this .bigInt = bigInt;
053: this .scale = scale;
054: }
055:
056: private SimpleBigDecimal(SimpleBigDecimal limBigDec) {
057: bigInt = limBigDec.bigInt;
058: scale = limBigDec.scale;
059: }
060:
061: private void checkScale(SimpleBigDecimal b) {
062: if (scale != b.scale) {
063: throw new IllegalArgumentException(
064: "Only SimpleBigDecimal of "
065: + "same scale allowed in arithmetic operations");
066: }
067: }
068:
069: public SimpleBigDecimal adjustScale(int newScale) {
070: if (newScale < 0) {
071: throw new IllegalArgumentException(
072: "scale may not be negative");
073: }
074:
075: if (newScale == scale) {
076: return new SimpleBigDecimal(this );
077: }
078:
079: return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
080: newScale);
081: }
082:
083: public SimpleBigDecimal add(SimpleBigDecimal b) {
084: checkScale(b);
085: return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
086: }
087:
088: public SimpleBigDecimal add(BigInteger b) {
089: return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)),
090: scale);
091: }
092:
093: public SimpleBigDecimal negate() {
094: return new SimpleBigDecimal(bigInt.negate(), scale);
095: }
096:
097: public SimpleBigDecimal subtract(SimpleBigDecimal b) {
098: return add(b.negate());
099: }
100:
101: public SimpleBigDecimal subtract(BigInteger b) {
102: return new SimpleBigDecimal(
103: bigInt.subtract(b.shiftLeft(scale)), scale);
104: }
105:
106: public SimpleBigDecimal multiply(SimpleBigDecimal b) {
107: checkScale(b);
108: return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale
109: + scale);
110: }
111:
112: public SimpleBigDecimal multiply(BigInteger b) {
113: return new SimpleBigDecimal(bigInt.multiply(b), scale);
114: }
115:
116: public SimpleBigDecimal divide(SimpleBigDecimal b) {
117: checkScale(b);
118: BigInteger dividend = bigInt.shiftLeft(scale);
119: return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
120: }
121:
122: public SimpleBigDecimal divide(BigInteger b) {
123: return new SimpleBigDecimal(bigInt.divide(b), scale);
124: }
125:
126: public SimpleBigDecimal shiftLeft(int n) {
127: return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
128: }
129:
130: public int compareTo(SimpleBigDecimal val) {
131: checkScale(val);
132: return bigInt.compareTo(val.bigInt);
133: }
134:
135: public int compareTo(BigInteger val) {
136: return bigInt.compareTo(val.shiftLeft(scale));
137: }
138:
139: public BigInteger floor() {
140: return bigInt.shiftRight(scale);
141: }
142:
143: public BigInteger round() {
144: SimpleBigDecimal oneHalf = new SimpleBigDecimal(
145: ECConstants.ONE, 1);
146: return add(oneHalf.adjustScale(scale)).floor();
147: }
148:
149: public int intValue() {
150: return floor().intValue();
151: }
152:
153: public long longValue() {
154: return floor().longValue();
155: }
156:
157: public double doubleValue() {
158: return Double.valueOf(toString()).doubleValue();
159: }
160:
161: public float floatValue() {
162: return Float.valueOf(toString()).floatValue();
163: }
164:
165: public int getScale() {
166: return scale;
167: }
168:
169: public String toString() {
170: if (scale == 0) {
171: return bigInt.toString();
172: }
173:
174: BigInteger floorBigInt = floor();
175:
176: BigInteger fract = bigInt
177: .subtract(floorBigInt.shiftLeft(scale));
178: if (bigInt.signum() == -1) {
179: fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
180: }
181:
182: if ((floorBigInt.signum() == -1)
183: && (!(fract.equals(ECConstants.ZERO)))) {
184: floorBigInt = floorBigInt.add(ECConstants.ONE);
185: }
186: String leftOfPoint = floorBigInt.toString();
187:
188: char[] fractCharArr = new char[scale];
189: String fractStr = fract.toString(2);
190: int fractLen = fractStr.length();
191: int zeroes = scale - fractLen;
192: for (int i = 0; i < zeroes; i++) {
193: fractCharArr[i] = '0';
194: }
195: for (int j = 0; j < fractLen; j++) {
196: fractCharArr[zeroes + j] = fractStr.charAt(j);
197: }
198: String rightOfPoint = new String(fractCharArr);
199:
200: StringBuffer sb = new StringBuffer(leftOfPoint);
201: sb.append(".");
202: sb.append(rightOfPoint);
203:
204: return sb.toString();
205: }
206:
207: public boolean equals(Object o) {
208: if (this == o) {
209: return true;
210: }
211:
212: if (!(o instanceof SimpleBigDecimal)) {
213: return false;
214: }
215:
216: SimpleBigDecimal other = (SimpleBigDecimal) o;
217: return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
218: }
219:
220: public int hashCode() {
221: return bigInt.hashCode() ^ scale;
222: }
223:
224: }
|