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

Last change on this file was 13440, checked in by ehuelsmann, 13 years ago

Rename writeToString() to printObject() since that's what it's being used for.
Additionally, create princToString() for use in error messages, making the

required replacement where appropriate.

  • 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 13440 2011-08-05 21:25:10Z ehuelsmann $
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 " + princToString() +
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 " + princToString() +
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 printObject()
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.