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