source: branches/0.22.x/abcl/src/org/armedbear/lisp/Bignum.java

Last change on this file was 12288, checked in by vvoutilainen, 15 years ago

Don't extend Lisp in LispObject, static import Lisp wherever
necessary. Patch by Douglas R. Miles.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.3 KB
Line 
1/*
2 * Bignum.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: Bignum.java 12288 2009-11-29 22:00:12Z vvoutilainen $
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 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38import java.math.BigInteger;
39
40public final class Bignum extends LispInteger
41{
42  public final BigInteger value;
43
44  private static BigInteger MOST_NEGATIVE_FIXNUM =
45          BigInteger.valueOf(Integer.MIN_VALUE);
46  private static BigInteger MOST_POSITIVE_FIXNUM =
47          BigInteger.valueOf(Integer.MAX_VALUE);
48
49  public static LispInteger getInstance(long l) {
50      if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE)
51          return Fixnum.getInstance(l);
52      else
53          return new Bignum(l);
54  }
55
56  public static LispInteger getInstance(BigInteger n) {
57      if (MOST_NEGATIVE_FIXNUM.compareTo(n) < 0 ||
58              MOST_POSITIVE_FIXNUM.compareTo(n) > 0)
59          return new Bignum(n);
60      else
61          return Fixnum.getInstance(n.intValue());
62  }
63
64  public static LispInteger getInstance(String s, int radix) {
65      BigInteger value = new BigInteger(s, radix);
66
67      return Bignum.getInstance(value);
68  }
69
70  private Bignum(long l)
71  {
72    value = BigInteger.valueOf(l);
73  }
74
75  private Bignum(BigInteger n)
76  {
77    value = n;
78  }
79
80  @Override
81  public Object javaInstance()
82  {
83    return value;
84  }
85
86  @Override
87  public Object javaInstance(Class c) {
88    String cn = c.getName();
89    if (cn.equals("java.lang.Byte") || cn.equals("byte"))
90      return Byte.valueOf((byte)value.intValue());
91    if (cn.equals("java.lang.Short") || cn.equals("short"))
92      return Short.valueOf((short)value.intValue());
93    if (cn.equals("java.lang.Integer") || cn.equals("int"))
94      return Integer.valueOf(value.intValue());
95    if (cn.equals("java.lang.Long") || cn.equals("long"))
96      return Long.valueOf((long)value.longValue());
97    return javaInstance();
98  }
99
100
101  @Override
102  public LispObject typeOf()
103  {
104    if (value.signum() > 0)
105      return list(Symbol.INTEGER,
106                   new Bignum((long)Integer.MAX_VALUE + 1));
107    return Symbol.BIGNUM;
108  }
109
110  @Override
111  public LispObject classOf()
112  {
113    return BuiltInClass.BIGNUM;
114  }
115
116  @Override
117  public LispObject typep(LispObject type)
118  {
119    if (type instanceof Symbol)
120      {
121        if (type == Symbol.BIGNUM)
122          return T;
123        if (type == Symbol.INTEGER)
124          return T;
125        if (type == Symbol.RATIONAL)
126          return T;
127        if (type == Symbol.REAL)
128          return T;
129        if (type == Symbol.NUMBER)
130          return T;
131        if (type == Symbol.SIGNED_BYTE)
132          return T;
133        if (type == Symbol.UNSIGNED_BYTE)
134          return value.signum() >= 0 ? T : NIL;
135      }
136    else if (type instanceof LispClass)
137      {
138        if (type == BuiltInClass.BIGNUM)
139          return T;
140        if (type == BuiltInClass.INTEGER)
141          return T;
142        if (type == BuiltInClass.RATIONAL)
143          return T;
144        if (type == BuiltInClass.REAL)
145          return T;
146        if (type == BuiltInClass.NUMBER)
147          return T;
148      }
149    else if (type instanceof Cons)
150      {
151        if (type.equal(UNSIGNED_BYTE_8))
152          return NIL;
153        if (type.equal(UNSIGNED_BYTE_32))
154          {
155            if (minusp())
156              return NIL;
157            return isLessThan(UNSIGNED_BYTE_32_MAX_VALUE) ? T : NIL;
158          }
159      }
160    return super.typep(type);
161  }
162
163  @Override
164  public boolean numberp()
165  {
166    return true;
167  }
168
169  @Override
170  public boolean integerp()
171  {
172    return true;
173  }
174
175  @Override
176  public boolean rationalp()
177  {
178    return true;
179  }
180
181  @Override
182  public boolean realp()
183  {
184    return true;
185  }
186
187  @Override
188  public boolean eql(LispObject obj)
189  {
190    if (this == obj)
191      return true;
192    if (obj instanceof Bignum)
193      {
194        if (value.equals(((Bignum)obj).value))
195          return true;
196      }
197    return false;
198  }
199
200  @Override
201  public boolean equal(LispObject obj)
202  {
203    if (this == obj)
204      return true;
205    if (obj instanceof Bignum)
206      {
207        if (value.equals(((Bignum)obj).value))
208          return true;
209      }
210    return false;
211  }
212
213  @Override
214  public boolean equalp(LispObject obj)
215  {
216    if (obj instanceof Bignum)
217      return value.equals(((Bignum)obj).value);
218    if (obj instanceof SingleFloat)
219      return floatValue() == ((SingleFloat)obj).value;
220    if (obj instanceof DoubleFloat)
221      return doubleValue() == ((DoubleFloat)obj).value;
222    return false;
223  }
224
225  @Override
226  public LispObject ABS()
227  {
228    if (value.signum() >= 0)
229      return this;
230    return new Bignum(value.negate());
231  }
232
233  @Override
234  public LispObject NUMERATOR()
235  {
236    return this;
237  }
238
239  @Override
240  public LispObject DENOMINATOR()
241  {
242    return Fixnum.ONE;
243  }
244
245  @Override
246  public boolean evenp()
247  {
248    return !value.testBit(0);
249  }
250
251  @Override
252  public boolean oddp()
253  {
254    return value.testBit(0);
255  }
256
257  @Override
258  public boolean plusp()
259  {
260    return value.signum() > 0;
261  }
262
263  @Override
264  public boolean minusp()
265  {
266    return value.signum() < 0;
267  }
268
269  @Override
270  public boolean zerop()
271  {
272    return false;
273  }
274
275  @Override
276  public int intValue()
277  {
278    return value.intValue();
279  }
280
281  @Override
282  public long longValue()
283  {
284    return value.longValue();
285  }
286
287  @Override
288  public float floatValue()
289  {
290    float f = value.floatValue();
291    if (Float.isInfinite(f))
292      error(new TypeError("The value " + writeToString() +
293                           " is too large to be converted to a single float."));
294    return f;
295  }
296
297  @Override
298  public double doubleValue()
299  {
300    double d = value.doubleValue();
301    if (Double.isInfinite(d))
302      error(new TypeError("The value " + writeToString() +
303                           " is too large to be converted to a double float."));
304    return d;
305  }
306
307  public static BigInteger getValue(LispObject obj)
308  {
309         
310    if (obj instanceof Bignum)
311      {
312        return ((Bignum)obj).value;
313      }
314        type_error(obj, Symbol.BIGNUM);
315        // Not reached.
316        return null;
317  }
318
319  @Override
320  public final LispObject incr()
321  {
322    return number(value.add(BigInteger.ONE));
323  }
324
325  @Override
326  public final LispObject decr()
327  {
328    return number(value.subtract(BigInteger.ONE));
329  }
330
331  @Override
332  public LispObject add(int n)
333  {
334    return number(value.add(BigInteger.valueOf(n)));
335  }
336
337  @Override
338  public LispObject add(LispObject obj)
339  {
340    if (obj instanceof Fixnum)
341      return number(value.add(Fixnum.getBigInteger(obj)));
342    if (obj instanceof Bignum)
343      return number(value.add(((Bignum)obj).value));
344    if (obj instanceof Ratio)
345      {
346        BigInteger numerator = ((Ratio)obj).numerator();
347        BigInteger denominator = ((Ratio)obj).denominator();
348        return number(value.multiply(denominator).add(numerator),
349                      denominator);
350      }
351    if (obj instanceof SingleFloat)
352      return new SingleFloat(floatValue() + ((SingleFloat)obj).value);
353    if (obj instanceof DoubleFloat)
354      return new DoubleFloat(doubleValue() + ((DoubleFloat)obj).value);
355    if (obj instanceof Complex)
356      {
357        Complex c = (Complex) obj;
358        return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
359      }
360    return type_error(obj, Symbol.NUMBER);
361  }
362
363  @Override
364  public LispObject subtract(LispObject obj)
365  {
366    if (obj instanceof Fixnum)
367      return number(value.subtract(Fixnum.getBigInteger(obj)));
368    if (obj instanceof Bignum)
369      return number(value.subtract(((Bignum)obj).value));
370    if (obj instanceof Ratio)
371      {
372        BigInteger numerator = ((Ratio)obj).numerator();
373        BigInteger denominator = ((Ratio)obj).denominator();
374        return number(value.multiply(denominator).subtract(numerator),
375                      denominator);
376      }
377    if (obj instanceof SingleFloat)
378      return new SingleFloat(floatValue() - ((SingleFloat)obj).value);
379    if (obj instanceof DoubleFloat)
380      return new DoubleFloat(doubleValue() - ((DoubleFloat)obj).value);
381    if (obj instanceof Complex)
382      {
383        Complex c = (Complex) obj;
384        return Complex.getInstance(subtract(c.getRealPart()),
385                                   Fixnum.ZERO.subtract(c.getImaginaryPart()));
386      }
387    return type_error(obj, Symbol.NUMBER);
388  }
389
390  @Override
391  public LispObject multiplyBy(int n)
392  {
393    if (n == 0)
394      return Fixnum.ZERO;
395    if (n == 1)
396      return this;
397    return new Bignum(value.multiply(BigInteger.valueOf(n)));
398  }
399
400  @Override
401  public LispObject multiplyBy(LispObject obj)
402  {
403    if (obj instanceof Fixnum)
404      {
405        int n = ((Fixnum)obj).value;
406        if (n == 0)
407          return Fixnum.ZERO;
408        if (n == 1)
409          return this;
410        return new Bignum(value.multiply(BigInteger.valueOf(n)));
411      }
412    if (obj instanceof Bignum)
413      return new Bignum(value.multiply(((Bignum)obj).value));
414    if (obj instanceof Ratio)
415      {
416        BigInteger n = ((Ratio)obj).numerator();
417        return number(n.multiply(value), ((Ratio)obj).denominator());
418      }
419    if (obj instanceof SingleFloat)
420      return new SingleFloat(floatValue() * ((SingleFloat)obj).value);
421    if (obj instanceof DoubleFloat)
422      return new DoubleFloat(doubleValue() * ((DoubleFloat)obj).value);
423    if (obj instanceof Complex)
424      {
425        Complex c = (Complex) obj;
426        return Complex.getInstance(multiplyBy(c.getRealPart()),
427                                   multiplyBy(c.getImaginaryPart()));
428      }
429    return type_error(obj, Symbol.NUMBER);
430  }
431
432  @Override
433  public LispObject divideBy(LispObject obj)
434  {
435    if (obj instanceof Fixnum)
436      return number(value, Fixnum.getBigInteger(obj));
437    if (obj instanceof Bignum)
438      return number(value, ((Bignum)obj).value);
439    if (obj instanceof Ratio)
440      {
441        BigInteger d = ((Ratio)obj).denominator();
442        return number(d.multiply(value), ((Ratio)obj).numerator());
443      }
444    if (obj instanceof SingleFloat)
445      return new SingleFloat(floatValue() / ((SingleFloat)obj).value);
446    if (obj instanceof DoubleFloat)
447      return new DoubleFloat(doubleValue() / ((DoubleFloat)obj).value);
448    if (obj instanceof Complex)
449      {
450        Complex c = (Complex) obj;
451        LispObject realPart = c.getRealPart();
452        LispObject imagPart = c.getImaginaryPart();
453        LispObject denominator =
454          realPart.multiplyBy(realPart).add(imagPart.multiplyBy(imagPart));
455        return Complex.getInstance(multiplyBy(realPart).divideBy(denominator),
456                                   Fixnum.ZERO.subtract(multiplyBy(imagPart).divideBy(denominator)));
457      }
458    return type_error(obj, Symbol.NUMBER);
459  }
460
461  @Override
462  public boolean isEqualTo(LispObject obj)
463  {
464    if (obj instanceof Bignum)
465      return value.equals(((Bignum)obj).value);
466    if (obj instanceof SingleFloat)
467      return isEqualTo(((SingleFloat)obj).rational());
468    if (obj instanceof DoubleFloat)
469      return isEqualTo(((DoubleFloat)obj).rational());
470    if (obj.numberp())
471      return false;
472    type_error(obj, Symbol.NUMBER);
473    // Not reached.
474    return false;
475  }
476
477  @Override
478  public boolean isNotEqualTo(LispObject obj)
479  {
480    if (obj instanceof Bignum)
481      return !value.equals(((Bignum)obj).value);
482    if (obj instanceof SingleFloat)
483      return isNotEqualTo(((SingleFloat)obj).rational());
484    if (obj instanceof DoubleFloat)
485      return isNotEqualTo(((DoubleFloat)obj).rational());
486    if (obj.numberp())
487      return true;
488    type_error(obj, Symbol.NUMBER);
489    // Not reached.
490    return false;
491  }
492
493  @Override
494  public boolean isLessThan(LispObject obj)
495  {
496    if (obj instanceof Fixnum)
497      return value.compareTo(Fixnum.getBigInteger(obj)) < 0;
498    if (obj instanceof Bignum)
499      return value.compareTo(((Bignum)obj).value) < 0;
500    if (obj instanceof Ratio)
501      {
502        BigInteger n = value.multiply(((Ratio)obj).denominator());
503        return n.compareTo(((Ratio)obj).numerator()) < 0;
504      }
505    if (obj instanceof SingleFloat)
506      return isLessThan(((SingleFloat)obj).rational());
507    if (obj instanceof DoubleFloat)
508      return isLessThan(((DoubleFloat)obj).rational());
509    type_error(obj, Symbol.REAL);
510    // Not reached.
511    return false;
512  }
513
514  @Override
515  public boolean isGreaterThan(LispObject obj)
516  {
517    if (obj instanceof Fixnum)
518      return value.compareTo(Fixnum.getBigInteger(obj)) > 0;
519    if (obj instanceof Bignum)
520      return value.compareTo(((Bignum)obj).value) > 0;
521    if (obj instanceof Ratio)
522      {
523        BigInteger n = value.multiply(((Ratio)obj).denominator());
524        return n.compareTo(((Ratio)obj).numerator()) > 0;
525      }
526    if (obj instanceof SingleFloat)
527      return isGreaterThan(((SingleFloat)obj).rational());
528    if (obj instanceof DoubleFloat)
529      return isGreaterThan(((DoubleFloat)obj).rational());
530    type_error(obj, Symbol.REAL);
531    // Not reached.
532    return false;
533  }
534
535  @Override
536  public boolean isLessThanOrEqualTo(LispObject obj)
537  {
538    if (obj instanceof Fixnum)
539      return value.compareTo(Fixnum.getBigInteger(obj)) <= 0;
540    if (obj instanceof Bignum)
541      return value.compareTo(((Bignum)obj).value) <= 0;
542    if (obj instanceof Ratio)
543      {
544        BigInteger n = value.multiply(((Ratio)obj).denominator());
545        return n.compareTo(((Ratio)obj).numerator()) <= 0;
546      }
547    if (obj instanceof SingleFloat)
548      return isLessThanOrEqualTo(((SingleFloat)obj).rational());
549    if (obj instanceof DoubleFloat)
550      return isLessThanOrEqualTo(((DoubleFloat)obj).rational());
551    type_error(obj, Symbol.REAL);
552    // Not reached.
553    return false;
554  }
555
556  @Override
557  public boolean isGreaterThanOrEqualTo(LispObject obj)
558  {
559    if (obj instanceof Fixnum)
560      return value.compareTo(Fixnum.getBigInteger(obj)) >= 0;
561    if (obj instanceof Bignum)
562      return value.compareTo(((Bignum)obj).value) >= 0;
563    if (obj instanceof Ratio)
564      {
565        BigInteger n = value.multiply(((Ratio)obj).denominator());
566        return n.compareTo(((Ratio)obj).numerator()) >= 0;
567      }
568    if (obj instanceof SingleFloat)
569      return isGreaterThanOrEqualTo(((SingleFloat)obj).rational());
570    if (obj instanceof DoubleFloat)
571      return isGreaterThanOrEqualTo(((DoubleFloat)obj).rational());
572    type_error(obj, Symbol.REAL);
573    // Not reached.
574    return false;
575  }
576
577  @Override
578  public LispObject truncate(LispObject obj)
579  {
580    final LispThread thread = LispThread.currentThread();
581    LispObject value1, value2;
582    try
583      {
584        if (obj instanceof Fixnum)
585          {
586            BigInteger divisor = ((Fixnum)obj).getBigInteger();
587            BigInteger[] results = value.divideAndRemainder(divisor);
588            BigInteger quotient = results[0];
589            BigInteger remainder = results[1];
590            value1 = number(quotient);
591            value2 = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
592          }
593        else if (obj instanceof Bignum)
594          {
595            BigInteger divisor = ((Bignum)obj).value;
596            BigInteger[] results = value.divideAndRemainder(divisor);
597            BigInteger quotient = results[0];
598            BigInteger remainder = results[1];
599            value1 = number(quotient);
600            value2 = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
601          }
602        else if (obj instanceof Ratio)
603          {
604            Ratio divisor = (Ratio) obj;
605            LispObject quotient =
606              multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
607            LispObject remainder =
608              subtract(quotient.multiplyBy(divisor));
609            value1 = quotient;
610            value2 = remainder;
611          }
612        else if (obj instanceof SingleFloat)
613          {
614            // "When rationals and floats are combined by a numerical
615            // function, the rational is first converted to a float of the
616            // same format." 12.1.4.1
617            return new SingleFloat(floatValue()).truncate(obj);
618          }
619        else if (obj instanceof DoubleFloat)
620          {
621            // "When rationals and floats are combined by a numerical
622            // function, the rational is first converted to a float of the
623            // same format." 12.1.4.1
624            return new DoubleFloat(doubleValue()).truncate(obj);
625          }
626        else
627          return type_error(obj, Symbol.REAL);
628      }
629    catch (ArithmeticException e)
630      {
631        if (obj.zerop())
632          return error(new DivisionByZero());
633        else
634          return error(new ArithmeticError(e.getMessage()));
635      }
636    return thread.setValues(value1, value2);
637  }
638
639  @Override
640  public LispObject ash(LispObject obj)
641  {
642    BigInteger n = value;
643    if (obj instanceof Fixnum)
644      {
645        int count = ((Fixnum)obj).value;
646        if (count == 0)
647          return this;
648        // BigInteger.shiftLeft() succumbs to a stack overflow if count
649        // is Integer.MIN_VALUE, so...
650        if (count == Integer.MIN_VALUE)
651          return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
652        return number(n.shiftLeft(count));
653      }
654    if (obj instanceof Bignum)
655      {
656        BigInteger count = ((Bignum)obj).value;
657        if (count.signum() > 0)
658          return error(new LispError("Can't represent result of left shift."));
659        if (count.signum() < 0)
660          return n.signum() >= 0 ? Fixnum.ZERO : Fixnum.MINUS_ONE;
661        Debug.bug(); // Shouldn't happen.
662      }
663    return type_error(obj, Symbol.INTEGER);
664  }
665
666  @Override
667  public LispObject LOGNOT()
668  {
669    return number(value.not());
670  }
671
672  @Override
673  public LispObject LOGAND(int n)
674  {
675    if (n >= 0)
676      return Fixnum.getInstance(value.intValue() & n);
677    else
678      return number(value.and(BigInteger.valueOf(n)));
679  }
680
681  @Override
682  public LispObject LOGAND(LispObject obj)
683  {
684    if (obj instanceof Fixnum)
685      {
686        int n = ((Fixnum)obj).value;
687        if (n >= 0)
688          return Fixnum.getInstance(value.intValue() & n);
689        else
690          return number(value.and(BigInteger.valueOf(n)));
691      }
692    else if (obj instanceof Bignum)
693      {
694        final BigInteger n = ((Bignum)obj).value;
695        return number(value.and(n));
696      }
697    else
698      return type_error(obj, Symbol.INTEGER);
699  }
700
701  @Override
702  public LispObject LOGIOR(int n)
703  {
704    return number(value.or(BigInteger.valueOf(n)));
705  }
706
707  @Override
708  public LispObject LOGIOR(LispObject obj)
709  {
710    if (obj instanceof Fixnum)
711      {
712        final BigInteger n = ((Fixnum)obj).getBigInteger();
713        return number(value.or(n));
714      }
715    else if (obj instanceof Bignum)
716      {
717        final BigInteger n = ((Bignum)obj).value;
718        return number(value.or(n));
719      }
720    else
721      return type_error(obj, Symbol.INTEGER);
722  }
723
724  @Override
725  public LispObject LOGXOR(int n)
726  {
727    return number(value.xor(BigInteger.valueOf(n)));
728  }
729
730  @Override
731  public LispObject LOGXOR(LispObject obj)
732  {
733    final BigInteger n;
734    if (obj instanceof Fixnum)
735      n = ((Fixnum)obj).getBigInteger();
736    else if (obj instanceof Bignum)
737      n = ((Bignum)obj).value;
738    else
739      return type_error(obj, Symbol.INTEGER);
740    return number(value.xor(n));
741  }
742
743  @Override
744  public LispObject LDB(int size, int position)
745  {
746    BigInteger n = value.shiftRight(position);
747    BigInteger mask = BigInteger.ONE.shiftLeft(size).subtract(BigInteger.ONE);
748    return number(n.and(mask));
749  }
750
751  @Override
752  public int hashCode()
753  {
754    return value.hashCode();
755  }
756
757  @Override
758  public String writeToString()
759  {
760    final LispThread thread = LispThread.currentThread();
761    final int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue(thread));
762    String s = value.toString(base).toUpperCase();
763    if (Symbol.PRINT_RADIX.symbolValue(thread) != NIL)
764      {
765        StringBuffer sb = new StringBuffer();
766        switch (base)
767          {
768          case 2:
769            sb.append("#b");
770            sb.append(s);
771            break;
772          case 8:
773            sb.append("#o");
774            sb.append(s);
775            break;
776          case 10:
777            sb.append(s);
778            sb.append('.');
779            break;
780          case 16:
781            sb.append("#x");
782            sb.append(s);
783            break;
784          default:
785            sb.append('#');
786            sb.append(String.valueOf(base));
787            sb.append('r');
788            sb.append(s);
789            break;
790          }
791        s = sb.toString();
792      }
793    return s;
794  }
795}
Note: See TracBrowser for help on using the repository browser.