| package org.bouncycastle.math.ec; |
| |
| import java.math.BigInteger; |
| |
| /** |
| * Class representing a simple version of a big decimal. A |
| * <code>SimpleBigDecimal</code> 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 <code>scale</code> of the <code>SimpleBigDecimal</code>. |
| * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted |
| * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s |
| * taking part in the same arithmetic operation must have equal scale. The |
| * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a |
| * <code>SimpleBigDecimal</code> 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 <code>SimpleBigDecimal</code> representing the same numerical |
| * value as <code>value</code>. |
| * @param value The value of the <code>SimpleBigDecimal</code> to be |
| * created. |
| * @param scale The scale of the <code>SimpleBigDecimal</code> to be |
| * created. |
| * @return The such created <code>SimpleBigDecimal</code>. |
| */ |
| public static SimpleBigDecimal getInstance(BigInteger value, int scale) |
| { |
| return new SimpleBigDecimal(value.shiftLeft(scale), scale); |
| } |
| |
| /** |
| * Constructor for <code>SimpleBigDecimal</code>. The value of the |
| * constructed <code>SimpleBigDecimal</code> equals <code>bigInt / |
| * 2<sup>scale</sup></code>. |
| * @param bigInt The <code>bigInt</code> value parameter. |
| * @param scale The scale of the constructed <code>SimpleBigDecimal</code>. |
| */ |
| 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; |
| } |
| |
| } |