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 void checkScale(SimpleBigDecimal b) 58 { 59 if (scale != b.scale) 60 { 61 throw new IllegalArgumentException("Only SimpleBigDecimal of " + 62 "same scale allowed in arithmetic operations"); 63 } 64 } 65 66 public SimpleBigDecimal adjustScale(int newScale) 67 { 68 if (newScale < 0) 69 { 70 throw new IllegalArgumentException("scale may not be negative"); 71 } 72 73 if (newScale == scale) 74 { 75 return this; 76 } 77 78 return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale), 79 newScale); 80 } 81 82 public SimpleBigDecimal add(SimpleBigDecimal b) 83 { 84 checkScale(b); 85 return new SimpleBigDecimal(bigInt.add(b.bigInt), scale); 86 } 87 88 public SimpleBigDecimal add(BigInteger b) 89 { 90 return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale); 91 } 92 93 public SimpleBigDecimal negate() 94 { 95 return new SimpleBigDecimal(bigInt.negate(), scale); 96 } 97 98 public SimpleBigDecimal subtract(SimpleBigDecimal b) 99 { 100 return add(b.negate()); 101 } 102 103 public SimpleBigDecimal subtract(BigInteger b) 104 { 105 return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)), 106 scale); 107 } 108 109 public SimpleBigDecimal multiply(SimpleBigDecimal b) 110 { 111 checkScale(b); 112 return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale); 113 } 114 115 public SimpleBigDecimal multiply(BigInteger b) 116 { 117 return new SimpleBigDecimal(bigInt.multiply(b), scale); 118 } 119 120 public SimpleBigDecimal divide(SimpleBigDecimal b) 121 { 122 checkScale(b); 123 BigInteger dividend = bigInt.shiftLeft(scale); 124 return new SimpleBigDecimal(dividend.divide(b.bigInt), scale); 125 } 126 127 public SimpleBigDecimal divide(BigInteger b) 128 { 129 return new SimpleBigDecimal(bigInt.divide(b), scale); 130 } 131 132 public SimpleBigDecimal shiftLeft(int n) 133 { 134 return new SimpleBigDecimal(bigInt.shiftLeft(n), scale); 135 } 136 137 public int compareTo(SimpleBigDecimal val) 138 { 139 checkScale(val); 140 return bigInt.compareTo(val.bigInt); 141 } 142 143 public int compareTo(BigInteger val) 144 { 145 return bigInt.compareTo(val.shiftLeft(scale)); 146 } 147 148 public BigInteger floor() 149 { 150 return bigInt.shiftRight(scale); 151 } 152 153 public BigInteger round() 154 { 155 SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1); 156 return add(oneHalf.adjustScale(scale)).floor(); 157 } 158 159 public int intValue() 160 { 161 return floor().intValue(); 162 } 163 164 public long longValue() 165 { 166 return floor().longValue(); 167 } 168 /* NON-J2ME compliant. 169 public double doubleValue() 170 { 171 return Double.valueOf(toString()).doubleValue(); 172 } 173 174 public float floatValue() 175 { 176 return Float.valueOf(toString()).floatValue(); 177 } 178 */ 179 public int getScale() 180 { 181 return scale; 182 } 183 184 public String toString() 185 { 186 if (scale == 0) 187 { 188 return bigInt.toString(); 189 } 190 191 BigInteger floorBigInt = floor(); 192 193 BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale)); 194 if (bigInt.signum() == -1) 195 { 196 fract = ECConstants.ONE.shiftLeft(scale).subtract(fract); 197 } 198 199 if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO)))) 200 { 201 floorBigInt = floorBigInt.add(ECConstants.ONE); 202 } 203 String leftOfPoint = floorBigInt.toString(); 204 205 char[] fractCharArr = new char[scale]; 206 String fractStr = fract.toString(2); 207 int fractLen = fractStr.length(); 208 int zeroes = scale - fractLen; 209 for (int i = 0; i < zeroes; i++) 210 { 211 fractCharArr[i] = '0'; 212 } 213 for (int j = 0; j < fractLen; j++) 214 { 215 fractCharArr[zeroes + j] = fractStr.charAt(j); 216 } 217 String rightOfPoint = new String(fractCharArr); 218 219 StringBuffer sb = new StringBuffer(leftOfPoint); 220 sb.append("."); 221 sb.append(rightOfPoint); 222 223 return sb.toString(); 224 } 225 226 public boolean equals(Object o) 227 { 228 if (this == o) 229 { 230 return true; 231 } 232 233 if (!(o instanceof SimpleBigDecimal)) 234 { 235 return false; 236 } 237 238 SimpleBigDecimal other = (SimpleBigDecimal)o; 239 return ((bigInt.equals(other.bigInt)) && (scale == other.scale)); 240 } 241 242 public int hashCode() 243 { 244 return bigInt.hashCode() ^ scale; 245 } 246 247} 248