001: /*
002: * Fixnum.java
003: *
004: * Copyright (C) 2002-2003 Peter Graves
005: * $Id: Fixnum.java,v 1.7 2003/11/15 11:03:32 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 Fixnum extends LispObject {
027: public static final Fixnum ZERO = new Fixnum(0);
028: public static final Fixnum ONE = new Fixnum(1);
029: public static final Fixnum TWO = new Fixnum(2);
030: public static final Fixnum MINUS_ONE = new Fixnum(-1);
031:
032: private final int value;
033:
034: public Fixnum(int value) {
035: this .value = value;
036: }
037:
038: public Object javaInstance() {
039: return new Integer(value);
040: }
041:
042: public static Fixnum getInstance(int value) {
043: return new Fixnum(value);
044: }
045:
046: public LispObject typeOf() {
047: return Symbol.FIXNUM;
048: }
049:
050: public LispClass classOf() {
051: return BuiltInClass.FIXNUM;
052: }
053:
054: public LispObject typep(LispObject type) throws ConditionThrowable {
055: if (type == Symbol.FIXNUM)
056: return T;
057: if (type == BuiltInClass.FIXNUM)
058: return T;
059: if (type == Symbol.INTEGER)
060: return T;
061: if (type == BuiltInClass.INTEGER)
062: return T;
063: if (type == Symbol.RATIONAL)
064: return T;
065: if (type == BuiltInClass.RATIONAL)
066: return T;
067: if (type == Symbol.REAL)
068: return T;
069: if (type == BuiltInClass.REAL)
070: return T;
071: if (type == Symbol.NUMBER)
072: return T;
073: if (type == BuiltInClass.NUMBER)
074: return T;
075: if (type == Symbol.UNSIGNED_BYTE)
076: return value >= 0 ? T : NIL;
077: if (type == Symbol.BIT)
078: return (value == 0 || value == 1) ? T : NIL;
079: return super .typep(type);
080: }
081:
082: public LispObject NUMBERP() {
083: return T;
084: }
085:
086: public boolean numberp() {
087: return true;
088: }
089:
090: public boolean integerp() {
091: return true;
092: }
093:
094: public boolean rationalp() {
095: return true;
096: }
097:
098: public boolean realp() {
099: return true;
100: }
101:
102: public boolean eql(LispObject obj) {
103: if (this == obj)
104: return true;
105: if (obj instanceof Fixnum) {
106: if (value == ((Fixnum) obj).value)
107: return true;
108: }
109: return false;
110: }
111:
112: public boolean equal(LispObject obj) {
113: if (this == obj)
114: return true;
115: if (obj instanceof Fixnum) {
116: if (value == ((Fixnum) obj).value)
117: return true;
118: }
119: return false;
120: }
121:
122: public boolean equalp(LispObject obj) {
123: if (obj instanceof Fixnum)
124: return value == ((Fixnum) obj).value;
125: if (obj instanceof LispFloat)
126: return (float) value == ((LispFloat) obj).getValue();
127: return false;
128: }
129:
130: public LispObject ABS() {
131: if (value >= 0)
132: return this ;
133: return number(-((long) value));
134: }
135:
136: public LispObject NUMERATOR() {
137: return this ;
138: }
139:
140: public LispObject DENOMINATOR() {
141: return ONE;
142: }
143:
144: public boolean evenp() throws ConditionThrowable {
145: return (value & 0x01) == 0;
146: }
147:
148: public boolean oddp() throws ConditionThrowable {
149: return (value & 0x01) != 0;
150: }
151:
152: public boolean plusp() {
153: return value > 0;
154: }
155:
156: public boolean minusp() {
157: return value < 0;
158: }
159:
160: public boolean zerop() {
161: return value == 0;
162: }
163:
164: public static int getValue(LispObject obj)
165: throws ConditionThrowable {
166: try {
167: return ((Fixnum) obj).value;
168: } catch (ClassCastException e) {
169: throw new ConditionThrowable(new TypeError(obj, "fixnum"));
170: }
171: }
172:
173: public static int getInt(LispObject obj) throws ConditionThrowable {
174: try {
175: return (int) ((Fixnum) obj).value;
176: } catch (ClassCastException e) {
177: throw new ConditionThrowable(new TypeError(obj, "fixnum"));
178: }
179: }
180:
181: public static BigInteger getBigInteger(LispObject obj)
182: throws ConditionThrowable {
183: try {
184: return BigInteger.valueOf(((Fixnum) obj).value);
185: } catch (ClassCastException e) {
186: throw new ConditionThrowable(new TypeError(obj, "fixnum"));
187: }
188: }
189:
190: public static float getFloat(LispObject obj)
191: throws ConditionThrowable {
192: try {
193: return (float) ((Fixnum) obj).value;
194: } catch (ClassCastException e) {
195: throw new ConditionThrowable(new TypeError(obj, "fixnum"));
196: }
197: }
198:
199: public final int getValue() {
200: return value;
201: }
202:
203: public final BigInteger getBigInteger() {
204: return BigInteger.valueOf(value);
205: }
206:
207: public final LispObject incr() {
208: if (value < Integer.MAX_VALUE)
209: return new Fixnum(value + 1);
210: return new Bignum((long) value + 1);
211: }
212:
213: public final LispObject decr() {
214: if (value > Integer.MIN_VALUE)
215: return new Fixnum(value - 1);
216: return new Bignum((long) value - 1);
217: }
218:
219: public LispObject add(LispObject obj) throws ConditionThrowable {
220: if (obj instanceof Fixnum)
221: return number((long) value + ((Fixnum) obj).value);
222: if (obj instanceof Bignum)
223: return number(getBigInteger().add(Bignum.getValue(obj)));
224: if (obj instanceof Ratio) {
225: BigInteger numerator = ((Ratio) obj).numerator();
226: BigInteger denominator = ((Ratio) obj).denominator();
227: return number(getBigInteger().multiply(denominator).add(
228: numerator), denominator);
229: }
230: if (obj instanceof LispFloat)
231: return new LispFloat(value + LispFloat.getValue(obj));
232: if (obj instanceof Complex) {
233: Complex c = (Complex) obj;
234: return Complex.getInstance(add(c.getRealPart()), c
235: .getImaginaryPart());
236: }
237: throw new ConditionThrowable(new TypeError(obj, "number"));
238: }
239:
240: public LispObject subtract(LispObject obj)
241: throws ConditionThrowable {
242: if (obj instanceof Fixnum)
243: return number((long) value - ((Fixnum) obj).value);
244: if (obj instanceof Bignum)
245: return number(getBigInteger()
246: .subtract(Bignum.getValue(obj)));
247: if (obj instanceof Ratio) {
248: BigInteger numerator = ((Ratio) obj).numerator();
249: BigInteger denominator = ((Ratio) obj).denominator();
250: return number(getBigInteger().multiply(denominator)
251: .subtract(numerator), denominator);
252: }
253: if (obj instanceof LispFloat)
254: return new LispFloat(value - LispFloat.getValue(obj));
255: if (obj instanceof Complex) {
256: Complex c = (Complex) obj;
257: return Complex.getInstance(subtract(c.getRealPart()), ZERO
258: .subtract(c.getImaginaryPart()));
259: }
260: throw new ConditionThrowable(new TypeError(obj, "number"));
261: }
262:
263: public LispObject multiplyBy(LispObject obj)
264: throws ConditionThrowable {
265: if (obj instanceof Fixnum)
266: return number((long) value * ((Fixnum) obj).value);
267: if (obj instanceof Bignum)
268: return number(getBigInteger()
269: .multiply(Bignum.getValue(obj)));
270: if (obj instanceof Ratio) {
271: BigInteger numerator = ((Ratio) obj).numerator();
272: BigInteger denominator = ((Ratio) obj).denominator();
273: return number(getBigInteger().multiply(numerator),
274: denominator);
275: }
276: if (obj instanceof LispFloat)
277: return new LispFloat(value * LispFloat.getValue(obj));
278: if (obj instanceof Complex) {
279: Complex c = (Complex) obj;
280: return Complex.getInstance(multiplyBy(c.getRealPart()),
281: multiplyBy(c.getImaginaryPart()));
282: }
283: throw new ConditionThrowable(new TypeError(obj, "number"));
284: }
285:
286: public LispObject divideBy(LispObject obj)
287: throws ConditionThrowable {
288: try {
289: if (obj instanceof Fixnum) {
290: final int divisor = ((Fixnum) obj).value;
291: if (value % divisor == 0)
292: return new Fixnum(value / divisor);
293: return number(BigInteger.valueOf(value), BigInteger
294: .valueOf(divisor));
295: }
296: if (obj instanceof Bignum)
297: return number(getBigInteger(), ((Bignum) obj)
298: .getValue());
299: if (obj instanceof Ratio) {
300: BigInteger numerator = ((Ratio) obj).numerator();
301: BigInteger denominator = ((Ratio) obj).denominator();
302: return number(getBigInteger().multiply(denominator),
303: numerator);
304: }
305: if (obj instanceof LispFloat)
306: return new LispFloat(value / LispFloat.getValue(obj));
307: if (obj instanceof Complex) {
308: Complex c = (Complex) obj;
309: LispObject realPart = c.getRealPart();
310: LispObject imagPart = c.getImaginaryPart();
311: LispObject denominator = realPart.multiplyBy(realPart)
312: .add(imagPart.multiplyBy(imagPart));
313: return Complex.getInstance(multiplyBy(realPart)
314: .divideBy(denominator), Fixnum.ZERO
315: .subtract(multiplyBy(imagPart).divideBy(
316: denominator)));
317: }
318: throw new ConditionThrowable(new TypeError(obj, "number"));
319: } catch (ArithmeticException e) {
320: if (obj.zerop())
321: throw new ConditionThrowable(new DivisionByZero());
322: throw new ConditionThrowable(new ArithmeticError(e
323: .getMessage()));
324: }
325: }
326:
327: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
328: if (obj instanceof Fixnum)
329: return value == ((Fixnum) obj).value;
330: if (obj instanceof LispFloat)
331: return (float) value == LispFloat.getValue(obj);
332: if (obj instanceof Complex)
333: return obj.isEqualTo(this );
334: if (obj.numberp())
335: return false;
336: throw new ConditionThrowable(new TypeError(obj, "number"));
337: }
338:
339: public boolean isNotEqualTo(LispObject obj)
340: throws ConditionThrowable {
341: if (obj instanceof Fixnum)
342: return value != ((Fixnum) obj).value;
343: // obj is not a fixnum.
344: if (obj instanceof LispFloat)
345: return (float) value != LispFloat.getValue(obj);
346: if (obj instanceof Complex)
347: return obj.isNotEqualTo(this );
348: if (obj.numberp())
349: return true;
350: throw new ConditionThrowable(new TypeError(obj, "number"));
351: }
352:
353: public boolean isLessThan(LispObject obj) throws ConditionThrowable {
354: if (obj instanceof Fixnum)
355: return value < ((Fixnum) obj).value;
356: if (obj instanceof Bignum)
357: return getBigInteger().compareTo(Bignum.getValue(obj)) < 0;
358: if (obj instanceof Ratio) {
359: BigInteger n = getBigInteger().multiply(
360: ((Ratio) obj).denominator());
361: return n.compareTo(((Ratio) obj).numerator()) < 0;
362: }
363: if (obj instanceof LispFloat)
364: return (float) value < LispFloat.getValue(obj);
365: throw new ConditionThrowable(new TypeError(obj, "number"));
366: }
367:
368: public boolean isGreaterThan(LispObject obj)
369: throws ConditionThrowable {
370: if (obj instanceof Fixnum)
371: return value > ((Fixnum) obj).value;
372: if (obj instanceof Bignum)
373: return getBigInteger().compareTo(Bignum.getValue(obj)) > 0;
374: if (obj instanceof Ratio) {
375: BigInteger n = getBigInteger().multiply(
376: ((Ratio) obj).denominator());
377: return n.compareTo(((Ratio) obj).numerator()) > 0;
378: }
379: if (obj instanceof LispFloat)
380: return (float) value > LispFloat.getValue(obj);
381: throw new ConditionThrowable(new TypeError(obj, "number"));
382: }
383:
384: public boolean isLessThanOrEqualTo(LispObject obj)
385: throws ConditionThrowable {
386: if (obj instanceof Fixnum)
387: return value <= ((Fixnum) obj).value;
388: if (obj instanceof Bignum)
389: return getBigInteger().compareTo(Bignum.getValue(obj)) <= 0;
390: if (obj instanceof Ratio) {
391: BigInteger n = getBigInteger().multiply(
392: ((Ratio) obj).denominator());
393: return n.compareTo(((Ratio) obj).numerator()) <= 0;
394: }
395: if (obj instanceof LispFloat)
396: return (float) value <= LispFloat.getValue(obj);
397: throw new ConditionThrowable(new TypeError(obj, "number"));
398: }
399:
400: public boolean isGreaterThanOrEqualTo(LispObject obj)
401: throws ConditionThrowable {
402: if (obj instanceof Fixnum)
403: return value >= ((Fixnum) obj).value;
404: if (obj instanceof Bignum)
405: return getBigInteger().compareTo(Bignum.getValue(obj)) >= 0;
406: if (obj instanceof Ratio) {
407: BigInteger n = getBigInteger().multiply(
408: ((Ratio) obj).denominator());
409: return n.compareTo(((Ratio) obj).numerator()) >= 0;
410: }
411: if (obj instanceof LispFloat)
412: return (float) value >= LispFloat.getValue(obj);
413: throw new ConditionThrowable(new TypeError(obj, "number"));
414: }
415:
416: public LispObject truncate(LispObject obj)
417: throws ConditionThrowable {
418: final LispThread thread = LispThread.currentThread();
419: LispObject[] values = new LispObject[2];
420: try {
421: if (obj instanceof Fixnum) {
422: long divisor = ((Fixnum) obj).value;
423: long quotient = value / divisor;
424: long remainder = value % divisor;
425: values[0] = number(quotient);
426: values[1] = remainder == 0 ? Fixnum.ZERO
427: : number(remainder);
428: } else if (obj instanceof Bignum) {
429: BigInteger value = getBigInteger();
430: BigInteger divisor = ((Bignum) obj).getValue();
431: BigInteger[] results = value
432: .divideAndRemainder(divisor);
433: BigInteger quotient = results[0];
434: BigInteger remainder = results[1];
435: values[0] = number(quotient);
436: values[1] = (remainder.signum() == 0) ? Fixnum.ZERO
437: : number(remainder);
438: } else if (obj instanceof Ratio) {
439: Ratio divisor = (Ratio) obj;
440: LispObject quotient = multiplyBy(divisor.DENOMINATOR())
441: .truncate(divisor.NUMERATOR());
442: LispObject remainder = subtract(quotient
443: .multiplyBy(divisor));
444: values[0] = quotient;
445: values[1] = remainder;
446: } else
447: throw new ConditionThrowable(new LispError(
448: "Fixnum.truncate(): not implemented: "
449: + obj.typeOf()));
450: } catch (ArithmeticException e) {
451: if (obj.zerop())
452: throw new ConditionThrowable(new DivisionByZero());
453: throw new ConditionThrowable(new ArithmeticError(e
454: .getMessage()));
455: }
456: thread.setValues(values);
457: return values[0];
458: }
459:
460: public int hashCode() {
461: return value;
462: }
463:
464: public String toString() {
465: final LispThread thread = LispThread.currentThread();
466: int base;
467: try {
468: base = Fixnum.getValue(_PRINT_BASE_
469: .symbolValueNoThrow(thread));
470: } catch (Throwable t) {
471: Debug.trace(t);
472: base = 10;
473: }
474: String s = Integer.toString(value, base).toUpperCase();
475: if (_PRINT_RADIX_.symbolValueNoThrow(thread) != NIL) {
476: StringBuffer sb = new StringBuffer();
477: switch (base) {
478: case 2:
479: sb.append("#b");
480: sb.append(s);
481: break;
482: case 8:
483: sb.append("#o");
484: sb.append(s);
485: break;
486: case 10:
487: sb.append(s);
488: sb.append('.');
489: break;
490: case 16:
491: sb.append("#x");
492: sb.append(s);
493: break;
494: default:
495: sb.append('#');
496: sb.append(String.valueOf(base));
497: sb.append('r');
498: sb.append(s);
499: break;
500: }
501: s = sb.toString();
502: }
503: return s;
504: }
505: }
|