1 /* 2 * Ratio.java 3 * 4 * Copyright (C) 2003-2005 Peter Graves 5 * $Id$ 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 * As a special exception, the copyright holders of this library give you 22 * permission to link this library with independent modules to produce an 23 * executable, regardless of the license terms of these independent 24 * modules, and to copy and distribute the resulting executable under 25 * terms of your choice, provided that you also meet, for each linked 26 * independent module, the terms and conditions of the license of that 27 * module. An independent module is a module which is not derived from 28 * or based on this library. If you modify this library, you may extend 29 * this exception to your version of the library, but you are not 30 * obligated to do so. If you do not wish to do so, delete this 31 * exception statement from your version. 32 */ 33 34 package org.armedbear.lisp; 35 36 import static org.armedbear.lisp.Lisp.*; 37 38 import java.math.BigInteger; 39 import java.math.BigDecimal; 40 import java.math.MathContext; 41 import java.math.RoundingMode; 42 43 public final class Ratio extends LispObject 44 { 45 private BigInteger numerator; 46 private BigInteger denominator; 47 Ratio(BigInteger numerator, BigInteger denominator)48 public Ratio(BigInteger numerator, BigInteger denominator) 49 { 50 this.numerator = numerator; 51 this.denominator = denominator; 52 } 53 numerator()54 public BigInteger numerator() 55 { 56 return numerator; 57 } 58 59 @Override NUMERATOR()60 public LispObject NUMERATOR() 61 { 62 return number(numerator); 63 } 64 denominator()65 public BigInteger denominator() 66 { 67 return denominator; 68 } 69 70 @Override DENOMINATOR()71 public LispObject DENOMINATOR() 72 { 73 return number(denominator); 74 } 75 76 @Override typeOf()77 public LispObject typeOf() 78 { 79 return Symbol.RATIO; 80 } 81 82 @Override classOf()83 public LispObject classOf() 84 { 85 return BuiltInClass.RATIO; 86 } 87 88 @Override typep(LispObject type)89 public LispObject typep(LispObject type) 90 { 91 if (type == Symbol.RATIO) 92 return T; 93 if (type == Symbol.RATIONAL) 94 return T; 95 if (type == Symbol.REAL) 96 return T; 97 if (type == Symbol.NUMBER) 98 return T; 99 if (type == BuiltInClass.RATIO) 100 return T; 101 return super.typep(type); 102 } 103 104 @Override numberp()105 public boolean numberp() 106 { 107 return true; 108 } 109 110 @Override rationalp()111 public boolean rationalp() 112 { 113 return true; 114 } 115 116 @Override realp()117 public boolean realp() 118 { 119 return true; 120 } 121 122 @Override eql(LispObject obj)123 public boolean eql(LispObject obj) 124 { 125 if (this == obj) 126 return true; 127 if (obj instanceof Ratio) { 128 return (numerator.equals(((Ratio)obj).numerator) && 129 denominator.equals(((Ratio)obj).denominator)); 130 } 131 return false; 132 } 133 134 @Override equal(LispObject obj)135 public boolean equal(LispObject obj) 136 { 137 return eql(obj); 138 } 139 140 @Override equalp(LispObject obj)141 public boolean equalp(LispObject obj) 142 { 143 if (obj != null && obj.numberp()) 144 return isEqualTo(obj); 145 return false; 146 } 147 148 @Override ABS()149 public LispObject ABS() 150 { 151 if (numerator.signum() > 0 && denominator.signum() > 0) 152 return this; 153 if (numerator.signum() < 0 && denominator.signum() < 0) 154 return this; 155 return new Ratio(numerator.negate(), denominator); 156 } 157 158 @Override plusp()159 public boolean plusp() 160 { 161 return numerator.signum() == denominator.signum(); 162 } 163 164 @Override minusp()165 public boolean minusp() 166 { 167 return numerator.signum() != denominator.signum(); 168 } 169 170 @Override zerop()171 public boolean zerop() 172 { 173 return false; 174 } 175 176 @Override floatValue()177 public float floatValue() 178 { 179 float result = (float) doubleValue(); 180 if (Float.isInfinite(result) && TRAP_OVERFLOW) 181 type_error(this, Symbol.SINGLE_FLOAT); 182 183 return (float) doubleValue(); 184 } 185 186 @Override doubleValue()187 public double doubleValue() 188 { 189 double result = numerator.doubleValue() / denominator.doubleValue(); 190 if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result)) 191 return result; 192 final boolean negative = numerator.signum() < 0; 193 final BigInteger num = negative ? numerator.negate() : numerator; 194 final BigInteger den = denominator; 195 final int numLen = num.bitLength(); 196 final int denLen = den.bitLength(); 197 int length = Math.min(numLen, denLen); 198 if (length <= 1) { 199 // A precision of 512 is overkill for DOUBLE-FLOAT types 200 // based on java.lang.Double TODO: optimize for space/time 201 final MathContext mathContext = new MathContext(512, RoundingMode.HALF_EVEN); 202 BigDecimal p = new BigDecimal(numerator, mathContext); 203 BigDecimal q = new BigDecimal(denominator, mathContext); 204 BigDecimal r = p.divide(q, mathContext); 205 result = r.doubleValue(); 206 return result; 207 } 208 209 BigInteger n = num; 210 BigInteger d = den; 211 final int digits = 54; 212 if (length > digits) { 213 n = n.shiftRight(length - digits); 214 d = d.shiftRight(length - digits); 215 length -= digits; 216 } else { 217 n = n.shiftRight(1); 218 d = d.shiftRight(1); 219 --length; 220 } 221 for (int i = 0; i < length; i++) { 222 result = n.doubleValue() / d.doubleValue(); 223 if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result)) 224 break; 225 n = n.shiftRight(1); 226 d = d.shiftRight(1); 227 } 228 if (Double.isInfinite(result) && TRAP_OVERFLOW) 229 type_error(this, Symbol.DOUBLE_FLOAT); 230 231 return negative ? -result : result; 232 } 233 234 @Override 235 public final LispObject incr() 236 { 237 return new Ratio(numerator.add(denominator), denominator); 238 } 239 240 @Override 241 public final LispObject decr() 242 { 243 return new Ratio(numerator.subtract(denominator), denominator); 244 } 245 246 @Override 247 public LispObject add(LispObject obj) 248 { 249 if (obj instanceof Fixnum) { 250 BigInteger n = 251 numerator.add(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator)); 252 return number(n, denominator); 253 } 254 if (obj instanceof Bignum) { 255 BigInteger n = ((Bignum)obj).value; 256 return number(numerator.add(n.multiply(denominator)), 257 denominator); 258 } 259 if (obj instanceof Ratio) { 260 BigInteger n = ((Ratio)obj).numerator; 261 BigInteger d = ((Ratio)obj).denominator; 262 if (denominator.equals(d)) 263 return number(numerator.add(n), denominator); 264 BigInteger common = denominator.multiply(d); 265 return number(numerator.multiply(d).add(n.multiply(denominator)), 266 common); 267 } 268 if (obj instanceof SingleFloat) { 269 return new SingleFloat(floatValue() + ((SingleFloat)obj).value); 270 } 271 if (obj instanceof DoubleFloat) { 272 return new DoubleFloat(doubleValue() + ((DoubleFloat)obj).value); 273 } 274 if (obj instanceof Complex) { 275 Complex c = (Complex) obj; 276 return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart()); 277 } 278 return type_error(obj, Symbol.NUMBER); 279 } 280 281 @Override 282 public LispObject subtract(LispObject obj) 283 { 284 if (obj instanceof Fixnum) { 285 BigInteger n = 286 numerator.subtract(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator)); 287 return number(n, denominator); 288 } 289 if (obj instanceof Bignum) { 290 BigInteger n = ((Bignum)obj).value; 291 return number(numerator.subtract(n.multiply(denominator)), 292 denominator); 293 } 294 if (obj instanceof Ratio) { 295 BigInteger n = ((Ratio)obj).numerator; 296 BigInteger d = ((Ratio)obj).denominator; 297 if (denominator.equals(d)) 298 return number(numerator.subtract(n), denominator); 299 BigInteger common = denominator.multiply(d); 300 return number(numerator.multiply(d).subtract(n.multiply(denominator)), 301 common); 302 } 303 if (obj instanceof SingleFloat) { 304 return new SingleFloat(floatValue() - ((SingleFloat)obj).value); 305 } 306 if (obj instanceof DoubleFloat) { 307 return new DoubleFloat(doubleValue() - ((DoubleFloat)obj).value); 308 } 309 if (obj instanceof Complex) { 310 Complex c = (Complex) obj; 311 return Complex.getInstance(subtract(c.getRealPart()), 312 Fixnum.ZERO.subtract(c.getImaginaryPart())); 313 } 314 return type_error(obj, Symbol.NUMBER); 315 } 316 317 @Override 318 public LispObject multiplyBy(LispObject obj) 319 { 320 if (obj instanceof Fixnum) { 321 BigInteger n = ((Fixnum)obj).getBigInteger(); 322 return number(numerator.multiply(n), denominator); 323 } 324 if (obj instanceof Bignum) { 325 BigInteger n = ((Bignum)obj).value; 326 return number(numerator.multiply(n), denominator); 327 } 328 if (obj instanceof Ratio) { 329 BigInteger n = ((Ratio)obj).numerator; 330 BigInteger d = ((Ratio)obj).denominator; 331 return number(numerator.multiply(n), denominator.multiply(d)); 332 } 333 if (obj instanceof SingleFloat) { 334 return new SingleFloat(floatValue() * ((SingleFloat)obj).value); 335 } 336 if (obj instanceof DoubleFloat) { 337 return new DoubleFloat(doubleValue() * ((DoubleFloat)obj).value); 338 } 339 if (obj instanceof Complex) { 340 Complex c = (Complex) obj; 341 return Complex.getInstance(multiplyBy(c.getRealPart()), 342 multiplyBy(c.getImaginaryPart())); 343 } 344 return type_error(obj, Symbol.NUMBER); 345 } 346 347 @Override 348 public LispObject divideBy(LispObject obj) 349 { 350 if (obj instanceof Fixnum) { 351 BigInteger n = ((Fixnum)obj).getBigInteger(); 352 return number(numerator, denominator.multiply(n)); 353 } 354 if (obj instanceof Bignum) { 355 BigInteger n = ((Bignum)obj).value; 356 return number(numerator, denominator.multiply(n)); 357 } 358 if (obj instanceof Ratio) { 359 BigInteger n = ((Ratio)obj).numerator; 360 BigInteger d = ((Ratio)obj).denominator; 361 return number(numerator.multiply(d), denominator.multiply(n)); 362 } 363 if (obj instanceof SingleFloat) { 364 if (obj.zerop()) 365 return error(new DivisionByZero()); 366 return new SingleFloat(floatValue() / ((SingleFloat)obj).value); 367 } 368 if (obj instanceof DoubleFloat) { 369 if (obj.zerop()) 370 return error(new DivisionByZero()); 371 return new DoubleFloat(doubleValue() / ((DoubleFloat)obj).value); 372 } 373 if (obj instanceof Complex) { 374 Complex c = (Complex) obj; 375 // numerator 376 LispObject realPart = this.multiplyBy(c.getRealPart()); 377 LispObject imagPart = 378 Fixnum.ZERO.subtract(this).multiplyBy(c.getImaginaryPart()); 379 // denominator 380 LispObject d = 381 c.getRealPart().multiplyBy(c.getRealPart()); 382 d = d.add(c.getImaginaryPart().multiplyBy(c.getImaginaryPart())); 383 return Complex.getInstance(realPart.divideBy(d), 384 imagPart.divideBy(d)); 385 } 386 return type_error(obj, Symbol.NUMBER); 387 } 388 389 @Override 390 public boolean isEqualTo(LispObject obj) 391 { 392 if (obj instanceof Ratio) 393 return (numerator.equals(((Ratio)obj).numerator) && 394 denominator.equals(((Ratio)obj).denominator)); 395 if (obj instanceof SingleFloat) 396 return isEqualTo(((SingleFloat)obj).rational()); 397 if (obj instanceof DoubleFloat) 398 return isEqualTo(((DoubleFloat)obj).rational()); 399 if (obj.numberp()) 400 return false; 401 type_error(obj, Symbol.NUMBER); 402 // Not reached. 403 return false; 404 } 405 406 @Override 407 public boolean isNotEqualTo(LispObject obj) 408 { 409 return !isEqualTo(obj); 410 } 411 412 @Override 413 public boolean isLessThan(LispObject obj) 414 { 415 if (obj instanceof Fixnum) { 416 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 417 return numerator.compareTo(n2) < 0; 418 } 419 if (obj instanceof Bignum) { 420 BigInteger n = ((Bignum)obj).value.multiply(denominator); 421 return numerator.compareTo(n) < 0; 422 } 423 if (obj instanceof Ratio) { 424 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 425 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 426 return n1.compareTo(n2) < 0; 427 } 428 if (obj instanceof SingleFloat) 429 return isLessThan(((SingleFloat)obj).rational()); 430 if (obj instanceof DoubleFloat) 431 return isLessThan(((DoubleFloat)obj).rational()); 432 type_error(obj, Symbol.REAL); 433 // Not reached. 434 return false; 435 } 436 437 @Override 438 public boolean isGreaterThan(LispObject obj) 439 { 440 if (obj instanceof Fixnum) { 441 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 442 return numerator.compareTo(n2) > 0; 443 } 444 if (obj instanceof Bignum) { 445 BigInteger n = ((Bignum)obj).value.multiply(denominator); 446 return numerator.compareTo(n) > 0; 447 } 448 if (obj instanceof Ratio) { 449 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 450 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 451 return n1.compareTo(n2) > 0; 452 } 453 if (obj instanceof SingleFloat) 454 return isGreaterThan(((SingleFloat)obj).rational()); 455 if (obj instanceof DoubleFloat) 456 return isGreaterThan(((DoubleFloat)obj).rational()); 457 type_error(obj, Symbol.REAL); 458 // Not reached. 459 return false; 460 } 461 462 @Override 463 public boolean isLessThanOrEqualTo(LispObject obj) 464 { 465 if (obj instanceof Fixnum) { 466 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 467 return numerator.compareTo(n2) <= 0; 468 } 469 if (obj instanceof Bignum) { 470 BigInteger n = ((Bignum)obj).value.multiply(denominator); 471 return numerator.compareTo(n) <= 0; 472 } 473 if (obj instanceof Ratio) { 474 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 475 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 476 return n1.compareTo(n2) <= 0; 477 } 478 if (obj instanceof SingleFloat) 479 return isLessThanOrEqualTo(((SingleFloat)obj).rational()); 480 if (obj instanceof DoubleFloat) 481 return isLessThanOrEqualTo(((DoubleFloat)obj).rational()); 482 type_error(obj, Symbol.REAL); 483 // Not reached. 484 return false; 485 } 486 487 @Override 488 public boolean isGreaterThanOrEqualTo(LispObject obj) 489 { 490 if (obj instanceof Fixnum) { 491 BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator); 492 return numerator.compareTo(n2) >= 0; 493 } 494 if (obj instanceof Bignum) { 495 BigInteger n = ((Bignum)obj).value.multiply(denominator); 496 return numerator.compareTo(n) >= 0; 497 } 498 if (obj instanceof Ratio) { 499 BigInteger n1 = numerator.multiply(((Ratio)obj).denominator); 500 BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator); 501 return n1.compareTo(n2) >= 0; 502 } 503 if (obj instanceof SingleFloat) 504 return isGreaterThanOrEqualTo(((SingleFloat)obj).rational()); 505 if (obj instanceof DoubleFloat) 506 return isGreaterThanOrEqualTo(((DoubleFloat)obj).rational()); 507 type_error(obj, Symbol.REAL); 508 // Not reached. 509 return false; 510 } 511 512 @Override 513 public LispObject truncate(LispObject obj) 514 { 515 // "When rationals and floats are combined by a numerical function, 516 // the rational is first converted to a float of the same format." 517 // 12.1.4.1 518 if (obj instanceof SingleFloat) 519 return new SingleFloat(floatValue()).truncate(obj); 520 if (obj instanceof DoubleFloat) 521 return new DoubleFloat(doubleValue()).truncate(obj); 522 BigInteger n, d; 523 try { 524 if (obj instanceof Fixnum) { 525 n = ((Fixnum)obj).getBigInteger(); 526 d = BigInteger.ONE; 527 } else if (obj instanceof Bignum) { 528 n = ((Bignum)obj).value; 529 d = BigInteger.ONE; 530 } else if (obj instanceof Ratio) { 531 n = ((Ratio)obj).numerator(); 532 d = ((Ratio)obj).denominator(); 533 } else { 534 return type_error(obj, Symbol.NUMBER); 535 } 536 // Invert and multiply. 537 BigInteger num = numerator.multiply(d); 538 BigInteger den = denominator.multiply(n); 539 BigInteger quotient = num.divide(den); 540 // Multiply quotient by divisor. 541 LispObject product = number(quotient.multiply(n), d); 542 // Subtract to get remainder. 543 LispObject remainder = subtract(product); 544 return LispThread.currentThread().setValues(number(quotient), remainder); 545 } 546 catch (ArithmeticException e) { 547 if (obj.zerop()) 548 return error(new DivisionByZero()); 549 return error(new ArithmeticError(e.getMessage())); 550 } 551 } 552 553 @Override 554 public int hashCode() 555 { 556 return numerator.hashCode() ^ denominator.hashCode(); 557 } 558 559 @Override 560 public String printObject() 561 { 562 final LispThread thread = LispThread.currentThread(); 563 int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue(thread)); 564 StringBuffer sb = new StringBuffer(numerator.toString(base)); 565 sb.append('/'); 566 sb.append(denominator.toString(base)); 567 String s = sb.toString().toUpperCase(); 568 if (Symbol.PRINT_RADIX.symbolValue(thread) != NIL) { 569 sb.setLength(0); 570 switch (base) { 571 case 2: 572 sb.append("#b"); 573 sb.append(s); 574 break; 575 case 8: 576 sb.append("#o"); 577 sb.append(s); 578 break; 579 case 10: 580 sb.append("#10r"); 581 sb.append(s); 582 break; 583 case 16: 584 sb.append("#x"); 585 sb.append(s); 586 break; 587 default: 588 sb.append('#'); 589 sb.append(String.valueOf(base)); 590 sb.append('r'); 591 sb.append(s); 592 break; 593 } 594 s = sb.toString(); 595 } 596 return s; 597 } 598 } 599