001: /*
002: * Bignum.java
003: *
004: * Copyright (C) 2003 Peter Graves
005: * $Id: Bignum.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 Bignum extends LispObject {
027: private 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.UNSIGNED_BYTE)
067: return value.signum() >= 0 ? T : NIL;
068: return super .typep(type);
069: }
070:
071: public LispObject NUMBERP() {
072: return T;
073: }
074:
075: public boolean numberp() {
076: return true;
077: }
078:
079: public boolean integerp() {
080: return true;
081: }
082:
083: public boolean rationalp() {
084: return true;
085: }
086:
087: public boolean realp() {
088: return true;
089: }
090:
091: public boolean eql(LispObject obj) {
092: if (this == obj)
093: return true;
094: if (obj instanceof Bignum) {
095: if (value.equals(((Bignum) obj).value))
096: return true;
097: }
098: return false;
099: }
100:
101: public boolean equal(LispObject obj) {
102: if (this == obj)
103: return true;
104: if (obj instanceof Bignum) {
105: if (value.equals(((Bignum) obj).value))
106: return true;
107: }
108: return false;
109: }
110:
111: public boolean equalp(LispObject obj) throws ConditionThrowable {
112: if (obj instanceof Bignum)
113: return value.equals(((Bignum) obj).value);
114: if (obj instanceof LispFloat)
115: return floatValue() == ((LispFloat) obj).getValue();
116: return false;
117: }
118:
119: public LispObject ABS() {
120: if (value.signum() >= 0)
121: return this ;
122: return new Bignum(value.negate());
123: }
124:
125: public LispObject NUMERATOR() {
126: return this ;
127: }
128:
129: public LispObject DENOMINATOR() {
130: return Fixnum.ONE;
131: }
132:
133: public boolean evenp() throws ConditionThrowable {
134: return !value.testBit(0);
135: }
136:
137: public boolean oddp() throws ConditionThrowable {
138: return value.testBit(0);
139: }
140:
141: public boolean plusp() {
142: return value.signum() > 0;
143: }
144:
145: public boolean minusp() {
146: return value.signum() < 0;
147: }
148:
149: public boolean zerop() {
150: return false;
151: }
152:
153: public double floatValue() throws ConditionThrowable {
154: double d = value.doubleValue();
155: if (Double.isInfinite(d))
156: throw new ConditionThrowable(new TypeError(toString())
157: + " is too large to be converted to a float");
158: return d;
159: }
160:
161: public static BigInteger getValue(LispObject obj)
162: throws ConditionThrowable {
163: try {
164: return ((Bignum) obj).value;
165: } catch (ClassCastException e) {
166: throw new ConditionThrowable(new TypeError(obj, "bignum"));
167: }
168: }
169:
170: public final BigInteger getValue() {
171: return value;
172: }
173:
174: public final LispObject incr() {
175: return number(value.add(BigInteger.ONE));
176: }
177:
178: public final LispObject decr() {
179: return number(value.subtract(BigInteger.ONE));
180: }
181:
182: public LispObject add(LispObject obj) throws ConditionThrowable {
183: if (obj instanceof Fixnum)
184: return number(value.add(Fixnum.getBigInteger(obj)));
185: if (obj instanceof Bignum)
186: return number(value.add(((Bignum) obj).value));
187: if (obj instanceof Ratio) {
188: BigInteger numerator = ((Ratio) obj).numerator();
189: BigInteger denominator = ((Ratio) obj).denominator();
190: return number(value.multiply(denominator).add(numerator),
191: denominator);
192: }
193: if (obj instanceof LispFloat)
194: return new LispFloat(floatValue()
195: + ((LispFloat) obj).getValue());
196: if (obj instanceof Complex) {
197: Complex c = (Complex) obj;
198: return Complex.getInstance(add(c.getRealPart()), c
199: .getImaginaryPart());
200: }
201: throw new ConditionThrowable(new TypeError(obj, "number"));
202: }
203:
204: public LispObject subtract(LispObject obj)
205: throws ConditionThrowable {
206: if (obj instanceof Fixnum)
207: return number(value.subtract(Fixnum.getBigInteger(obj)));
208: if (obj instanceof Bignum)
209: return number(value.subtract(((Bignum) obj).value));
210: if (obj instanceof Ratio) {
211: BigInteger numerator = ((Ratio) obj).numerator();
212: BigInteger denominator = ((Ratio) obj).denominator();
213: return number(value.multiply(denominator).subtract(
214: numerator), denominator);
215: }
216: if (obj instanceof LispFloat)
217: return new LispFloat(floatValue()
218: - ((LispFloat) obj).getValue());
219: if (obj instanceof Complex) {
220: Complex c = (Complex) obj;
221: return Complex.getInstance(subtract(c.getRealPart()),
222: Fixnum.ZERO.subtract(c.getImaginaryPart()));
223: }
224: throw new ConditionThrowable(new TypeError(obj, "number"));
225: }
226:
227: public LispObject multiplyBy(LispObject obj)
228: throws ConditionThrowable {
229: if (obj instanceof Fixnum) {
230: int n = ((Fixnum) obj).getValue();
231: if (n == 0)
232: return Fixnum.ZERO;
233: if (n == 1)
234: return this ;
235: return new Bignum(value.multiply(BigInteger.valueOf(n)));
236: }
237: if (obj instanceof Bignum)
238: return new Bignum(value.multiply(((Bignum) obj).value));
239: if (obj instanceof Ratio) {
240: BigInteger n = ((Ratio) obj).numerator();
241: return number(n.multiply(value), ((Ratio) obj)
242: .denominator());
243: }
244: if (obj instanceof LispFloat)
245: return new LispFloat(floatValue()
246: * ((LispFloat) obj).getValue());
247: throw new ConditionThrowable(new TypeError(obj, "number"));
248: }
249:
250: public LispObject divideBy(LispObject obj)
251: throws ConditionThrowable {
252: if (obj instanceof Fixnum)
253: return number(value, Fixnum.getBigInteger(obj));
254: if (obj instanceof Bignum)
255: return number(value, ((Bignum) obj).value);
256: if (obj instanceof Ratio) {
257: BigInteger d = ((Ratio) obj).denominator();
258: return number(d.multiply(value), ((Ratio) obj).numerator());
259: }
260: if (obj instanceof LispFloat)
261: return new LispFloat(floatValue()
262: / ((LispFloat) obj).getValue());
263: throw new ConditionThrowable(new TypeError(obj, "number"));
264: }
265:
266: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
267: if (obj instanceof Bignum)
268: return value.equals(((Bignum) obj).value);
269: if (obj instanceof LispFloat)
270: return floatValue() == ((LispFloat) obj).getValue();
271: if (obj.numberp())
272: return false;
273: throw new ConditionThrowable(new TypeError(obj, "number"));
274: }
275:
276: public boolean isNotEqualTo(LispObject obj)
277: throws ConditionThrowable {
278: if (obj instanceof Bignum)
279: return !value.equals(((Bignum) obj).value);
280: if (obj instanceof LispFloat)
281: return floatValue() != ((LispFloat) obj).getValue();
282: if (obj.numberp())
283: return true;
284: throw new ConditionThrowable(new TypeError(obj, "number"));
285: }
286:
287: public boolean isLessThan(LispObject obj) throws ConditionThrowable {
288: if (obj instanceof Fixnum)
289: return value.compareTo(Fixnum.getBigInteger(obj)) < 0;
290: if (obj instanceof Bignum)
291: return value.compareTo(((Bignum) obj).value) < 0;
292: if (obj instanceof Ratio) {
293: BigInteger n = value.multiply(((Ratio) obj).denominator());
294: return n.compareTo(((Ratio) obj).numerator()) < 0;
295: }
296: if (obj instanceof LispFloat)
297: return floatValue() < ((LispFloat) obj).getValue();
298: throw new ConditionThrowable(new TypeError(obj, "real"));
299: }
300:
301: public boolean isGreaterThan(LispObject obj)
302: throws ConditionThrowable {
303: if (obj instanceof Fixnum)
304: return value.compareTo(Fixnum.getBigInteger(obj)) > 0;
305: if (obj instanceof Bignum)
306: return value.compareTo(((Bignum) obj).value) > 0;
307: if (obj instanceof Ratio) {
308: BigInteger n = value.multiply(((Ratio) obj).denominator());
309: return n.compareTo(((Ratio) obj).numerator()) > 0;
310: }
311: if (obj instanceof LispFloat)
312: return floatValue() > ((LispFloat) obj).getValue();
313: throw new ConditionThrowable(new TypeError(obj, "real"));
314: }
315:
316: public boolean isLessThanOrEqualTo(LispObject obj)
317: throws ConditionThrowable {
318: if (obj instanceof Fixnum)
319: return value.compareTo(Fixnum.getBigInteger(obj)) <= 0;
320: if (obj instanceof Bignum)
321: return value.compareTo(((Bignum) obj).value) <= 0;
322: if (obj instanceof Ratio) {
323: BigInteger n = value.multiply(((Ratio) obj).denominator());
324: return n.compareTo(((Ratio) obj).numerator()) <= 0;
325: }
326: if (obj instanceof LispFloat)
327: return floatValue() <= ((LispFloat) obj).getValue();
328: throw new ConditionThrowable(new TypeError(obj, "real"));
329: }
330:
331: public boolean isGreaterThanOrEqualTo(LispObject obj)
332: throws ConditionThrowable {
333: if (obj instanceof Fixnum)
334: return value.compareTo(Fixnum.getBigInteger(obj)) >= 0;
335: if (obj instanceof Bignum)
336: return value.compareTo(((Bignum) obj).value) >= 0;
337: if (obj instanceof Ratio) {
338: BigInteger n = value.multiply(((Ratio) obj).denominator());
339: return n.compareTo(((Ratio) obj).numerator()) >= 0;
340: }
341: if (obj instanceof LispFloat)
342: return floatValue() >= ((LispFloat) obj).getValue();
343: throw new ConditionThrowable(new TypeError(obj, "real"));
344: }
345:
346: public LispObject truncate(LispObject obj)
347: throws ConditionThrowable {
348: final LispThread thread = LispThread.currentThread();
349: LispObject[] values = new LispObject[2];
350: try {
351: if (obj instanceof Ratio) {
352: Ratio divisor = (Ratio) obj;
353: LispObject quotient = multiplyBy(divisor.DENOMINATOR())
354: .truncate(divisor.NUMERATOR());
355: LispObject remainder = subtract(quotient
356: .multiplyBy(divisor));
357: values[0] = quotient;
358: values[1] = remainder;
359: } else if (obj instanceof Fixnum) {
360: BigInteger divisor = ((Fixnum) obj).getBigInteger();
361: BigInteger[] results = value
362: .divideAndRemainder(divisor);
363: BigInteger quotient = results[0];
364: BigInteger remainder = results[1];
365: values[0] = number(quotient);
366: values[1] = (remainder.signum() == 0) ? Fixnum.ZERO
367: : number(remainder);
368: } else if (obj instanceof Bignum) {
369: BigInteger divisor = ((Bignum) obj).getValue();
370: BigInteger[] results = value
371: .divideAndRemainder(divisor);
372: BigInteger quotient = results[0];
373: BigInteger remainder = results[1];
374: values[0] = number(quotient);
375: values[1] = (remainder.signum() == 0) ? Fixnum.ZERO
376: : number(remainder);
377: } else if (obj instanceof Ratio) {
378: Ratio divisor = (Ratio) obj;
379: LispObject quotient = multiplyBy(divisor.DENOMINATOR())
380: .truncate(divisor.NUMERATOR());
381: LispObject remainder = subtract(quotient
382: .multiplyBy(divisor));
383: values[0] = quotient;
384: values[1] = remainder;
385: } else
386: throw new ConditionThrowable(new LispError(
387: "Bignum.truncate(): not implemented: "
388: + obj.typeOf()));
389: } catch (ArithmeticException e) {
390: if (obj.zerop())
391: throw new ConditionThrowable(new DivisionByZero());
392: throw new ConditionThrowable(new ArithmeticError(e
393: .getMessage()));
394: }
395: thread.setValues(values);
396: return values[0];
397: }
398:
399: public int hashCode() {
400: return value.hashCode();
401: }
402:
403: public String toString() {
404: final LispThread thread = LispThread.currentThread();
405: int base;
406: try {
407: base = Fixnum.getValue(_PRINT_BASE_
408: .symbolValueNoThrow(thread));
409: } catch (Throwable t) {
410: Debug.trace(t);
411: base = 10;
412: }
413: String s = value.toString(base).toUpperCase();
414: if (_PRINT_RADIX_.symbolValueNoThrow(thread) != NIL) {
415: StringBuffer sb = new StringBuffer();
416: switch (base) {
417: case 2:
418: sb.append("#b");
419: sb.append(s);
420: break;
421: case 8:
422: sb.append("#o");
423: sb.append(s);
424: break;
425: case 10:
426: sb.append(s);
427: sb.append('.');
428: break;
429: case 16:
430: sb.append("#x");
431: sb.append(s);
432: break;
433: default:
434: sb.append('#');
435: sb.append(String.valueOf(base));
436: sb.append('r');
437: sb.append(s);
438: break;
439: }
440: s = sb.toString();
441: }
442: return s;
443: }
444: }
|