001: /*
002: * Fixnum.java
003: *
004: * Copyright (C) 2002-2004 Peter Graves
005: * $Id: Fixnum.java,v 1.95 2004/09/21 18:14:11 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 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: public 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 Object javaInstance(Class c) {
043: String cn = c.getName();
044: if (cn.equals("java.lang.Byte") || cn.equals("byte"))
045: return new Byte(((Integer) javaInstance()).byteValue());
046: if (cn.equals("java.lang.Short") || cn.equals("short"))
047: return new Short(((Integer) javaInstance()).shortValue());
048: if (cn.equals("java.lang.Long") || cn.equals("long"))
049: return new Long(((Integer) javaInstance()).longValue());
050: return javaInstance();
051: }
052:
053: public static Fixnum getInstance(int value) {
054: return new Fixnum(value);
055: }
056:
057: public LispObject typeOf() {
058: if (value == 0 || value == 1)
059: return Symbol.BIT;
060: else
061: return Symbol.FIXNUM;
062: }
063:
064: public LispClass classOf() {
065: return BuiltInClass.FIXNUM;
066: }
067:
068: public LispObject getDescription() {
069: StringBuffer sb = new StringBuffer("The fixnum ");
070: sb.append(value);
071: return new SimpleString(sb);
072: }
073:
074: public LispObject typep(LispObject type) throws ConditionThrowable {
075: if (type == Symbol.FIXNUM)
076: return T;
077: if (type == BuiltInClass.FIXNUM)
078: return T;
079: if (type == Symbol.INTEGER)
080: return T;
081: if (type == BuiltInClass.INTEGER)
082: return T;
083: if (type == Symbol.RATIONAL)
084: return T;
085: if (type == BuiltInClass.RATIONAL)
086: return T;
087: if (type == Symbol.REAL)
088: return T;
089: if (type == BuiltInClass.REAL)
090: return T;
091: if (type == Symbol.NUMBER)
092: return T;
093: if (type == BuiltInClass.NUMBER)
094: return T;
095: if (type == Symbol.SIGNED_BYTE)
096: return T;
097: if (type == Symbol.UNSIGNED_BYTE)
098: return value >= 0 ? T : NIL;
099: if (type == Symbol.BIT)
100: return (value == 0 || value == 1) ? T : NIL;
101: return super .typep(type);
102: }
103:
104: public LispObject NUMBERP() {
105: return T;
106: }
107:
108: public boolean numberp() {
109: return true;
110: }
111:
112: public boolean integerp() {
113: return true;
114: }
115:
116: public boolean rationalp() {
117: return true;
118: }
119:
120: public boolean realp() {
121: return true;
122: }
123:
124: public boolean eql(LispObject obj) {
125: if (this == obj)
126: return true;
127: if (obj instanceof Fixnum) {
128: if (value == ((Fixnum) obj).value)
129: return true;
130: }
131: return false;
132: }
133:
134: public boolean equal(LispObject obj) {
135: if (this == obj)
136: return true;
137: if (obj instanceof Fixnum) {
138: if (value == ((Fixnum) obj).value)
139: return true;
140: }
141: return false;
142: }
143:
144: public boolean equalp(LispObject obj) {
145: if (obj instanceof Fixnum)
146: return value == ((Fixnum) obj).value;
147: if (obj instanceof LispFloat)
148: return (float) value == ((LispFloat) obj).getValue();
149: return false;
150: }
151:
152: public LispObject ABS() {
153: if (value >= 0)
154: return this ;
155: return number(-((long) value));
156: }
157:
158: public LispObject NUMERATOR() {
159: return this ;
160: }
161:
162: public LispObject DENOMINATOR() {
163: return ONE;
164: }
165:
166: public boolean evenp() throws ConditionThrowable {
167: return (value & 0x01) == 0;
168: }
169:
170: public boolean oddp() throws ConditionThrowable {
171: return (value & 0x01) != 0;
172: }
173:
174: public boolean plusp() {
175: return value > 0;
176: }
177:
178: public boolean minusp() {
179: return value < 0;
180: }
181:
182: public boolean zerop() {
183: return value == 0;
184: }
185:
186: public static int getValue(LispObject obj)
187: throws ConditionThrowable {
188: try {
189: return ((Fixnum) obj).value;
190: } catch (ClassCastException e) {
191: signal(new TypeError(obj, Symbol.FIXNUM));
192: // Not reached.
193: return 0;
194: }
195: }
196:
197: public static int getInt(LispObject obj) throws ConditionThrowable {
198: try {
199: return (int) ((Fixnum) obj).value;
200: } catch (ClassCastException e) {
201: signal(new TypeError(obj, Symbol.FIXNUM));
202: // Not reached.
203: return 0;
204: }
205: }
206:
207: public static BigInteger getBigInteger(LispObject obj)
208: throws ConditionThrowable {
209: try {
210: return BigInteger.valueOf(((Fixnum) obj).value);
211: } catch (ClassCastException e) {
212: signal(new TypeError(obj, Symbol.FIXNUM));
213: // Not reached.
214: return null;
215: }
216: }
217:
218: public static float getFloat(LispObject obj)
219: throws ConditionThrowable {
220: try {
221: return (float) ((Fixnum) obj).value;
222: } catch (ClassCastException e) {
223: signal(new TypeError(obj, Symbol.FIXNUM));
224: return 0;
225: }
226: }
227:
228: public final int getValue() {
229: return value;
230: }
231:
232: public final BigInteger getBigInteger() {
233: return BigInteger.valueOf(value);
234: }
235:
236: public final LispObject incr() {
237: if (value < Integer.MAX_VALUE)
238: return new Fixnum(value + 1);
239: return new Bignum((long) value + 1);
240: }
241:
242: public final LispObject decr() {
243: if (value > Integer.MIN_VALUE)
244: return new Fixnum(value - 1);
245: return new Bignum((long) value - 1);
246: }
247:
248: public LispObject add(LispObject obj) throws ConditionThrowable {
249: if (obj instanceof Fixnum)
250: return number((long) value + ((Fixnum) obj).value);
251: if (obj instanceof Bignum)
252: return number(getBigInteger().add(Bignum.getValue(obj)));
253: if (obj instanceof Ratio) {
254: BigInteger numerator = ((Ratio) obj).numerator();
255: BigInteger denominator = ((Ratio) obj).denominator();
256: return number(getBigInteger().multiply(denominator).add(
257: numerator), denominator);
258: }
259: if (obj instanceof LispFloat)
260: return new LispFloat(value + LispFloat.getValue(obj));
261: if (obj instanceof Complex) {
262: Complex c = (Complex) obj;
263: return Complex.getInstance(add(c.getRealPart()), c
264: .getImaginaryPart());
265: }
266: return signal(new TypeError(obj, "number"));
267: }
268:
269: public LispObject subtract(LispObject obj)
270: throws ConditionThrowable {
271: if (obj instanceof Fixnum)
272: return number((long) value - ((Fixnum) obj).value);
273: if (obj instanceof Bignum)
274: return number(getBigInteger()
275: .subtract(Bignum.getValue(obj)));
276: if (obj instanceof Ratio) {
277: BigInteger numerator = ((Ratio) obj).numerator();
278: BigInteger denominator = ((Ratio) obj).denominator();
279: return number(getBigInteger().multiply(denominator)
280: .subtract(numerator), denominator);
281: }
282: if (obj instanceof LispFloat)
283: return new LispFloat(value - LispFloat.getValue(obj));
284: if (obj instanceof Complex) {
285: Complex c = (Complex) obj;
286: return Complex.getInstance(subtract(c.getRealPart()), ZERO
287: .subtract(c.getImaginaryPart()));
288: }
289: return signal(new TypeError(obj, "number"));
290: }
291:
292: public LispObject multiplyBy(LispObject obj)
293: throws ConditionThrowable {
294: if (obj instanceof Fixnum)
295: return number((long) value * ((Fixnum) obj).value);
296: if (obj instanceof Bignum)
297: return number(getBigInteger()
298: .multiply(((Bignum) obj).value));
299: if (obj instanceof Ratio) {
300: BigInteger numerator = ((Ratio) obj).numerator();
301: BigInteger denominator = ((Ratio) obj).denominator();
302: return number(getBigInteger().multiply(numerator),
303: denominator);
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: return Complex.getInstance(multiplyBy(c.getRealPart()),
310: multiplyBy(c.getImaginaryPart()));
311: }
312: return signal(new TypeError(obj, "number"));
313: }
314:
315: public LispObject divideBy(LispObject obj)
316: throws ConditionThrowable {
317: try {
318: if (obj instanceof Fixnum) {
319: final int divisor = ((Fixnum) obj).value;
320: if (value % divisor == 0)
321: return new Fixnum(value / divisor);
322: return number(BigInteger.valueOf(value), BigInteger
323: .valueOf(divisor));
324: }
325: if (obj instanceof Bignum)
326: return number(getBigInteger(), ((Bignum) obj)
327: .getValue());
328: if (obj instanceof Ratio) {
329: BigInteger numerator = ((Ratio) obj).numerator();
330: BigInteger denominator = ((Ratio) obj).denominator();
331: return number(getBigInteger().multiply(denominator),
332: numerator);
333: }
334: if (obj instanceof LispFloat)
335: return new LispFloat(value / LispFloat.getValue(obj));
336: if (obj instanceof Complex) {
337: Complex c = (Complex) obj;
338: LispObject realPart = c.getRealPart();
339: LispObject imagPart = c.getImaginaryPart();
340: LispObject denominator = realPart.multiplyBy(realPart)
341: .add(imagPart.multiplyBy(imagPart));
342: return Complex.getInstance(multiplyBy(realPart)
343: .divideBy(denominator), Fixnum.ZERO
344: .subtract(multiplyBy(imagPart).divideBy(
345: denominator)));
346: }
347: return signal(new TypeError(obj, "number"));
348: } catch (ArithmeticException e) {
349: if (obj.zerop())
350: return signal(new DivisionByZero());
351: return signal(new ArithmeticError(e.getMessage()));
352: }
353: }
354:
355: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
356: if (obj instanceof Fixnum)
357: return value == ((Fixnum) obj).value;
358: if (obj instanceof LispFloat)
359: return (float) value == LispFloat.getValue(obj);
360: if (obj instanceof Complex)
361: return obj.isEqualTo(this );
362: if (obj.numberp())
363: return false;
364: signal(new TypeError(obj, "number"));
365: // Not reached.
366: return false;
367: }
368:
369: public boolean isNotEqualTo(LispObject obj)
370: throws ConditionThrowable {
371: if (obj instanceof Fixnum)
372: return value != ((Fixnum) obj).value;
373: // obj is not a fixnum.
374: if (obj instanceof LispFloat)
375: return (float) value != LispFloat.getValue(obj);
376: if (obj instanceof Complex)
377: return obj.isNotEqualTo(this );
378: if (obj.numberp())
379: return true;
380: signal(new TypeError(obj, "number"));
381: // Not reached.
382: return false;
383: }
384:
385: public boolean isLessThan(LispObject obj) 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 isLessThan(((LispFloat) obj).rational());
397: signal(new TypeError(obj, "number"));
398: // Not reached.
399: return false;
400: }
401:
402: public boolean isGreaterThan(LispObject obj)
403: throws ConditionThrowable {
404: if (obj instanceof Fixnum)
405: return value > ((Fixnum) obj).value;
406: if (obj instanceof Bignum)
407: return getBigInteger().compareTo(Bignum.getValue(obj)) > 0;
408: if (obj instanceof Ratio) {
409: BigInteger n = getBigInteger().multiply(
410: ((Ratio) obj).denominator());
411: return n.compareTo(((Ratio) obj).numerator()) > 0;
412: }
413: if (obj instanceof LispFloat)
414: return isGreaterThan(((LispFloat) obj).rational());
415: signal(new TypeError(obj, "number"));
416: // Not reached.
417: return false;
418: }
419:
420: public boolean isLessThanOrEqualTo(LispObject obj)
421: throws ConditionThrowable {
422: if (obj instanceof Fixnum)
423: return value <= ((Fixnum) obj).value;
424: if (obj instanceof Bignum)
425: return getBigInteger().compareTo(Bignum.getValue(obj)) <= 0;
426: if (obj instanceof Ratio) {
427: BigInteger n = getBigInteger().multiply(
428: ((Ratio) obj).denominator());
429: return n.compareTo(((Ratio) obj).numerator()) <= 0;
430: }
431: if (obj instanceof LispFloat)
432: return isLessThanOrEqualTo(((LispFloat) obj).rational());
433: signal(new TypeError(obj, "number"));
434: // Not reached.
435: return false;
436: }
437:
438: public boolean isGreaterThanOrEqualTo(LispObject obj)
439: throws ConditionThrowable {
440: if (obj instanceof Fixnum)
441: return value >= ((Fixnum) obj).value;
442: if (obj instanceof Bignum)
443: return getBigInteger().compareTo(Bignum.getValue(obj)) >= 0;
444: if (obj instanceof Ratio) {
445: BigInteger n = getBigInteger().multiply(
446: ((Ratio) obj).denominator());
447: return n.compareTo(((Ratio) obj).numerator()) >= 0;
448: }
449: if (obj instanceof LispFloat)
450: return isGreaterThanOrEqualTo(((LispFloat) obj).rational());
451: signal(new TypeError(obj, "number"));
452: // Not reached.
453: return false;
454: }
455:
456: public LispObject truncate(LispObject obj)
457: throws ConditionThrowable {
458: final LispThread thread = LispThread.currentThread();
459: final LispObject value1, value2;
460: try {
461: if (obj instanceof Fixnum) {
462: long divisor = ((Fixnum) obj).value;
463: long quotient = value / divisor;
464: long remainder = value % divisor;
465: value1 = number(quotient);
466: value2 = remainder == 0 ? Fixnum.ZERO
467: : number(remainder);
468: } else if (obj instanceof Bignum) {
469: BigInteger value = getBigInteger();
470: BigInteger divisor = ((Bignum) obj).getValue();
471: BigInteger[] results = value
472: .divideAndRemainder(divisor);
473: BigInteger quotient = results[0];
474: BigInteger remainder = results[1];
475: value1 = number(quotient);
476: value2 = (remainder.signum() == 0) ? Fixnum.ZERO
477: : number(remainder);
478: } else if (obj instanceof Ratio) {
479: Ratio divisor = (Ratio) obj;
480: LispObject quotient = multiplyBy(divisor.DENOMINATOR())
481: .truncate(divisor.NUMERATOR());
482: LispObject remainder = subtract(quotient
483: .multiplyBy(divisor));
484: value1 = quotient;
485: value2 = remainder;
486: } else
487: return signal(new LispError(
488: "Fixnum.truncate(): not implemented: "
489: + obj.typeOf()));
490: } catch (ArithmeticException e) {
491: if (obj.zerop())
492: return signal(new DivisionByZero());
493: else
494: return signal(new ArithmeticError(e.getMessage()));
495: }
496: return thread.setValues(value1, value2);
497: }
498:
499: public LispObject MOD(LispObject divisor) throws ConditionThrowable {
500: if (divisor instanceof Fixnum) {
501: final int d = ((Fixnum) divisor).value;
502: final int r;
503: try {
504: r = value % d;
505: } catch (ArithmeticException e) {
506: return signal(new ArithmeticError("Division by zero."));
507: }
508: if (r == 0)
509: return Fixnum.ZERO;
510: if (d < 0) {
511: if (value > 0)
512: return new Fixnum(r + d);
513: } else {
514: if (value < 0)
515: return new Fixnum(r + d);
516: }
517: return new Fixnum(r);
518: }
519: return super .MOD(divisor);
520: }
521:
522: public LispObject ash(LispObject obj) throws ConditionThrowable {
523: if (obj instanceof Fixnum) {
524: if (value == 0)
525: return this ;
526: int shift = ((Fixnum) obj).value;
527: if (shift == 0)
528: return this ;
529: long n = value;
530: if (shift <= -32) {
531: // Right shift.
532: return n >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
533: }
534: if (shift < 0)
535: return new Fixnum((int) (n >> -shift));
536: if (shift <= 32)
537: return number(n << shift);
538: // BigInteger.shiftLeft() succumbs to a stack overflow if shift
539: // is Integer.MIN_VALUE, so...
540: if (shift == Integer.MIN_VALUE)
541: return n >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
542: return number(BigInteger.valueOf(value).shiftLeft(shift));
543: }
544: if (obj instanceof Bignum) {
545: if (value == 0)
546: return this ;
547: BigInteger n = BigInteger.valueOf(value);
548: BigInteger shift = ((Bignum) obj).value;
549: if (shift.signum() > 0)
550: return signal(new LispError(
551: "Can't represent result of left shift."));
552: if (shift.signum() < 0)
553: return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
554: Debug.bug(); // Shouldn't happen.
555: }
556: return signal(new TypeError(obj, Symbol.INTEGER));
557: }
558:
559: public int hashCode() {
560: return value;
561: }
562:
563: public String writeToString() throws ConditionThrowable {
564: final LispThread thread = LispThread.currentThread();
565: int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread));
566: String s = Integer.toString(value, base).toUpperCase();
567: if (_PRINT_RADIX_.symbolValue(thread) != NIL) {
568: StringBuffer sb = new StringBuffer();
569: switch (base) {
570: case 2:
571: sb.append("#b");
572: sb.append(s);
573: break;
574: case 8:
575: sb.append("#o");
576: sb.append(s);
577: break;
578: case 10:
579: sb.append(s);
580: sb.append('.');
581: break;
582: case 16:
583: sb.append("#x");
584: sb.append(s);
585: break;
586: default:
587: sb.append('#');
588: sb.append(String.valueOf(base));
589: sb.append('r');
590: sb.append(s);
591: break;
592: }
593: s = sb.toString();
594: }
595: return s;
596: }
597: }
|