package org.bouncycastle.math.ec; import java.math.BigInteger; /** * Class representing a simple version of a big decimal. A * SimpleBigDecimal is basically a * {@link java.math.BigInteger BigInteger} with a few digits on the right of * the decimal point. The number of (binary) digits on the right of the decimal * point is called the scale of the SimpleBigDecimal. * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted * automatically, but must be set manually. All SimpleBigDecimals * taking part in the same arithmetic operation must have equal scale. The * result of a multiplication of two SimpleBigDecimals returns a * SimpleBigDecimal with double scale. */ class SimpleBigDecimal //extends Number // not in J2ME - add compatibility class? { private static final long serialVersionUID = 1L; private final BigInteger bigInt; private final int scale; /** * Returns a SimpleBigDecimal representing the same numerical * value as value. * @param value The value of the SimpleBigDecimal to be * created. * @param scale The scale of the SimpleBigDecimal to be * created. * @return The such created SimpleBigDecimal. */ public static SimpleBigDecimal getInstance(BigInteger value, int scale) { return new SimpleBigDecimal(value.shiftLeft(scale), scale); } /** * Constructor for SimpleBigDecimal. The value of the * constructed SimpleBigDecimal equals bigInt / * 2scale. * @param bigInt The bigInt value parameter. * @param scale The scale of the constructed SimpleBigDecimal. */ public SimpleBigDecimal(BigInteger bigInt, int scale) { if (scale < 0) { throw new IllegalArgumentException("scale may not be negative"); } this.bigInt = bigInt; this.scale = scale; } private SimpleBigDecimal(SimpleBigDecimal limBigDec) { bigInt = limBigDec.bigInt; scale = limBigDec.scale; } private void checkScale(SimpleBigDecimal b) { if (scale != b.scale) { throw new IllegalArgumentException("Only SimpleBigDecimal of " + "same scale allowed in arithmetic operations"); } } public SimpleBigDecimal adjustScale(int newScale) { if (newScale < 0) { throw new IllegalArgumentException("scale may not be negative"); } if (newScale == scale) { return new SimpleBigDecimal(this); } return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale), newScale); } public SimpleBigDecimal add(SimpleBigDecimal b) { checkScale(b); return new SimpleBigDecimal(bigInt.add(b.bigInt), scale); } public SimpleBigDecimal add(BigInteger b) { return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale); } public SimpleBigDecimal negate() { return new SimpleBigDecimal(bigInt.negate(), scale); } public SimpleBigDecimal subtract(SimpleBigDecimal b) { return add(b.negate()); } public SimpleBigDecimal subtract(BigInteger b) { return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)), scale); } public SimpleBigDecimal multiply(SimpleBigDecimal b) { checkScale(b); return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale); } public SimpleBigDecimal multiply(BigInteger b) { return new SimpleBigDecimal(bigInt.multiply(b), scale); } public SimpleBigDecimal divide(SimpleBigDecimal b) { checkScale(b); BigInteger dividend = bigInt.shiftLeft(scale); return new SimpleBigDecimal(dividend.divide(b.bigInt), scale); } public SimpleBigDecimal divide(BigInteger b) { return new SimpleBigDecimal(bigInt.divide(b), scale); } public SimpleBigDecimal shiftLeft(int n) { return new SimpleBigDecimal(bigInt.shiftLeft(n), scale); } public int compareTo(SimpleBigDecimal val) { checkScale(val); return bigInt.compareTo(val.bigInt); } public int compareTo(BigInteger val) { return bigInt.compareTo(val.shiftLeft(scale)); } public BigInteger floor() { return bigInt.shiftRight(scale); } public BigInteger round() { SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1); return add(oneHalf.adjustScale(scale)).floor(); } public int intValue() { return floor().intValue(); } public long longValue() { return floor().longValue(); } /* NON-J2ME compliant. public double doubleValue() { return Double.valueOf(toString()).doubleValue(); } public float floatValue() { return Float.valueOf(toString()).floatValue(); } */ public int getScale() { return scale; } public String toString() { if (scale == 0) { return bigInt.toString(); } BigInteger floorBigInt = floor(); BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale)); if (bigInt.signum() == -1) { fract = ECConstants.ONE.shiftLeft(scale).subtract(fract); } if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO)))) { floorBigInt = floorBigInt.add(ECConstants.ONE); } String leftOfPoint = floorBigInt.toString(); char[] fractCharArr = new char[scale]; String fractStr = fract.toString(2); int fractLen = fractStr.length(); int zeroes = scale - fractLen; for (int i = 0; i < zeroes; i++) { fractCharArr[i] = '0'; } for (int j = 0; j < fractLen; j++) { fractCharArr[zeroes + j] = fractStr.charAt(j); } String rightOfPoint = new String(fractCharArr); StringBuffer sb = new StringBuffer(leftOfPoint); sb.append("."); sb.append(rightOfPoint); return sb.toString(); } public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof SimpleBigDecimal)) { return false; } SimpleBigDecimal other = (SimpleBigDecimal)o; return ((bigInt.equals(other.bigInt)) && (scale == other.scale)); } public int hashCode() { return bigInt.hashCode() ^ scale; } }