KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > lisp > Fixnum


1 /*
2  * Fixnum.java
3  *
4  * Copyright (C) 2002-2004 Peter Graves
5  * $Id: Fixnum.java,v 1.95 2004/09/21 18:14:11 piso Exp $
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
22 package org.armedbear.lisp;
23
24 import java.math.BigInteger JavaDoc;
25
26 public final class Fixnum extends LispObject
27 {
28     public static final Fixnum ZERO = new Fixnum(0);
29     public static final Fixnum ONE = new Fixnum(1);
30     public static final Fixnum TWO = new Fixnum(2);
31     public static final Fixnum MINUS_ONE = new Fixnum(-1);
32
33     public final int value;
34
35     public Fixnum(int value)
36     {
37         this.value = value;
38     }
39
40     public Object JavaDoc javaInstance()
41     {
42         return new Integer JavaDoc(value);
43     }
44
45     public Object JavaDoc javaInstance(Class JavaDoc c)
46     {
47         String JavaDoc cn = c.getName();
48         if (cn.equals("java.lang.Byte") || cn.equals("byte"))
49             return new Byte JavaDoc(((Integer JavaDoc)javaInstance()).byteValue());
50         if (cn.equals("java.lang.Short") || cn.equals("short"))
51             return new Short JavaDoc(((Integer JavaDoc)javaInstance()).shortValue());
52         if (cn.equals("java.lang.Long") || cn.equals("long"))
53             return new Long JavaDoc(((Integer JavaDoc)javaInstance()).longValue());
54         return javaInstance();
55     }
56
57     public static Fixnum getInstance(int value)
58     {
59         return new Fixnum(value);
60     }
61
62     public LispObject typeOf()
63     {
64         if (value == 0 || value == 1)
65             return Symbol.BIT;
66         else
67             return Symbol.FIXNUM;
68     }
69
70     public LispClass classOf()
71     {
72         return BuiltInClass.FIXNUM;
73     }
74
75     public LispObject getDescription()
76     {
77         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("The fixnum ");
78         sb.append(value);
79         return new SimpleString(sb);
80     }
81
82     public LispObject typep(LispObject type) throws ConditionThrowable
83     {
84         if (type == Symbol.FIXNUM)
85             return T;
86         if (type == BuiltInClass.FIXNUM)
87             return T;
88         if (type == Symbol.INTEGER)
89             return T;
90         if (type == BuiltInClass.INTEGER)
91             return T;
92         if (type == Symbol.RATIONAL)
93             return T;
94         if (type == BuiltInClass.RATIONAL)
95             return T;
96         if (type == Symbol.REAL)
97             return T;
98         if (type == BuiltInClass.REAL)
99             return T;
100         if (type == Symbol.NUMBER)
101             return T;
102         if (type == BuiltInClass.NUMBER)
103             return T;
104         if (type == Symbol.SIGNED_BYTE)
105             return T;
106         if (type == Symbol.UNSIGNED_BYTE)
107             return value >= 0 ? T : NIL;
108         if (type == Symbol.BIT)
109             return (value == 0 || value == 1) ? T : NIL;
110         return super.typep(type);
111     }
112
113     public LispObject NUMBERP()
114     {
115         return T;
116     }
117
118     public boolean numberp()
119     {
120         return true;
121     }
122
123     public boolean integerp()
124     {
125         return true;
126     }
127
128     public boolean rationalp()
129     {
130         return true;
131     }
132
133     public boolean realp()
134     {
135         return true;
136     }
137
138     public boolean eql(LispObject obj)
139     {
140         if (this == obj)
141             return true;
142         if (obj instanceof Fixnum) {
143             if (value == ((Fixnum)obj).value)
144                 return true;
145         }
146         return false;
147     }
148
149     public boolean equal(LispObject obj)
150     {
151         if (this == obj)
152             return true;
153         if (obj instanceof Fixnum) {
154             if (value == ((Fixnum)obj).value)
155                 return true;
156         }
157         return false;
158     }
159
160     public boolean equalp(LispObject obj)
161     {
162         if (obj instanceof Fixnum)
163             return value == ((Fixnum)obj).value;
164         if (obj instanceof LispFloat)
165             return (float) value == ((LispFloat)obj).getValue();
166         return false;
167     }
168
169     public LispObject ABS()
170     {
171         if (value >= 0)
172             return this;
173         return number(-((long)value));
174     }
175
176     public LispObject NUMERATOR()
177     {
178         return this;
179     }
180
181     public LispObject DENOMINATOR()
182     {
183         return ONE;
184     }
185
186     public boolean evenp() throws ConditionThrowable
187     {
188         return (value & 0x01) == 0;
189     }
190
191     public boolean oddp() throws ConditionThrowable
192     {
193         return (value & 0x01) != 0;
194     }
195
196     public boolean plusp()
197     {
198         return value > 0;
199     }
200
201     public boolean minusp()
202     {
203         return value < 0;
204     }
205
206     public boolean zerop()
207     {
208         return value == 0;
209     }
210
211     public static int getValue(LispObject obj) throws ConditionThrowable
212     {
213         try {
214             return ((Fixnum)obj).value;
215         }
216         catch (ClassCastException JavaDoc e) {
217             signal(new TypeError(obj, Symbol.FIXNUM));
218             // Not reached.
219
return 0;
220         }
221     }
222
223     public static int getInt(LispObject obj) throws ConditionThrowable
224     {
225         try {
226             return (int) ((Fixnum)obj).value;
227         }
228         catch (ClassCastException JavaDoc e) {
229             signal(new TypeError(obj, Symbol.FIXNUM));
230             // Not reached.
231
return 0;
232         }
233     }
234
235     public static BigInteger JavaDoc getBigInteger(LispObject obj) throws ConditionThrowable
236     {
237         try {
238             return BigInteger.valueOf(((Fixnum)obj).value);
239         }
240         catch (ClassCastException JavaDoc e) {
241             signal(new TypeError(obj, Symbol.FIXNUM));
242             // Not reached.
243
return null;
244         }
245     }
246
247     public static float getFloat(LispObject obj) throws ConditionThrowable
248     {
249         try {
250             return (float) ((Fixnum)obj).value;
251         }
252         catch (ClassCastException JavaDoc e) {
253             signal(new TypeError(obj, Symbol.FIXNUM));
254             return 0;
255         }
256     }
257
258     public final int getValue()
259     {
260         return value;
261     }
262
263     public final BigInteger JavaDoc getBigInteger()
264     {
265         return BigInteger.valueOf(value);
266     }
267
268     public final LispObject incr()
269     {
270         if (value < Integer.MAX_VALUE)
271             return new Fixnum(value + 1);
272         return new Bignum((long) value + 1);
273     }
274
275     public final LispObject decr()
276     {
277         if (value > Integer.MIN_VALUE)
278             return new Fixnum(value - 1);
279         return new Bignum((long) value - 1);
280     }
281
282     public LispObject add(LispObject obj) throws ConditionThrowable
283     {
284         if (obj instanceof Fixnum)
285             return number((long) value + ((Fixnum)obj).value);
286         if (obj instanceof Bignum)
287             return number(getBigInteger().add(Bignum.getValue(obj)));
288         if (obj instanceof Ratio) {
289             BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
290             BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
291             return number(
292                 getBigInteger().multiply(denominator).add(numerator),
293                 denominator);
294         }
295         if (obj instanceof LispFloat)
296             return new LispFloat(value + LispFloat.getValue(obj));
297         if (obj instanceof Complex) {
298             Complex c = (Complex) obj;
299             return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
300         }
301         return signal(new TypeError(obj, "number"));
302     }
303
304     public LispObject subtract(LispObject obj) throws ConditionThrowable
305     {
306         if (obj instanceof Fixnum)
307             return number((long) value - ((Fixnum)obj).value);
308         if (obj instanceof Bignum)
309             return number(getBigInteger().subtract(Bignum.getValue(obj)));
310         if (obj instanceof Ratio) {
311             BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
312             BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
313             return number(
314                 getBigInteger().multiply(denominator).subtract(numerator),
315                 denominator);
316         }
317         if (obj instanceof LispFloat)
318             return new LispFloat(value - LispFloat.getValue(obj));
319         if (obj instanceof Complex) {
320             Complex c = (Complex) obj;
321             return Complex.getInstance(subtract(c.getRealPart()),
322                                        ZERO.subtract(c.getImaginaryPart()));
323         }
324         return signal(new TypeError(obj, "number"));
325     }
326
327     public LispObject multiplyBy(LispObject obj) throws ConditionThrowable
328     {
329         if (obj instanceof Fixnum)
330             return number((long) value * ((Fixnum)obj).value);
331         if (obj instanceof Bignum)
332             return number(getBigInteger().multiply(((Bignum)obj).value));
333         if (obj instanceof Ratio) {
334             BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
335             BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
336             return number(
337                 getBigInteger().multiply(numerator),
338                 denominator);
339         }
340         if (obj instanceof LispFloat)
341             return new LispFloat(value * LispFloat.getValue(obj));
342         if (obj instanceof Complex) {
343             Complex c = (Complex) obj;
344             return Complex.getInstance(multiplyBy(c.getRealPart()),
345                                        multiplyBy(c.getImaginaryPart()));
346         }
347         return signal(new TypeError(obj, "number"));
348     }
349
350     public LispObject divideBy(LispObject obj) throws ConditionThrowable
351     {
352         try {
353             if (obj instanceof Fixnum) {
354                 final int divisor = ((Fixnum)obj).value;
355                 if (value % divisor == 0)
356                     return new Fixnum(value / divisor);
357                 return number(BigInteger.valueOf(value),
358                               BigInteger.valueOf(divisor));
359             }
360             if (obj instanceof Bignum)
361                 return number(getBigInteger(), ((Bignum)obj).getValue());
362             if (obj instanceof Ratio) {
363                 BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
364                 BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
365                 return number(getBigInteger().multiply(denominator),
366                               numerator);
367             }
368             if (obj instanceof LispFloat)
369                 return new LispFloat(value / LispFloat.getValue(obj));
370             if (obj instanceof Complex) {
371                 Complex c = (Complex) obj;
372                 LispObject realPart = c.getRealPart();
373                 LispObject imagPart = c.getImaginaryPart();
374                 LispObject denominator =
375                     realPart.multiplyBy(realPart).add(imagPart.multiplyBy(imagPart));
376                 return Complex.getInstance(multiplyBy(realPart).divideBy(denominator),
377                                            Fixnum.ZERO.subtract(multiplyBy(imagPart).divideBy(denominator)));
378             }
379             return signal(new TypeError(obj, "number"));
380         }
381         catch (ArithmeticException JavaDoc e) {
382             if (obj.zerop())
383                 return signal(new DivisionByZero());
384             return signal(new ArithmeticError(e.getMessage()));
385         }
386     }
387
388     public boolean isEqualTo(LispObject obj) throws ConditionThrowable
389     {
390         if (obj instanceof Fixnum)
391             return value == ((Fixnum)obj).value;
392         if (obj instanceof LispFloat)
393             return (float) value == LispFloat.getValue(obj);
394         if (obj instanceof Complex)
395             return obj.isEqualTo(this);
396         if (obj.numberp())
397             return false;
398         signal(new TypeError(obj, "number"));
399         // Not reached.
400
return false;
401     }
402
403     public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable
404     {
405         if (obj instanceof Fixnum)
406             return value != ((Fixnum)obj).value;
407             // obj is not a fixnum.
408
if (obj instanceof LispFloat)
409             return (float) value != LispFloat.getValue(obj);
410         if (obj instanceof Complex)
411             return obj.isNotEqualTo(this);
412         if (obj.numberp())
413             return true;
414         signal(new TypeError(obj, "number"));
415         // Not reached.
416
return false;
417     }
418
419     public boolean isLessThan(LispObject obj) throws ConditionThrowable
420     {
421         if (obj instanceof Fixnum)
422             return value < ((Fixnum)obj).value;
423         if (obj instanceof Bignum)
424             return getBigInteger().compareTo(Bignum.getValue(obj)) < 0;
425         if (obj instanceof Ratio) {
426             BigInteger JavaDoc n =
427                 getBigInteger().multiply(((Ratio)obj).denominator());
428             return n.compareTo(((Ratio)obj).numerator()) < 0;
429         }
430         if (obj instanceof LispFloat)
431             return isLessThan(((LispFloat)obj).rational());
432         signal(new TypeError(obj, "number"));
433         // Not reached.
434
return false;
435     }
436
437     public boolean isGreaterThan(LispObject obj) throws ConditionThrowable
438     {
439         if (obj instanceof Fixnum)
440             return value > ((Fixnum)obj).value;
441         if (obj instanceof Bignum)
442             return getBigInteger().compareTo(Bignum.getValue(obj)) > 0;
443         if (obj instanceof Ratio) {
444             BigInteger JavaDoc n =
445                 getBigInteger().multiply(((Ratio)obj).denominator());
446             return n.compareTo(((Ratio)obj).numerator()) > 0;
447         }
448         if (obj instanceof LispFloat)
449             return isGreaterThan(((LispFloat)obj).rational());
450         signal(new TypeError(obj, "number"));
451         // Not reached.
452
return false;
453     }
454
455     public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable
456     {
457         if (obj instanceof Fixnum)
458             return value <= ((Fixnum)obj).value;
459         if (obj instanceof Bignum)
460             return getBigInteger().compareTo(Bignum.getValue(obj)) <= 0;
461         if (obj instanceof Ratio) {
462             BigInteger JavaDoc n =
463                 getBigInteger().multiply(((Ratio)obj).denominator());
464             return n.compareTo(((Ratio)obj).numerator()) <= 0;
465         }
466         if (obj instanceof LispFloat)
467             return isLessThanOrEqualTo(((LispFloat)obj).rational());
468         signal(new TypeError(obj, "number"));
469         // Not reached.
470
return false;
471     }
472
473     public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable
474     {
475         if (obj instanceof Fixnum)
476             return value >= ((Fixnum)obj).value;
477         if (obj instanceof Bignum)
478             return getBigInteger().compareTo(Bignum.getValue(obj)) >= 0;
479         if (obj instanceof Ratio) {
480             BigInteger JavaDoc n =
481                 getBigInteger().multiply(((Ratio)obj).denominator());
482             return n.compareTo(((Ratio)obj).numerator()) >= 0;
483         }
484         if (obj instanceof LispFloat)
485             return isGreaterThanOrEqualTo(((LispFloat)obj).rational());
486         signal(new TypeError(obj, "number"));
487         // Not reached.
488
return false;
489     }
490
491     public LispObject truncate(LispObject obj) throws ConditionThrowable
492     {
493         final LispThread thread = LispThread.currentThread();
494         final LispObject value1, value2;
495     try {
496             if (obj instanceof Fixnum) {
497                 long divisor = ((Fixnum)obj).value;
498                 long quotient = value / divisor;
499                 long remainder = value % divisor;
500                 value1 = number(quotient);
501                 value2 = remainder == 0 ? Fixnum.ZERO : number(remainder);
502             } else if (obj instanceof Bignum) {
503                 BigInteger JavaDoc value = getBigInteger();
504                 BigInteger JavaDoc divisor = ((Bignum)obj).getValue();
505                 BigInteger JavaDoc[] results = value.divideAndRemainder(divisor);
506                 BigInteger JavaDoc quotient = results[0];
507                 BigInteger JavaDoc remainder = results[1];
508                 value1 = number(quotient);
509                 value2 = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
510             } else if (obj instanceof Ratio) {
511                 Ratio divisor = (Ratio) obj;
512                 LispObject quotient =
513                     multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
514                 LispObject remainder =
515                     subtract(quotient.multiplyBy(divisor));
516                 value1 = quotient;
517                 value2 = remainder;
518             } else
519                 return signal(new LispError("Fixnum.truncate(): not implemented: " + obj.typeOf()));
520         }
521         catch (ArithmeticException JavaDoc e) {
522             if (obj.zerop())
523                 return signal(new DivisionByZero());
524             else
525                 return signal(new ArithmeticError(e.getMessage()));
526         }
527         return thread.setValues(value1, value2);
528     }
529
530     public LispObject MOD(LispObject divisor) throws ConditionThrowable
531     {
532         if (divisor instanceof Fixnum) {
533             final int d = ((Fixnum)divisor).value;
534             final int r;
535             try {
536                 r = value % d;
537             }
538             catch (ArithmeticException JavaDoc e) {
539                 return signal(new ArithmeticError("Division by zero."));
540             }
541             if (r == 0)
542                 return Fixnum.ZERO;
543             if (d < 0) {
544                 if (value > 0)
545                     return new Fixnum(r + d);
546             } else {
547                 if (value < 0)
548                     return new Fixnum(r + d);
549             }
550             return new Fixnum(r);
551         }
552         return super.MOD(divisor);
553     }
554
555     public LispObject ash(LispObject obj) throws ConditionThrowable
556     {
557         if (obj instanceof Fixnum) {
558             if (value == 0)
559                 return this;
560             int shift = ((Fixnum)obj).value;
561             if (shift == 0)
562                 return this;
563             long n = value;
564             if (shift <= -32) {
565                 // Right shift.
566
return n >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
567             }
568             if (shift < 0)
569                 return new Fixnum((int)(n >> -shift));
570             if (shift <= 32)
571                 return number(n << shift);
572             // BigInteger.shiftLeft() succumbs to a stack overflow if shift
573
// is Integer.MIN_VALUE, so...
574
if (shift == Integer.MIN_VALUE)
575                 return n >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
576             return number(BigInteger.valueOf(value).shiftLeft(shift));
577         }
578         if (obj instanceof Bignum) {
579             if (value == 0)
580                 return this;
581             BigInteger JavaDoc n = BigInteger.valueOf(value);
582             BigInteger JavaDoc shift = ((Bignum)obj).value;
583             if (shift.signum() > 0)
584                 return signal(new LispError("Can't represent result of left shift."));
585             if (shift.signum() < 0)
586                 return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
587             Debug.bug(); // Shouldn't happen.
588
}
589         return signal(new TypeError(obj, Symbol.INTEGER));
590     }
591
592     public int hashCode()
593     {
594         return value;
595     }
596
597     public String JavaDoc writeToString() throws ConditionThrowable
598     {
599         final LispThread thread = LispThread.currentThread();
600         int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread));
601         String JavaDoc s = Integer.toString(value, base).toUpperCase();
602         if (_PRINT_RADIX_.symbolValue(thread) != NIL) {
603             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
604             switch (base) {
605                 case 2:
606                     sb.append("#b");
607                     sb.append(s);
608                     break;
609                 case 8:
610                     sb.append("#o");
611                     sb.append(s);
612                     break;
613                 case 10:
614                     sb.append(s);
615                     sb.append('.');
616                     break;
617                 case 16:
618                     sb.append("#x");
619                     sb.append(s);
620                     break;
621                 default:
622                     sb.append('#');
623                     sb.append(String.valueOf(base));
624                     sb.append('r');
625                     sb.append(s);
626                     break;
627             }
628             s = sb.toString();
629         }
630         return s;
631     }
632 }
633
Popular Tags