1package org.bouncycastle.math.ec; 2 3import java.math.BigInteger; 4 5/** 6 * Class representing a simple version of a big decimal. A 7 * <code>SimpleBigDecimal</code> is basically a 8 * {@link java.math.BigInteger BigInteger} with a few digits on the right of 9 * the decimal point. The number of (binary) digits on the right of the decimal 10 * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>. 11 * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted 12 * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s 13 * taking part in the same arithmetic operation must have equal scale. The 14 * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a 15 * <code>SimpleBigDecimal</code> with double scale. 16 */ 17class SimpleBigDecimal 18 //extends Number // not in J2ME - add compatibility class? 19{ 20 private static final long serialVersionUID = 1L; 21 22 private final BigInteger bigInt; 23 private final int scale; 24 25 /** 26 * Returns a <code>SimpleBigDecimal</code> representing the same numerical 27 * value as <code>value</code>. 28 * @param value The value of the <code>SimpleBigDecimal</code> to be 29 * created. 30 * @param scale The scale of the <code>SimpleBigDecimal</code> to be 31 * created. 32 * @return The such created <code>SimpleBigDecimal</code>. 33 */ 34 public static SimpleBigDecimal getInstance(BigInteger value, int scale) 35 { 36 return new SimpleBigDecimal(value.shiftLeft(scale), scale); 37 } 38 39 /** 40 * Constructor for <code>SimpleBigDecimal</code>. The value of the 41 * constructed <code>SimpleBigDecimal</code> equals <code>bigInt / 42 * 2<sup>scale</sup></code>. 43 * @param bigInt The <code>bigInt</code> value parameter. 44 * @param scale The scale of the constructed <code>SimpleBigDecimal</code>. 45 */ 46 public SimpleBigDecimal(BigInteger bigInt, int scale) 47 { 48 if (scale < 0) 49 { 50 throw new IllegalArgumentException("scale may not be negative"); 51 } 52 53 this.bigInt = bigInt; 54 this.scale = scale; 55 } 56 57 private SimpleBigDecimal(SimpleBigDecimal limBigDec) 58 { 59 bigInt = limBigDec.bigInt; 60 scale = limBigDec.scale; 61 } 62 63 private void checkScale(SimpleBigDecimal b) 64 { 65 if (scale != b.scale) 66 { 67 throw new IllegalArgumentException("Only SimpleBigDecimal of " + 68 "same scale allowed in arithmetic operations"); 69 } 70 } 71 72 public SimpleBigDecimal adjustScale(int newScale) 73 { 74 if (newScale < 0) 75 { 76 throw new IllegalArgumentException("scale may not be negative"); 77 } 78 79 if (newScale == scale) 80 { 81 return new SimpleBigDecimal(this); 82 } 83 84 return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale), 85 newScale); 86 } 87 88 public SimpleBigDecimal add(SimpleBigDecimal b) 89 { 90 checkScale(b); 91 return new SimpleBigDecimal(bigInt.add(b.bigInt), scale); 92 } 93 94 public SimpleBigDecimal add(BigInteger b) 95 { 96 return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale); 97 } 98 99 public SimpleBigDecimal negate() 100 { 101 return new SimpleBigDecimal(bigInt.negate(), scale); 102 } 103 104 public SimpleBigDecimal subtract(SimpleBigDecimal b) 105 { 106 return add(b.negate()); 107 } 108 109 public SimpleBigDecimal subtract(BigInteger b) 110 { 111 return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)), 112 scale); 113 } 114 115 public SimpleBigDecimal multiply(SimpleBigDecimal b) 116 { 117 checkScale(b); 118 return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale); 119 } 120 121 public SimpleBigDecimal multiply(BigInteger b) 122 { 123 return new SimpleBigDecimal(bigInt.multiply(b), scale); 124 } 125 126 public SimpleBigDecimal divide(SimpleBigDecimal b) 127 { 128 checkScale(b); 129 BigInteger dividend = bigInt.shiftLeft(scale); 130 return new SimpleBigDecimal(dividend.divide(b.bigInt), scale); 131 } 132 133 public SimpleBigDecimal divide(BigInteger b) 134 { 135 return new SimpleBigDecimal(bigInt.divide(b), scale); 136 } 137 138 public SimpleBigDecimal shiftLeft(int n) 139 { 140 return new SimpleBigDecimal(bigInt.shiftLeft(n), scale); 141 } 142 143 public int compareTo(SimpleBigDecimal val) 144 { 145 checkScale(val); 146 return bigInt.compareTo(val.bigInt); 147 } 148 149 public int compareTo(BigInteger val) 150 { 151 return bigInt.compareTo(val.shiftLeft(scale)); 152 } 153 154 public BigInteger floor() 155 { 156 return bigInt.shiftRight(scale); 157 } 158 159 public BigInteger round() 160 { 161 SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1); 162 return add(oneHalf.adjustScale(scale)).floor(); 163 } 164 165 public int intValue() 166 { 167 return floor().intValue(); 168 } 169 170 public long longValue() 171 { 172 return floor().longValue(); 173 } 174 /* NON-J2ME compliant. 175 public double doubleValue() 176 { 177 return Double.valueOf(toString()).doubleValue(); 178 } 179 180 public float floatValue() 181 { 182 return Float.valueOf(toString()).floatValue(); 183 } 184 */ 185 public int getScale() 186 { 187 return scale; 188 } 189 190 public String toString() 191 { 192 if (scale == 0) 193 { 194 return bigInt.toString(); 195 } 196 197 BigInteger floorBigInt = floor(); 198 199 BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale)); 200 if (bigInt.signum() == -1) 201 { 202 fract = ECConstants.ONE.shiftLeft(scale).subtract(fract); 203 } 204 205 if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO)))) 206 { 207 floorBigInt = floorBigInt.add(ECConstants.ONE); 208 } 209 String leftOfPoint = floorBigInt.toString(); 210 211 char[] fractCharArr = new char[scale]; 212 String fractStr = fract.toString(2); 213 int fractLen = fractStr.length(); 214 int zeroes = scale - fractLen; 215 for (int i = 0; i < zeroes; i++) 216 { 217 fractCharArr[i] = '0'; 218 } 219 for (int j = 0; j < fractLen; j++) 220 { 221 fractCharArr[zeroes + j] = fractStr.charAt(j); 222 } 223 String rightOfPoint = new String(fractCharArr); 224 225 StringBuffer sb = new StringBuffer(leftOfPoint); 226 sb.append("."); 227 sb.append(rightOfPoint); 228 229 return sb.toString(); 230 } 231 232 public boolean equals(Object o) 233 { 234 if (this == o) 235 { 236 return true; 237 } 238 239 if (!(o instanceof SimpleBigDecimal)) 240 { 241 return false; 242 } 243 244 SimpleBigDecimal other = (SimpleBigDecimal)o; 245 return ((bigInt.equals(other.bigInt)) && (scale == other.scale)); 246 } 247 248 public int hashCode() 249 { 250 return bigInt.hashCode() ^ scale; 251 } 252 253} 254