KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Bignum.java
3  *
4  * Copyright (C) 2003-2004 Peter Graves
5  * $Id: Bignum.java,v 1.57 2004/06/19 17:01:55 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 Bignum extends LispObject
27 {
28     public final BigInteger JavaDoc value;
29
30     public Bignum(long l)
31     {
32         value = BigInteger.valueOf(l);
33     }
34
35     public Bignum(BigInteger JavaDoc n)
36     {
37         value = n;
38     }
39
40     public LispObject typeOf()
41     {
42         return Symbol.BIGNUM;
43     }
44
45     public LispClass classOf()
46     {
47         return BuiltInClass.BIGNUM;
48     }
49
50     public LispObject typep(LispObject type) throws ConditionThrowable
51     {
52         if (type == Symbol.BIGNUM)
53             return T;
54         if (type == BuiltInClass.BIGNUM)
55             return T;
56         if (type == Symbol.INTEGER)
57             return T;
58         if (type == BuiltInClass.INTEGER)
59             return T;
60         if (type == Symbol.RATIONAL)
61             return T;
62         if (type == BuiltInClass.RATIONAL)
63             return T;
64         if (type == Symbol.REAL)
65             return T;
66         if (type == BuiltInClass.REAL)
67             return T;
68         if (type == Symbol.NUMBER)
69             return T;
70         if (type == BuiltInClass.NUMBER)
71             return T;
72         if (type == Symbol.SIGNED_BYTE)
73             return T;
74         if (type == Symbol.UNSIGNED_BYTE)
75             return value.signum() >= 0 ? T : NIL;
76         return super.typep(type);
77     }
78
79     public LispObject NUMBERP()
80     {
81         return T;
82     }
83
84     public boolean numberp()
85     {
86         return true;
87     }
88
89     public boolean integerp()
90     {
91         return true;
92     }
93
94     public boolean rationalp()
95     {
96         return true;
97     }
98
99     public boolean realp()
100     {
101         return true;
102     }
103
104     public boolean eql(LispObject obj)
105     {
106         if (this == obj)
107             return true;
108         if (obj instanceof Bignum) {
109             if (value.equals(((Bignum)obj).value))
110                 return true;
111         }
112         return false;
113     }
114
115     public boolean equal(LispObject obj)
116     {
117         if (this == obj)
118             return true;
119         if (obj instanceof Bignum) {
120             if (value.equals(((Bignum)obj).value))
121                 return true;
122         }
123         return false;
124     }
125
126     public boolean equalp(LispObject obj) throws ConditionThrowable
127     {
128         if (obj instanceof Bignum)
129             return value.equals(((Bignum)obj).value);
130         if (obj instanceof LispFloat)
131             return floatValue() == ((LispFloat)obj).getValue();
132         return false;
133     }
134
135     public LispObject ABS()
136     {
137         if (value.signum() >= 0)
138             return this;
139         return new Bignum(value.negate());
140     }
141
142     public LispObject NUMERATOR()
143     {
144         return this;
145     }
146
147     public LispObject DENOMINATOR()
148     {
149         return Fixnum.ONE;
150     }
151
152     public boolean evenp() throws ConditionThrowable
153     {
154         return !value.testBit(0);
155     }
156
157     public boolean oddp() throws ConditionThrowable
158     {
159         return value.testBit(0);
160     }
161
162     public boolean plusp()
163     {
164         return value.signum() > 0;
165     }
166
167     public boolean minusp()
168     {
169         return value.signum() < 0;
170     }
171
172     public boolean zerop()
173     {
174         return false;
175     }
176
177     public double floatValue() throws ConditionThrowable
178     {
179         double d = value.doubleValue();
180         if (Double.isInfinite(d))
181             signal(new TypeError(writeToString() +
182                                  " is too large to be converted to a float"));
183         return d;
184     }
185
186     public static BigInteger JavaDoc getValue(LispObject obj) throws ConditionThrowable
187     {
188         try {
189             return ((Bignum)obj).value;
190         }
191         catch (ClassCastException JavaDoc e) {
192             signal(new TypeError(obj, "bignum"));
193             // Not reached.
194
return null;
195         }
196     }
197
198     public final BigInteger JavaDoc getValue()
199     {
200         return value;
201     }
202
203     public final LispObject incr()
204     {
205         return number(value.add(BigInteger.ONE));
206     }
207
208     public final LispObject decr()
209     {
210         return number(value.subtract(BigInteger.ONE));
211     }
212
213     public LispObject add(LispObject obj) throws ConditionThrowable
214     {
215         if (obj instanceof Fixnum)
216             return number(value.add(Fixnum.getBigInteger(obj)));
217         if (obj instanceof Bignum)
218             return number(value.add(((Bignum)obj).value));
219         if (obj instanceof Ratio) {
220             BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
221             BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
222             return number(value.multiply(denominator).add(numerator),
223                 denominator);
224         }
225         if (obj instanceof LispFloat)
226             return new LispFloat(floatValue() + ((LispFloat)obj).getValue());
227         if (obj instanceof Complex) {
228             Complex c = (Complex) obj;
229             return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
230         }
231         return signal(new TypeError(obj, Symbol.NUMBER));
232     }
233
234     public LispObject subtract(LispObject obj) throws ConditionThrowable
235     {
236         if (obj instanceof Fixnum)
237             return number(value.subtract(Fixnum.getBigInteger(obj)));
238         if (obj instanceof Bignum)
239             return number(value.subtract(((Bignum)obj).value));
240         if (obj instanceof Ratio) {
241             BigInteger JavaDoc numerator = ((Ratio)obj).numerator();
242             BigInteger JavaDoc denominator = ((Ratio)obj).denominator();
243             return number(value.multiply(denominator).subtract(numerator),
244                 denominator);
245         }
246         if (obj instanceof LispFloat)
247             return new LispFloat(floatValue() - ((LispFloat)obj).getValue());
248         if (obj instanceof Complex) {
249             Complex c = (Complex) obj;
250             return Complex.getInstance(subtract(c.getRealPart()),
251                                        Fixnum.ZERO.subtract(c.getImaginaryPart()));
252         }
253         return signal(new TypeError(obj, Symbol.NUMBER));
254     }
255
256     public LispObject multiplyBy(LispObject obj) throws ConditionThrowable
257     {
258         if (obj instanceof Fixnum) {
259             int n = ((Fixnum)obj).value;
260             if (n == 0)
261                 return Fixnum.ZERO;
262             if (n == 1)
263                 return this;
264             return new Bignum(value.multiply(BigInteger.valueOf(n)));
265         }
266         if (obj instanceof Bignum)
267             return new Bignum(value.multiply(((Bignum)obj).value));
268         if (obj instanceof Ratio) {
269             BigInteger JavaDoc n = ((Ratio)obj).numerator();
270             return number(n.multiply(value), ((Ratio)obj).denominator());
271         }
272         if (obj instanceof LispFloat)
273             return new LispFloat(floatValue() * ((LispFloat)obj).getValue());
274         return signal(new TypeError(obj, Symbol.NUMBER));
275     }
276
277     public LispObject divideBy(LispObject obj) throws ConditionThrowable
278     {
279         if (obj instanceof Fixnum)
280             return number(value, Fixnum.getBigInteger(obj));
281         if (obj instanceof Bignum)
282             return number(value, ((Bignum)obj).value);
283         if (obj instanceof Ratio) {
284             BigInteger JavaDoc d = ((Ratio)obj).denominator();
285             return number(d.multiply(value), ((Ratio)obj).numerator());
286         }
287         if (obj instanceof LispFloat)
288             return new LispFloat(floatValue() / ((LispFloat)obj).getValue());
289         return signal(new TypeError(obj, Symbol.NUMBER));
290     }
291
292     public boolean isEqualTo(LispObject obj) throws ConditionThrowable
293     {
294         if (obj instanceof Bignum)
295             return value.equals(((Bignum)obj).value);
296         if (obj instanceof LispFloat)
297             return isEqualTo(((LispFloat)obj).rational());
298         if (obj.numberp())
299             return false;
300         signal(new TypeError(obj, Symbol.NUMBER));
301         // Not reached.
302
return false;
303     }
304
305     public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable
306     {
307         if (obj instanceof Bignum)
308             return !value.equals(((Bignum)obj).value);
309         if (obj instanceof LispFloat)
310             return isNotEqualTo(((LispFloat)obj).rational());
311         if (obj.numberp())
312             return true;
313         signal(new TypeError(obj, Symbol.NUMBER));
314         // Not reached.
315
return false;
316     }
317
318     public boolean isLessThan(LispObject obj) throws ConditionThrowable
319     {
320         if (obj instanceof Fixnum)
321             return value.compareTo(Fixnum.getBigInteger(obj)) < 0;
322         if (obj instanceof Bignum)
323             return value.compareTo(((Bignum)obj).value) < 0;
324         if (obj instanceof Ratio) {
325             BigInteger JavaDoc n = value.multiply(((Ratio)obj).denominator());
326             return n.compareTo(((Ratio)obj).numerator()) < 0;
327         }
328         if (obj instanceof LispFloat)
329             return isLessThan(((LispFloat)obj).rational());
330         signal(new TypeError(obj, Symbol.REAL));
331         // Not reached.
332
return false;
333     }
334
335     public boolean isGreaterThan(LispObject obj) throws ConditionThrowable
336     {
337         if (obj instanceof Fixnum)
338             return value.compareTo(Fixnum.getBigInteger(obj)) > 0;
339         if (obj instanceof Bignum)
340             return value.compareTo(((Bignum)obj).value) > 0;
341         if (obj instanceof Ratio) {
342             BigInteger JavaDoc n = value.multiply(((Ratio)obj).denominator());
343             return n.compareTo(((Ratio)obj).numerator()) > 0;
344         }
345         if (obj instanceof LispFloat)
346             return isGreaterThan(((LispFloat)obj).rational());
347         signal(new TypeError(obj, Symbol.REAL));
348         // Not reached.
349
return false;
350     }
351
352     public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable
353     {
354         if (obj instanceof Fixnum)
355             return value.compareTo(Fixnum.getBigInteger(obj)) <= 0;
356         if (obj instanceof Bignum)
357             return value.compareTo(((Bignum)obj).value) <= 0;
358         if (obj instanceof Ratio) {
359             BigInteger JavaDoc n = value.multiply(((Ratio)obj).denominator());
360             return n.compareTo(((Ratio)obj).numerator()) <= 0;
361         }
362         if (obj instanceof LispFloat)
363             return isLessThanOrEqualTo(((LispFloat)obj).rational());
364         signal(new TypeError(obj, Symbol.REAL));
365         // Not reached.
366
return false;
367     }
368
369     public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable
370     {
371         if (obj instanceof Fixnum)
372             return value.compareTo(Fixnum.getBigInteger(obj)) >= 0;
373         if (obj instanceof Bignum)
374             return value.compareTo(((Bignum)obj).value) >= 0;
375         if (obj instanceof Ratio) {
376             BigInteger JavaDoc n = value.multiply(((Ratio)obj).denominator());
377             return n.compareTo(((Ratio)obj).numerator()) >= 0;
378         }
379         if (obj instanceof LispFloat)
380             return isGreaterThanOrEqualTo(((LispFloat)obj).rational());
381         signal(new TypeError(obj, Symbol.REAL));
382         // Not reached.
383
return false;
384     }
385
386     public LispObject truncate(LispObject obj) throws ConditionThrowable
387     {
388         final LispThread thread = LispThread.currentThread();
389         LispObject value1, value2;
390     try {
391             if (obj instanceof Ratio) {
392                 Ratio divisor = (Ratio) obj;
393                 LispObject quotient =
394                     multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
395                 LispObject remainder =
396                     subtract(quotient.multiplyBy(divisor));
397                 value1 = quotient;
398                 value2 = remainder;
399             } else if (obj instanceof Fixnum) {
400                 BigInteger JavaDoc divisor = ((Fixnum)obj).getBigInteger();
401                 BigInteger JavaDoc[] results = value.divideAndRemainder(divisor);
402                 BigInteger JavaDoc quotient = results[0];
403                 BigInteger JavaDoc remainder = results[1];
404                 value1 = number(quotient);
405                 value2 = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
406             } else if (obj instanceof Bignum) {
407                 BigInteger JavaDoc divisor = ((Bignum)obj).value;
408                 BigInteger JavaDoc[] results = value.divideAndRemainder(divisor);
409                 BigInteger JavaDoc quotient = results[0];
410                 BigInteger JavaDoc remainder = results[1];
411                 value1 = number(quotient);
412                 value2 = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
413             } else if (obj instanceof Ratio) {
414                 Ratio divisor = (Ratio) obj;
415                 LispObject quotient =
416                     multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
417                 LispObject remainder =
418                     subtract(quotient.multiplyBy(divisor));
419                 value1 = quotient;
420                 value2 = remainder;
421             } else
422                 return signal(new LispError("Bignum.truncate(): not implemented: " + obj.typeOf()));
423         }
424         catch (ArithmeticException JavaDoc e) {
425             if (obj.zerop())
426                 return signal(new DivisionByZero());
427             else
428                 return signal(new ArithmeticError(e.getMessage()));
429         }
430         return thread.setValues(value1, value2);
431     }
432
433     public LispObject ash(LispObject obj) throws ConditionThrowable
434     {
435         BigInteger JavaDoc n = value;
436         if (obj instanceof Fixnum) {
437             int count = ((Fixnum)obj).value;
438             if (count == 0)
439                 return this;
440             // BigInteger.shiftLeft() succumbs to a stack overflow if count
441
// is Integer.MIN_VALUE, so...
442
if (count == Integer.MIN_VALUE)
443                 return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
444             return number(n.shiftLeft(count));
445         }
446         if (obj instanceof Bignum) {
447             BigInteger JavaDoc count = ((Bignum)obj).value;
448             if (count.signum() > 0)
449                 return signal(new LispError("Can't represent result of left shift."));
450             if (count.signum() < 0)
451                 return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
452             Debug.bug(); // Shouldn't happen.
453
}
454         return signal(new TypeError(obj, Symbol.INTEGER));
455     }
456
457     public int hashCode()
458     {
459         return value.hashCode();
460     }
461
462     public String JavaDoc writeToString() throws ConditionThrowable
463     {
464         final LispThread thread = LispThread.currentThread();
465         final int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread));
466         String JavaDoc s = value.toString(base).toUpperCase();
467         if (_PRINT_RADIX_.symbolValue(thread) != NIL) {
468             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
469             switch (base) {
470                 case 2:
471                     sb.append("#b");
472                     sb.append(s);
473                     break;
474                 case 8:
475                     sb.append("#o");
476                     sb.append(s);
477                     break;
478                 case 10:
479                     sb.append(s);
480                     sb.append('.');
481                     break;
482                 case 16:
483                     sb.append("#x");
484                     sb.append(s);
485                     break;
486                 default:
487                     sb.append('#');
488                     sb.append(String.valueOf(base));
489                     sb.append('r');
490                     sb.append(s);
491                     break;
492             }
493             s = sb.toString();
494         }
495         return s;
496     }
497 }
498
Popular Tags