001: /*
002: * Ratio.java
003: *
004: * Copyright (C) 2003-2004 Peter Graves
005: * $Id: Ratio.java,v 1.46 2004/07/29 23:25:47 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: import java.math.BigInteger;
025:
026: public final class Ratio extends LispObject {
027: private BigInteger numerator;
028: private BigInteger denominator;
029:
030: public Ratio(BigInteger numerator, BigInteger denominator) {
031: this .numerator = numerator;
032: this .denominator = denominator;
033: }
034:
035: public BigInteger numerator() {
036: return numerator;
037: }
038:
039: public LispObject NUMERATOR() {
040: return number(numerator);
041: }
042:
043: public BigInteger denominator() {
044: return denominator;
045: }
046:
047: public LispObject DENOMINATOR() {
048: return number(denominator);
049: }
050:
051: public LispObject typeOf() {
052: return Symbol.RATIO;
053: }
054:
055: public LispClass classOf() {
056: return BuiltInClass.RATIO;
057: }
058:
059: public LispObject typep(LispObject type) throws ConditionThrowable {
060: if (type == Symbol.RATIO)
061: return T;
062: if (type == Symbol.RATIONAL)
063: return T;
064: if (type == Symbol.REAL)
065: return T;
066: if (type == Symbol.NUMBER)
067: return T;
068: if (type == BuiltInClass.RATIO)
069: return T;
070: return super .typep(type);
071: }
072:
073: public LispObject NUMBERP() {
074: return T;
075: }
076:
077: public boolean numberp() {
078: return true;
079: }
080:
081: public boolean rationalp() {
082: return true;
083: }
084:
085: public boolean realp() {
086: return true;
087: }
088:
089: public boolean eql(LispObject obj) {
090: if (this == obj)
091: return true;
092: if (obj instanceof Ratio) {
093: return numerator.equals(((Ratio) obj).numerator)
094: && denominator.equals(((Ratio) obj).denominator);
095: }
096: return false;
097: }
098:
099: public boolean equal(LispObject obj) {
100: return eql(obj);
101: }
102:
103: public boolean equalp(LispObject obj) {
104: if (obj instanceof Ratio) {
105: return numerator.equals(((Ratio) obj).numerator)
106: && denominator.equals(((Ratio) obj).denominator);
107: }
108: if (obj instanceof LispFloat) {
109: return floatValue() == ((LispFloat) obj).getValue();
110: }
111: return false;
112: }
113:
114: public LispObject ABS() {
115: if (numerator.signum() > 0 && denominator.signum() > 0)
116: return this ;
117: if (numerator.signum() < 0 && denominator.signum() < 0)
118: return this ;
119: return new Ratio(numerator.negate(), denominator);
120: }
121:
122: public boolean plusp() {
123: return numerator.signum() == denominator.signum();
124: }
125:
126: public boolean minusp() {
127: return numerator.signum() != denominator.signum();
128: }
129:
130: public boolean zerop() {
131: return false;
132: }
133:
134: public double floatValue() {
135: double result = numerator.doubleValue()
136: / denominator.doubleValue();
137: if (result != 0 && !Double.isNaN(result)
138: && !Double.isInfinite(result))
139: return result;
140: final boolean negative = numerator.signum() < 0;
141: final BigInteger num = negative ? numerator.negate()
142: : numerator;
143: final BigInteger den = denominator;
144: final int numLen = num.bitLength();
145: final int denLen = den.bitLength();
146: int length = Math.min(numLen, denLen);
147: if (length <= 1)
148: return result;
149: BigInteger n = num;
150: BigInteger d = den;
151: final int digits = 54;
152: if (length > digits) {
153: n = n.shiftRight(length - digits);
154: d = d.shiftRight(length - digits);
155: length -= digits;
156: } else {
157: n = n.shiftRight(1);
158: d = d.shiftRight(1);
159: --length;
160: }
161: for (int i = 0; i < length; i++) {
162: result = n.doubleValue() / d.doubleValue();
163: if (result != 0 && !Double.isNaN(result)
164: && !Double.isInfinite(result))
165: break;
166: n = n.shiftRight(1);
167: d = d.shiftRight(1);
168: }
169: return negative ? -result : result;
170: }
171:
172: public final LispObject incr() throws ConditionThrowable {
173: return new Ratio(numerator.add(denominator), denominator);
174: }
175:
176: public final LispObject decr() throws ConditionThrowable {
177: return new Ratio(numerator.subtract(denominator), denominator);
178: }
179:
180: public LispObject add(LispObject obj) throws ConditionThrowable {
181: if (obj instanceof Fixnum) {
182: BigInteger n = numerator.add(BigInteger.valueOf(
183: ((Fixnum) obj).getValue()).multiply(denominator));
184: return number(n, denominator);
185: }
186: if (obj instanceof Bignum) {
187: BigInteger n = ((Bignum) obj).getValue();
188: return number(numerator.add(n.multiply(denominator)),
189: denominator);
190: }
191: if (obj instanceof Ratio) {
192: BigInteger n = ((Ratio) obj).numerator;
193: BigInteger d = ((Ratio) obj).denominator;
194: if (denominator.equals(d))
195: return number(numerator.add(n), denominator);
196: BigInteger common = denominator.multiply(d);
197: return number(numerator.multiply(d).add(
198: n.multiply(denominator)), common);
199: }
200: if (obj instanceof LispFloat) {
201: return new LispFloat(floatValue()
202: + ((LispFloat) obj).getValue());
203: }
204: if (obj instanceof Complex) {
205: Complex c = (Complex) obj;
206: return Complex.getInstance(add(c.getRealPart()), c
207: .getImaginaryPart());
208: }
209: return signal(new TypeError(obj, "number"));
210: }
211:
212: public LispObject subtract(LispObject obj)
213: throws ConditionThrowable {
214: if (obj instanceof Fixnum) {
215: BigInteger n = numerator.subtract(BigInteger.valueOf(
216: ((Fixnum) obj).getValue()).multiply(denominator));
217: return number(n, denominator);
218: }
219: if (obj instanceof Bignum) {
220: BigInteger n = ((Bignum) obj).getValue();
221: return number(numerator.subtract(n.multiply(denominator)),
222: denominator);
223: }
224: if (obj instanceof Ratio) {
225: BigInteger n = ((Ratio) obj).numerator;
226: BigInteger d = ((Ratio) obj).denominator;
227: if (denominator.equals(d))
228: return number(numerator.subtract(n), denominator);
229: BigInteger common = denominator.multiply(d);
230: return number(numerator.multiply(d).subtract(
231: n.multiply(denominator)), common);
232: }
233: if (obj instanceof LispFloat) {
234: return new LispFloat(floatValue()
235: - ((LispFloat) obj).getValue());
236: }
237: if (obj instanceof Complex) {
238: Complex c = (Complex) obj;
239: return Complex.getInstance(subtract(c.getRealPart()),
240: Fixnum.ZERO.subtract(c.getImaginaryPart()));
241: }
242: return signal(new TypeError(obj, "number"));
243: }
244:
245: public LispObject multiplyBy(LispObject obj)
246: throws ConditionThrowable {
247: if (obj instanceof Fixnum) {
248: BigInteger n = ((Fixnum) obj).getBigInteger();
249: return number(numerator.multiply(n), denominator);
250: }
251: if (obj instanceof Bignum) {
252: BigInteger n = ((Bignum) obj).getValue();
253: return number(numerator.multiply(n), denominator);
254: }
255: if (obj instanceof Ratio) {
256: BigInteger n = ((Ratio) obj).numerator;
257: BigInteger d = ((Ratio) obj).denominator;
258: return number(numerator.multiply(n), denominator
259: .multiply(d));
260: }
261: if (obj instanceof LispFloat) {
262: return new LispFloat(floatValue()
263: * ((LispFloat) obj).getValue());
264: }
265: return signal(new TypeError(obj, "number"));
266: }
267:
268: public LispObject divideBy(LispObject obj)
269: throws ConditionThrowable {
270: if (obj instanceof Fixnum) {
271: BigInteger n = ((Fixnum) obj).getBigInteger();
272: return number(numerator, denominator.multiply(n));
273: }
274: if (obj instanceof Bignum) {
275: BigInteger n = ((Bignum) obj).getValue();
276: return number(numerator, denominator.multiply(n));
277: }
278: if (obj instanceof Ratio) {
279: BigInteger n = ((Ratio) obj).numerator;
280: BigInteger d = ((Ratio) obj).denominator;
281: return number(numerator.multiply(d), denominator
282: .multiply(n));
283: }
284: if (obj instanceof LispFloat) {
285: if (obj.zerop())
286: return signal(new DivisionByZero());
287: return new LispFloat(floatValue()
288: / ((LispFloat) obj).getValue());
289: }
290: return signal(new TypeError(obj, "number"));
291: }
292:
293: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
294: if (obj instanceof Ratio)
295: return (numerator.equals(((Ratio) obj).numerator) && denominator
296: .equals(((Ratio) obj).denominator));
297: if (obj instanceof LispFloat)
298: return isEqualTo(((LispFloat) obj).rational());
299: if (obj.numberp())
300: return false;
301: signal(new TypeError(obj, "number"));
302: // Not reached.
303: return false;
304: }
305:
306: public boolean isNotEqualTo(LispObject obj)
307: throws ConditionThrowable {
308: return !isEqualTo(obj);
309: }
310:
311: public boolean isLessThan(LispObject obj) throws ConditionThrowable {
312: if (obj instanceof Fixnum) {
313: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
314: denominator);
315: return numerator.compareTo(n2) < 0;
316: }
317: if (obj instanceof Bignum) {
318: BigInteger n = ((Bignum) obj).getValue().multiply(
319: denominator);
320: return numerator.compareTo(n) < 0;
321: }
322: if (obj instanceof Ratio) {
323: BigInteger n1 = numerator
324: .multiply(((Ratio) obj).denominator);
325: BigInteger n2 = ((Ratio) obj).numerator
326: .multiply(denominator);
327: return n1.compareTo(n2) < 0;
328: }
329: if (obj instanceof LispFloat)
330: return isLessThan(((LispFloat) obj).rational());
331: signal(new TypeError(obj, Symbol.REAL));
332: // Not reached.
333: return false;
334: }
335:
336: public boolean isGreaterThan(LispObject obj)
337: throws ConditionThrowable {
338: if (obj instanceof Fixnum) {
339: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
340: denominator);
341: return numerator.compareTo(n2) > 0;
342: }
343: if (obj instanceof Bignum) {
344: BigInteger n = ((Bignum) obj).getValue().multiply(
345: denominator);
346: return numerator.compareTo(n) > 0;
347: }
348: if (obj instanceof Ratio) {
349: BigInteger n1 = numerator
350: .multiply(((Ratio) obj).denominator);
351: BigInteger n2 = ((Ratio) obj).numerator
352: .multiply(denominator);
353: return n1.compareTo(n2) > 0;
354: }
355: if (obj instanceof LispFloat)
356: return isGreaterThan(((LispFloat) obj).rational());
357: signal(new TypeError(obj, Symbol.REAL));
358: // Not reached.
359: return false;
360: }
361:
362: public boolean isLessThanOrEqualTo(LispObject obj)
363: throws ConditionThrowable {
364: if (obj instanceof Fixnum) {
365: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
366: denominator);
367: return numerator.compareTo(n2) <= 0;
368: }
369: if (obj instanceof Bignum) {
370: BigInteger n = ((Bignum) obj).getValue().multiply(
371: denominator);
372: return numerator.compareTo(n) <= 0;
373: }
374: if (obj instanceof Ratio) {
375: BigInteger n1 = numerator
376: .multiply(((Ratio) obj).denominator);
377: BigInteger n2 = ((Ratio) obj).numerator
378: .multiply(denominator);
379: return n1.compareTo(n2) <= 0;
380: }
381: if (obj instanceof LispFloat)
382: return isLessThanOrEqualTo(((LispFloat) obj).rational());
383: signal(new TypeError(obj, Symbol.REAL));
384: // Not reached.
385: return false;
386: }
387:
388: public boolean isGreaterThanOrEqualTo(LispObject obj)
389: throws ConditionThrowable {
390: if (obj instanceof Fixnum) {
391: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
392: denominator);
393: return numerator.compareTo(n2) >= 0;
394: }
395: if (obj instanceof Bignum) {
396: BigInteger n = ((Bignum) obj).getValue().multiply(
397: denominator);
398: return numerator.compareTo(n) >= 0;
399: }
400: if (obj instanceof Ratio) {
401: BigInteger n1 = numerator
402: .multiply(((Ratio) obj).denominator);
403: BigInteger n2 = ((Ratio) obj).numerator
404: .multiply(denominator);
405: return n1.compareTo(n2) >= 0;
406: }
407: if (obj instanceof LispFloat)
408: return isGreaterThanOrEqualTo(((LispFloat) obj).rational());
409: signal(new TypeError(obj, Symbol.REAL));
410: // Not reached.
411: return false;
412: }
413:
414: public LispObject truncate(LispObject obj)
415: throws ConditionThrowable {
416: if (obj instanceof LispFloat)
417: return new LispFloat(floatValue()).truncate(obj);
418: BigInteger n, d;
419: try {
420: if (obj instanceof Fixnum) {
421: n = ((Fixnum) obj).getBigInteger();
422: d = BigInteger.ONE;
423: } else if (obj instanceof Bignum) {
424: n = ((Bignum) obj).getValue();
425: d = BigInteger.ONE;
426: } else if (obj instanceof Ratio) {
427: n = ((Ratio) obj).numerator();
428: d = ((Ratio) obj).denominator();
429: } else {
430: return signal(new TypeError(obj, "number"));
431: }
432: // Invert and multiply.
433: BigInteger num = numerator.multiply(d);
434: BigInteger den = denominator.multiply(n);
435: BigInteger quotient = num.divide(den);
436: // Multiply quotient by divisor.
437: LispObject product = number(quotient.multiply(n), d);
438: // Subtract to get remainder.
439: LispObject remainder = subtract(product);
440: return LispThread.currentThread().setValues(
441: number(quotient), remainder);
442: } catch (ArithmeticException e) {
443: if (obj.zerop())
444: return signal(new DivisionByZero());
445: return signal(new ArithmeticError(e.getMessage()));
446: }
447: }
448:
449: public int hashCode() {
450: return numerator.hashCode() ^ denominator.hashCode();
451: }
452:
453: public String writeToString() throws ConditionThrowable {
454: final LispThread thread = LispThread.currentThread();
455: int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread));
456: StringBuffer sb = new StringBuffer(numerator.toString(base));
457: sb.append('/');
458: sb.append(denominator.toString(base));
459: String s = sb.toString().toUpperCase();
460: if (_PRINT_RADIX_.symbolValue(thread) != NIL) {
461: sb.setLength(0);
462: switch (base) {
463: case 2:
464: sb.append("#b");
465: sb.append(s);
466: break;
467: case 8:
468: sb.append("#o");
469: sb.append(s);
470: break;
471: case 10:
472: sb.append("#10r");
473: sb.append(s);
474: break;
475: case 16:
476: sb.append("#x");
477: sb.append(s);
478: break;
479: default:
480: sb.append('#');
481: sb.append(String.valueOf(base));
482: sb.append('r');
483: sb.append(s);
484: break;
485: }
486: s = sb.toString();
487: }
488: return s;
489: }
490: }
|