1 21 22 package org.armedbear.lisp; 23 24 import java.math.BigInteger ; 25 26 public final class Ratio extends LispObject 27 { 28 private BigInteger numerator; 29 private BigInteger denominator; 30 31 public Ratio(BigInteger numerator, BigInteger denominator) 32 { 33 this.numerator = numerator; 34 this.denominator = denominator; 35 } 36 37 public BigInteger numerator() 38 { 39 return numerator; 40 } 41 42 public LispObject NUMERATOR() 43 { 44 return number(numerator); 45 } 46 47 public BigInteger denominator() 48 { 49 return denominator; 50 } 51 52 public LispObject DENOMINATOR() 53 { 54 return number(denominator); 55 } 56 57 public LispObject typeOf() 58 { 59 return Symbol.RATIO; 60 } 61 62 public LispClass classOf() 63 { 64 return BuiltInClass.RATIO; 65 } 66 67 public LispObject typep(LispObject type) throws ConditionThrowable 68 { 69 if (type == Symbol.RATIO) 70 return T; 71 if (type == Symbol.RATIONAL) 72 return T; 73 if (type == Symbol.REAL) 74 return T; 75 if (type == Symbol.NUMBER) 76 return T; 77 if (type == BuiltInClass.RATIO) 78 return T; 79 return super.typep(type); 80 } 81 82 public LispObject NUMBERP() 83 { 84 return T; 85 } 86 87 public boolean numberp() 88 { 89 return true; 90 } 91 92 public boolean rationalp() 93 { 94 return true; 95 } 96 97 public boolean realp() 98 { 99 return true; 100 } 101 102 public boolean eql(LispObject obj) 103 { 104 if (this == obj) 105 return true; 106 if (obj instanceof Ratio) { 107 return numerator.equals(((Ratio)obj).numerator) && 108 denominator.equals(((Ratio)obj).denominator); 109 } 110 return false; 111 } 112 113 public boolean equal(LispObject obj) 114 { 115 return eql(obj); 116 } 117 118 public boolean equalp(LispObject obj) 119 { 120 if (obj instanceof Ratio) { 121 return numerator.equals(((Ratio)obj).numerator) && 122 denominator.equals(((Ratio)obj).denominator); 123 } 124 if (obj instanceof LispFloat) { 125 return floatValue() == ((LispFloat)obj).getValue(); 126 } 127 return false; 128 } 129 130 public LispObject ABS() 131 { 132 if (numerator.signum() > 0 && denominator.signum() > 0) 133 return this; 134 if (numerator.signum() < 0 && denominator.signum() < 0) 135 return this; 136 return new Ratio(numerator.negate(), denominator); 137 } 138 139 public boolean plusp() 140 { 141 return numerator.signum() == denominator.signum(); 142 } 143 144 public boolean minusp() 145 { 146 return numerator.signum() != denominator.signum(); 147 } 148 149 public boolean zerop() 150 { 151 return false; 152 } 153 154 public double floatValue() 155 { 156 double result = numerator.doubleValue() / denominator.doubleValue(); 157 if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result)) 158 return result; 159 final boolean negative = numerator.signum() < 0; 160 final BigInteger num = negative ? numerator.negate() : numerator; 161 final BigInteger den = denominator; 162 final int numLen = num.bitLength(); 163 final int denLen = den.bitLength(); 164 int length = Math.min(numLen, denLen); 165 if (length <= 1) 166 return result; 167 BigInteger n = num; 168 BigInteger d = den; 169 final int digits = 54; 170 if (length > digits) { 171 n = n.shiftRight(length - digits); 172 d = d.shiftRight(length - digits); 173 length -= digits; 174 } else { 175 n = n.shiftRight(1); 176 d = d.shiftRight(1); 177 --length; 178 } 179 for (int i = 0; i < length; i++) { 180 result = n.doubleValue() / d.doubleValue(); 181 if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result)) 182 break; 183 n = n.shiftRight(1); 184 d = d.shiftRight(1); 185 } 186 return negative ? -result : result; 187 } 188 189 public final LispObject incr() throws ConditionThrowable 190 { 191 return new Ratio(numerator.add(denominator), denominator); 192 } 193 194 public final LispObject decr() throws ConditionThrowable 195 { 196 return new Ratio(numerator.subtract(denominator), denominator); 197 } 198 199 public LispObject add(LispObject obj) throws ConditionThrowable 200 { 201 if (obj instanceof Fixnum) { 202 BigInteger n = 203 numerator.add(BigInteger.valueOf(((Fixnum)obj).getValue()).multiply(denominator)); 204 return number(n, denominator); 205 } 206 if (obj instanceof Bignum) { 207 BigInteger n = ((Bignum)obj).getValue(); 208 return number(numerator.add(n.multiply(denominator)), 209 denominator); 210 } 211 if (obj instanceof Ratio) { 212 BigInteger n = ((Ratio)obj).numerator; 213 BigInteger d = ((Ratio)obj).denominator; 214 if (denominator.equals(d)) 215 return number(numerator.add(n), denominator); 216 BigInteger common = denominator.multiply(d); 217 return number(numerator.multiply(d).add(n.multiply(denominator)), 218 common); 219 } 220 if (obj instanceof LispFloat) { 221 return new LispFloat(floatValue() + ((LispFloat)obj).getValue()); 222 } 223 if (obj instanceof Complex) { 224 Complex c = (Complex) obj; 225 return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart()); 226 } 227 return signal(new TypeError(obj, "number")); 228 } 229 230 public LispObject subtract(LispObject obj) throws ConditionThrowable 231 { 232 if (obj instanceof Fixnum) { 233 BigInteger n = 234 numerator.subtract(BigInteger.valueOf(((Fixnum)obj).getValue()).multiply(denominator)); 235 return number(n, denominator); 236 } 237 if (obj instanceof Bignum) { 238 BigInteger n = ((Bignum)obj).getValue(); 239 return number(numerator.subtract(n.multiply(denominator)), 240 denominator); 241 } 242 if (obj instanceof Ratio) { 243 BigInteger n = ((Ratio)obj).numerator; 244 BigInteger d = ((Ratio)obj).denominator; 245 if (denominator.equals(d)) 246 return number(numerator.subtract(n), denominator); 247 BigInteger common = denominator.multiply(d); 248 return number(numerator.multiply(d).subtract(n.multiply(denominator)), 249 common); 250 } 251 if (obj instanceof LispFloat) { 252 return new LispFloat(floatValue() - ((LispFloat)obj).getValue()); 253 } 254 if (obj instanceof Complex) { 255 Complex c = (Complex) obj; 256 return Complex.getInstance(subtract(c.getRealPart()), 257 Fixnum.ZERO.subtract(c.getImaginaryPart())); 258 } 259 return signal(new TypeError(obj, "number")); 260 } 261 262 public LispObject multiplyBy(LispObject obj) throws ConditionThrowable 263 { 264 if (obj instanceof Fixnum) { 265 BigInteger n = ((Fixnum)obj).getBigInteger(); 266 return number(numerator.multiply(n), denominator); 267 } 268 if (obj instanceof Bignum) { 269 BigInteger n = ((Bignum)obj).getValue(); 270 return number(numerator.multiply(n), denominator); 271 } 272 if (obj instanceof Ratio) { 273 BigInteger n = ((Ratio)obj).numerator; 274 BigInteger d = ((Ratio)obj).denominator; 275 return number(numerator.multiply(n), denominator.multiply(d)); 276 } 277 if (obj instanceof LispFloat) { 278 return new LispFloat(floatValue() * ((LispFloat)obj).getValue()); 279 } 280 return signal(new TypeError(obj, "number")); 281 } 282 283 public LispObject divideBy(LispObject obj) throws ConditionThrowable 284 { 285 if (obj instanceof Fixnum) { 286 BigInteger n = ((Fixnum)obj).getBigInteger(); 287 return number(numerator, denominator.multiply(n)); 288 } 289 if (obj instanceof Bignum) { 290 BigInteger n = ((Bignum)obj).getValue(); 291 return number(numerator, denominator.multiply(n)); 292 } 293 if (obj instanceof Ratio) { 294 BigInteger n = ((Ratio)obj).numerator; 295 BigInteger d = ((Ratio)obj).denominator; 296 return number(numerator.multiply(d), denominator.multiply(n)); 297 } 298 if (obj instanceof LispFloat) { 299 if (obj.zerop()) 300 return signal(new DivisionByZero()); 301 return new LispFloat(floatValue() / ((LispFloat)obj).getValue()); 302 } 303 return signal(new TypeError(obj, "number")); 304 } 305 306 public boolean isEqualTo(LispObject obj) throws ConditionThrowable 307 { 308 if (obj instanceof Ratio) 309 return (numerator.equals(((Ratio)obj).numerator) && 310 denominator.equals(((Ratio)obj).denominator)); 311 if (obj instanceof LispFloat) 312 return isEqualTo(((LispFloat)obj).rational()); 313 if (obj.numberp()) 314 return false; 315 signal(new TypeError(obj, "number")); 316 return false; 318 } 319 320 public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable 321 { 322 return !isEqualTo(obj); 323 } 324 325 public boolean isLessThan(LispObject obj) throws ConditionThrowable 326 { 327 if (obj instanceof Fixnum) { 328 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 329 return numerator.compareTo(n2) < 0; 330 } 331 if (obj instanceof Bignum) { 332 BigInteger n = ((Bignum)obj).getValue().multiply(denominator); 333 return numerator.compareTo(n) < 0; 334 } 335 if (obj instanceof Ratio) { 336 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 337 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 338 return n1.compareTo(n2) < 0; 339 } 340 if (obj instanceof LispFloat) 341 return isLessThan(((LispFloat)obj).rational()); 342 signal(new TypeError(obj, Symbol.REAL)); 343 return false; 345 } 346 347 public boolean isGreaterThan(LispObject obj) throws ConditionThrowable 348 { 349 if (obj instanceof Fixnum) { 350 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 351 return numerator.compareTo(n2) > 0; 352 } 353 if (obj instanceof Bignum) { 354 BigInteger n = ((Bignum)obj).getValue().multiply(denominator); 355 return numerator.compareTo(n) > 0; 356 } 357 if (obj instanceof Ratio) { 358 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 359 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 360 return n1.compareTo(n2) > 0; 361 } 362 if (obj instanceof LispFloat) 363 return isGreaterThan(((LispFloat)obj).rational()); 364 signal(new TypeError(obj, Symbol.REAL)); 365 return false; 367 } 368 369 public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable 370 { 371 if (obj instanceof Fixnum) { 372 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 373 return numerator.compareTo(n2) <= 0; 374 } 375 if (obj instanceof Bignum) { 376 BigInteger n = ((Bignum)obj).getValue().multiply(denominator); 377 return numerator.compareTo(n) <= 0; 378 } 379 if (obj instanceof Ratio) { 380 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 381 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 382 return n1.compareTo(n2) <= 0; 383 } 384 if (obj instanceof LispFloat) 385 return isLessThanOrEqualTo(((LispFloat)obj).rational()); 386 signal(new TypeError(obj, Symbol.REAL)); 387 return false; 389 } 390 391 public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable 392 { 393 if (obj instanceof Fixnum) { 394 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 395 return numerator.compareTo(n2) >= 0; 396 } 397 if (obj instanceof Bignum) { 398 BigInteger n = ((Bignum)obj).getValue().multiply(denominator); 399 return numerator.compareTo(n) >= 0; 400 } 401 if (obj instanceof Ratio) { 402 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 403 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 404 return n1.compareTo(n2) >= 0; 405 } 406 if (obj instanceof LispFloat) 407 return isGreaterThanOrEqualTo(((LispFloat)obj).rational()); 408 signal(new TypeError(obj, Symbol.REAL)); 409 return false; 411 } 412 413 public LispObject truncate(LispObject obj) throws ConditionThrowable 414 { 415 if (obj instanceof LispFloat) 416 return new LispFloat(floatValue()).truncate(obj); 417 BigInteger n, d; 418 try { 419 if (obj instanceof Fixnum) { 420 n = ((Fixnum)obj).getBigInteger(); 421 d = BigInteger.ONE; 422 } else if (obj instanceof Bignum) { 423 n = ((Bignum)obj).getValue(); 424 d = BigInteger.ONE; 425 } else if (obj instanceof Ratio) { 426 n = ((Ratio)obj).numerator(); 427 d = ((Ratio)obj).denominator(); 428 } else { 429 return signal(new TypeError(obj, "number")); 430 } 431 BigInteger num = numerator.multiply(d); 433 BigInteger den = denominator.multiply(n); 434 BigInteger quotient = num.divide(den); 435 LispObject product = number(quotient.multiply(n), d); 437 LispObject remainder = subtract(product); 439 return LispThread.currentThread().setValues(number(quotient), remainder); 440 } 441 catch (ArithmeticException e) { 442 if (obj.zerop()) 443 return signal(new DivisionByZero()); 444 return signal(new ArithmeticError(e.getMessage())); 445 } 446 } 447 448 public int hashCode() 449 { 450 return numerator.hashCode() ^ denominator.hashCode(); 451 } 452 453 public String writeToString() throws ConditionThrowable 454 { 455 final LispThread thread = LispThread.currentThread(); 456 int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread)); 457 StringBuffer sb = new StringBuffer (numerator.toString(base)); 458 sb.append('/'); 459 sb.append(denominator.toString(base)); 460 String s = sb.toString().toUpperCase(); 461 if (_PRINT_RADIX_.symbolValue(thread) != NIL) { 462 sb.setLength(0); 463 switch (base) { 464 case 2: 465 sb.append("#b"); 466 sb.append(s); 467 break; 468 case 8: 469 sb.append("#o"); 470 sb.append(s); 471 break; 472 case 10: 473 sb.append("#10r"); 474 sb.append(s); 475 break; 476 case 16: 477 sb.append("#x"); 478 sb.append(s); 479 break; 480 default: 481 sb.append('#'); 482 sb.append(String.valueOf(base)); 483 sb.append('r'); 484 sb.append(s); 485 break; 486 } 487 s = sb.toString(); 488 } 489 return s; 490 } 491 } 492 | Popular Tags |