001: /*
002: * Ratio.java
003: *
004: * Copyright (C) 2003 Peter Graves
005: * $Id: Ratio.java,v 1.7 2003/11/15 11:03:29 beedlem 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: return numerator.doubleValue() / denominator.doubleValue();
136: }
137:
138: public final LispObject incr() throws ConditionThrowable {
139: return new Ratio(numerator.add(denominator), denominator);
140: }
141:
142: public final LispObject decr() throws ConditionThrowable {
143: return new Ratio(numerator.subtract(denominator), denominator);
144: }
145:
146: public LispObject add(LispObject obj) throws ConditionThrowable {
147: if (obj instanceof Fixnum) {
148: BigInteger n = numerator.add(BigInteger.valueOf(
149: ((Fixnum) obj).getValue()).multiply(denominator));
150: return number(n, denominator);
151: }
152: if (obj instanceof Bignum) {
153: BigInteger n = ((Bignum) obj).getValue();
154: return number(numerator.add(n.multiply(denominator)),
155: denominator);
156: }
157: if (obj instanceof Ratio) {
158: BigInteger n = ((Ratio) obj).numerator;
159: BigInteger d = ((Ratio) obj).denominator;
160: if (denominator.equals(d))
161: return number(numerator.add(n), denominator);
162: BigInteger common = denominator.multiply(d);
163: return number(numerator.multiply(d).add(
164: n.multiply(denominator)), common);
165: }
166: if (obj instanceof LispFloat) {
167: return new LispFloat(floatValue()
168: + ((LispFloat) obj).getValue());
169: }
170: if (obj instanceof Complex) {
171: Complex c = (Complex) obj;
172: return Complex.getInstance(add(c.getRealPart()), c
173: .getImaginaryPart());
174: }
175: throw new ConditionThrowable(new TypeError(obj, "number"));
176: }
177:
178: public LispObject subtract(LispObject obj)
179: throws ConditionThrowable {
180: if (obj instanceof Fixnum) {
181: BigInteger n = numerator.subtract(BigInteger.valueOf(
182: ((Fixnum) obj).getValue()).multiply(denominator));
183: return number(n, denominator);
184: }
185: if (obj instanceof Bignum) {
186: BigInteger n = ((Bignum) obj).getValue();
187: return number(numerator.subtract(n.multiply(denominator)),
188: denominator);
189: }
190: if (obj instanceof Ratio) {
191: BigInteger n = ((Ratio) obj).numerator;
192: BigInteger d = ((Ratio) obj).denominator;
193: if (denominator.equals(d))
194: return number(numerator.subtract(n), denominator);
195: BigInteger common = denominator.multiply(d);
196: return number(numerator.multiply(d).subtract(
197: n.multiply(denominator)), common);
198: }
199: if (obj instanceof LispFloat) {
200: return new LispFloat(floatValue()
201: - ((LispFloat) obj).getValue());
202: }
203: if (obj instanceof Complex) {
204: Complex c = (Complex) obj;
205: return Complex.getInstance(subtract(c.getRealPart()),
206: Fixnum.ZERO.subtract(c.getImaginaryPart()));
207: }
208: throw new ConditionThrowable(new TypeError(obj, "number"));
209: }
210:
211: public LispObject multiplyBy(LispObject obj)
212: throws ConditionThrowable {
213: if (obj instanceof Fixnum) {
214: BigInteger n = ((Fixnum) obj).getBigInteger();
215: return number(numerator.multiply(n), denominator);
216: }
217: if (obj instanceof Bignum) {
218: BigInteger n = ((Bignum) obj).getValue();
219: return number(numerator.multiply(n), denominator);
220: }
221: if (obj instanceof Ratio) {
222: BigInteger n = ((Ratio) obj).numerator;
223: BigInteger d = ((Ratio) obj).denominator;
224: return number(numerator.multiply(n), denominator
225: .multiply(d));
226: }
227: if (obj instanceof LispFloat) {
228: return new LispFloat(floatValue()
229: * ((LispFloat) obj).getValue());
230: }
231: throw new ConditionThrowable(new TypeError(obj, "number"));
232: }
233:
234: public LispObject divideBy(LispObject obj)
235: throws ConditionThrowable {
236: if (obj instanceof Fixnum) {
237: BigInteger n = ((Fixnum) obj).getBigInteger();
238: return number(numerator, denominator.multiply(n));
239: }
240: if (obj instanceof Bignum) {
241: BigInteger n = ((Bignum) obj).getValue();
242: return number(numerator, denominator.multiply(n));
243: }
244: if (obj instanceof Ratio) {
245: BigInteger n = ((Ratio) obj).numerator;
246: BigInteger d = ((Ratio) obj).denominator;
247: return number(numerator.multiply(d), denominator
248: .multiply(n));
249: }
250: if (obj instanceof LispFloat) {
251: if (obj.zerop())
252: throw new ConditionThrowable(new DivisionByZero());
253: return new LispFloat(floatValue()
254: / ((LispFloat) obj).getValue());
255: }
256: throw new ConditionThrowable(new TypeError(obj, "number"));
257: }
258:
259: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
260: if (obj instanceof Ratio)
261: return (numerator.equals(((Ratio) obj).numerator) && denominator
262: .equals(((Ratio) obj).denominator));
263: if (obj instanceof LispFloat)
264: return floatValue() == ((LispFloat) obj).getValue();
265: if (obj.numberp())
266: return false;
267: throw new ConditionThrowable(new TypeError(obj, "number"));
268: }
269:
270: public boolean isNotEqualTo(LispObject obj)
271: throws ConditionThrowable {
272: return !isEqualTo(obj);
273: }
274:
275: public boolean isLessThan(LispObject obj) throws ConditionThrowable {
276: if (obj instanceof Fixnum) {
277: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
278: denominator);
279: return numerator.compareTo(n2) < 0;
280: }
281: if (obj instanceof Bignum) {
282: BigInteger n = ((Bignum) obj).getValue().multiply(
283: denominator);
284: return numerator.compareTo(n) < 0;
285: }
286: if (obj instanceof Ratio) {
287: BigInteger n1 = numerator
288: .multiply(((Ratio) obj).denominator);
289: BigInteger n2 = ((Ratio) obj).numerator
290: .multiply(denominator);
291: return n1.compareTo(n2) < 0;
292: }
293: if (obj instanceof LispFloat) {
294: return floatValue() < ((LispFloat) obj).getValue();
295: }
296: throw new ConditionThrowable(new TypeError(obj, "real"));
297: }
298:
299: public boolean isGreaterThan(LispObject obj)
300: throws ConditionThrowable {
301: if (obj instanceof Fixnum) {
302: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
303: denominator);
304: return numerator.compareTo(n2) > 0;
305: }
306: if (obj instanceof Bignum) {
307: BigInteger n = ((Bignum) obj).getValue().multiply(
308: denominator);
309: return numerator.compareTo(n) > 0;
310: }
311: if (obj instanceof Ratio) {
312: BigInteger n1 = numerator
313: .multiply(((Ratio) obj).denominator);
314: BigInteger n2 = ((Ratio) obj).numerator
315: .multiply(denominator);
316: return n1.compareTo(n2) > 0;
317: }
318: if (obj instanceof LispFloat) {
319: return floatValue() > ((LispFloat) obj).getValue();
320: }
321: throw new ConditionThrowable(new TypeError(obj, "real"));
322: }
323:
324: public boolean isLessThanOrEqualTo(LispObject obj)
325: throws ConditionThrowable {
326: if (obj instanceof Fixnum) {
327: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
328: denominator);
329: return numerator.compareTo(n2) <= 0;
330: }
331: if (obj instanceof Bignum) {
332: BigInteger n = ((Bignum) obj).getValue().multiply(
333: denominator);
334: return numerator.compareTo(n) <= 0;
335: }
336: if (obj instanceof Ratio) {
337: BigInteger n1 = numerator
338: .multiply(((Ratio) obj).denominator);
339: BigInteger n2 = ((Ratio) obj).numerator
340: .multiply(denominator);
341: return n1.compareTo(n2) <= 0;
342: }
343: if (obj instanceof LispFloat) {
344: return floatValue() <= ((LispFloat) obj).getValue();
345: }
346: throw new ConditionThrowable(new TypeError(obj, "real"));
347: }
348:
349: public boolean isGreaterThanOrEqualTo(LispObject obj)
350: throws ConditionThrowable {
351: if (obj instanceof Fixnum) {
352: BigInteger n2 = ((Fixnum) obj).getBigInteger().multiply(
353: denominator);
354: return numerator.compareTo(n2) >= 0;
355: }
356: if (obj instanceof Bignum) {
357: BigInteger n = ((Bignum) obj).getValue().multiply(
358: denominator);
359: return numerator.compareTo(n) >= 0;
360: }
361: if (obj instanceof Ratio) {
362: BigInteger n1 = numerator
363: .multiply(((Ratio) obj).denominator);
364: BigInteger n2 = ((Ratio) obj).numerator
365: .multiply(denominator);
366: return n1.compareTo(n2) >= 0;
367: }
368: if (obj instanceof LispFloat) {
369: return floatValue() >= ((LispFloat) obj).getValue();
370: }
371: throw new ConditionThrowable(new TypeError(obj, "real"));
372: }
373:
374: public LispObject truncate(LispObject obj)
375: throws ConditionThrowable {
376: BigInteger n, d;
377: try {
378: if (obj instanceof Fixnum) {
379: n = ((Fixnum) obj).getBigInteger();
380: d = BigInteger.ONE;
381: } else if (obj instanceof Bignum) {
382: n = ((Bignum) obj).getValue();
383: d = BigInteger.ONE;
384: } else if (obj instanceof Ratio) {
385: n = ((Ratio) obj).numerator();
386: d = ((Ratio) obj).denominator();
387: } else {
388: Thread.dumpStack();
389: throw new ConditionThrowable(new TypeError(obj,
390: "number"));
391: }
392:
393: // Invert and multiply.
394: BigInteger num = numerator.multiply(d);
395: BigInteger den = denominator.multiply(n);
396: BigInteger quotient = num.divide(den);
397:
398: // Multiply quotient by divisor.
399: LispObject product = number(quotient.multiply(n), d);
400:
401: // Subtract to get remainder.
402: LispObject remainder = subtract(product);
403:
404: final LispThread thread = LispThread.currentThread();
405: LispObject[] values = new LispObject[2];
406: values[0] = number(quotient);
407: values[1] = remainder;
408: thread.setValues(values);
409: return values[0];
410: } catch (ArithmeticException e) {
411: if (obj.zerop())
412: throw new ConditionThrowable(new DivisionByZero());
413: throw new ConditionThrowable(new ArithmeticError(e
414: .getMessage()));
415: }
416: }
417:
418: public int hashCode() {
419: return numerator.hashCode() ^ denominator.hashCode();
420: }
421:
422: public String toString() {
423: final LispThread thread = LispThread.currentThread();
424: int base;
425: try {
426: base = Fixnum.getValue(_PRINT_BASE_
427: .symbolValueNoThrow(thread));
428: } catch (Throwable t) {
429: Debug.trace(t);
430: base = 10;
431: }
432: StringBuffer sb = new StringBuffer(numerator.toString(base));
433: sb.append('/');
434: sb.append(denominator.toString(base));
435: String s = sb.toString().toUpperCase();
436: if (_PRINT_RADIX_.symbolValueNoThrow(thread) != NIL) {
437: sb.setLength(0);
438: switch (base) {
439: case 2:
440: sb.append("#b");
441: sb.append(s);
442: break;
443: case 8:
444: sb.append("#o");
445: sb.append(s);
446: break;
447: case 10:
448: sb.append("#10r");
449: sb.append(s);
450: break;
451: case 16:
452: sb.append("#x");
453: sb.append(s);
454: break;
455: default:
456: sb.append('#');
457: sb.append(String.valueOf(base));
458: sb.append('r');
459: sb.append(s);
460: break;
461: }
462: s = sb.toString();
463: }
464: return s;
465: }
466: }
|