Package org.armedbear.lisp

Source Code of org.armedbear.lisp.Bignum

/*
* Bignum.java
*
* Copyright (C) 2003 Peter Graves
* $Id: Bignum.java,v 1.7 2003/11/15 11:03:32 beedlem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

package org.armedbear.lisp;

import java.math.BigInteger;

public final class Bignum extends LispObject
{
    private final BigInteger value;

    public Bignum(long l)
    {
        value = BigInteger.valueOf(l);
    }

    public Bignum(BigInteger n)
    {
        value = n;
    }

    public LispObject typeOf()
    {
        return Symbol.BIGNUM;
    }

    public LispClass classOf()
    {
        return BuiltInClass.BIGNUM;
    }

    public LispObject typep(LispObject type) throws ConditionThrowable
    {
        if (type == Symbol.BIGNUM)
            return T;
        if (type == BuiltInClass.BIGNUM)
            return T;
        if (type == Symbol.INTEGER)
            return T;
        if (type == BuiltInClass.INTEGER)
            return T;
        if (type == Symbol.RATIONAL)
            return T;
        if (type == BuiltInClass.RATIONAL)
            return T;
        if (type == Symbol.REAL)
            return T;
        if (type == BuiltInClass.REAL)
            return T;
        if (type == Symbol.NUMBER)
            return T;
        if (type == BuiltInClass.NUMBER)
            return T;
        if (type == Symbol.UNSIGNED_BYTE)
            return value.signum() >= 0 ? T : NIL;
        return super.typep(type);
    }

    public LispObject NUMBERP()
    {
        return T;
    }

    public boolean numberp()
    {
        return true;
    }

    public boolean integerp()
    {
        return true;
    }

    public boolean rationalp()
    {
        return true;
    }

    public boolean realp()
    {
        return true;
    }

    public boolean eql(LispObject obj)
    {
        if (this == obj)
            return true;
        if (obj instanceof Bignum) {
            if (value.equals(((Bignum)obj).value))
                return true;
        }
        return false;
    }

    public boolean equal(LispObject obj)
    {
        if (this == obj)
            return true;
        if (obj instanceof Bignum) {
            if (value.equals(((Bignum)obj).value))
                return true;
        }
        return false;
    }

    public boolean equalp(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Bignum)
            return value.equals(((Bignum)obj).value);
        if (obj instanceof LispFloat)
            return floatValue() == ((LispFloat)obj).getValue();
        return false;
    }

    public LispObject ABS()
    {
        if (value.signum() >= 0)
            return this;
        return new Bignum(value.negate());
    }

    public LispObject NUMERATOR()
    {
        return this;
    }

    public LispObject DENOMINATOR()
    {
        return Fixnum.ONE;
    }

    public boolean evenp() throws ConditionThrowable
    {
        return !value.testBit(0);
    }

    public boolean oddp() throws ConditionThrowable
    {
        return value.testBit(0);
    }

    public boolean plusp()
    {
        return value.signum() > 0;
    }

    public boolean minusp()
    {
        return value.signum() < 0;
    }

    public boolean zerop()
    {
        return false;
    }

    public double floatValue() throws ConditionThrowable
    {
        double d = value.doubleValue();
        if (Double.isInfinite(d))
            throw new ConditionThrowable(new TypeError(toString()) +
                                " is too large to be converted to a float");
        return d;
    }

    public static BigInteger getValue(LispObject obj) throws ConditionThrowable
    {
        try {
            return ((Bignum)obj).value;
        }
        catch (ClassCastException e) {
            throw new ConditionThrowable(new TypeError(obj, "bignum"));
        }
    }

    public final BigInteger getValue()
    {
        return value;
    }

    public final LispObject incr()
    {
        return number(value.add(BigInteger.ONE));
    }

    public final LispObject decr()
    {
        return number(value.subtract(BigInteger.ONE));
    }

    public LispObject add(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return number(value.add(Fixnum.getBigInteger(obj)));
        if (obj instanceof Bignum)
            return number(value.add(((Bignum)obj).value));
        if (obj instanceof Ratio) {
            BigInteger numerator = ((Ratio)obj).numerator();
            BigInteger denominator = ((Ratio)obj).denominator();
            return number(value.multiply(denominator).add(numerator),
                denominator);
        }
        if (obj instanceof LispFloat)
            return new LispFloat(floatValue() + ((LispFloat)obj).getValue());
        if (obj instanceof Complex) {
            Complex c = (Complex) obj;
            return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
        }
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public LispObject subtract(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return number(value.subtract(Fixnum.getBigInteger(obj)));
        if (obj instanceof Bignum)
            return number(value.subtract(((Bignum)obj).value));
        if (obj instanceof Ratio) {
            BigInteger numerator = ((Ratio)obj).numerator();
            BigInteger denominator = ((Ratio)obj).denominator();
            return number(value.multiply(denominator).subtract(numerator),
                denominator);
        }
        if (obj instanceof LispFloat)
            return new LispFloat(floatValue() - ((LispFloat)obj).getValue());
        if (obj instanceof Complex) {
            Complex c = (Complex) obj;
            return Complex.getInstance(subtract(c.getRealPart()),
                                       Fixnum.ZERO.subtract(c.getImaginaryPart()));
        }
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public LispObject multiplyBy(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum) {
            int n = ((Fixnum)obj).getValue();
            if (n == 0)
                return Fixnum.ZERO;
            if (n == 1)
                return this;
            return new Bignum(value.multiply(BigInteger.valueOf(n)));
        }
        if (obj instanceof Bignum)
            return new Bignum(value.multiply(((Bignum)obj).value));
        if (obj instanceof Ratio) {
            BigInteger n = ((Ratio)obj).numerator();
            return number(n.multiply(value), ((Ratio)obj).denominator());
        }
        if (obj instanceof LispFloat)
            return new LispFloat(floatValue() * ((LispFloat)obj).getValue());
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public LispObject divideBy(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return number(value, Fixnum.getBigInteger(obj));
        if (obj instanceof Bignum)
            return number(value, ((Bignum)obj).value);
        if (obj instanceof Ratio) {
            BigInteger d = ((Ratio)obj).denominator();
            return number(d.multiply(value), ((Ratio)obj).numerator());
        }
        if (obj instanceof LispFloat)
            return new LispFloat(floatValue() / ((LispFloat)obj).getValue());
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public boolean isEqualTo(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Bignum)
            return value.equals(((Bignum)obj).value);
        if (obj instanceof LispFloat)
            return floatValue() == ((LispFloat)obj).getValue();
        if (obj.numberp())
            return false;
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Bignum)
            return !value.equals(((Bignum)obj).value);
        if (obj instanceof LispFloat)
            return floatValue() != ((LispFloat)obj).getValue();
        if (obj.numberp())
            return true;
        throw new ConditionThrowable(new TypeError(obj, "number"));
    }

    public boolean isLessThan(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return value.compareTo(Fixnum.getBigInteger(obj)) < 0;
        if (obj instanceof Bignum)
            return value.compareTo(((Bignum)obj).value) < 0;
        if (obj instanceof Ratio) {
            BigInteger n = value.multiply(((Ratio)obj).denominator());
            return n.compareTo(((Ratio)obj).numerator()) < 0;
        }
        if (obj instanceof LispFloat)
            return floatValue() < ((LispFloat)obj).getValue();
        throw new ConditionThrowable(new TypeError(obj, "real"));
    }

    public boolean isGreaterThan(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return value.compareTo(Fixnum.getBigInteger(obj)) > 0;
        if (obj instanceof Bignum)
            return value.compareTo(((Bignum)obj).value) > 0;
        if (obj instanceof Ratio) {
            BigInteger n = value.multiply(((Ratio)obj).denominator());
            return n.compareTo(((Ratio)obj).numerator()) > 0;
        }
        if (obj instanceof LispFloat)
            return floatValue() > ((LispFloat)obj).getValue();
        throw new ConditionThrowable(new TypeError(obj, "real"));
    }

    public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return value.compareTo(Fixnum.getBigInteger(obj)) <= 0;
        if (obj instanceof Bignum)
            return value.compareTo(((Bignum)obj).value) <= 0;
        if (obj instanceof Ratio) {
            BigInteger n = value.multiply(((Ratio)obj).denominator());
            return n.compareTo(((Ratio)obj).numerator()) <= 0;
        }
        if (obj instanceof LispFloat)
            return floatValue() <= ((LispFloat)obj).getValue();
        throw new ConditionThrowable(new TypeError(obj, "real"));
    }

    public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable
    {
        if (obj instanceof Fixnum)
            return value.compareTo(Fixnum.getBigInteger(obj)) >= 0;
        if (obj instanceof Bignum)
            return value.compareTo(((Bignum)obj).value) >= 0;
        if (obj instanceof Ratio) {
            BigInteger n = value.multiply(((Ratio)obj).denominator());
            return n.compareTo(((Ratio)obj).numerator()) >= 0;
        }
        if (obj instanceof LispFloat)
            return floatValue() >= ((LispFloat)obj).getValue();
        throw new ConditionThrowable(new TypeError(obj, "real"));
    }

    public LispObject truncate(LispObject obj) throws ConditionThrowable
    {
        final LispThread thread = LispThread.currentThread();
        LispObject[] values = new LispObject[2];
  try {
    if (obj instanceof Ratio) {
            Ratio divisor = (Ratio) obj;
            LispObject quotient =
        multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
            LispObject remainder =
        subtract(quotient.multiplyBy(divisor));
            values[0] = quotient;
            values[1] = remainder;
    } else if (obj instanceof Fixnum) {
            BigInteger divisor = ((Fixnum)obj).getBigInteger();
            BigInteger[] results = value.divideAndRemainder(divisor);
            BigInteger quotient = results[0];
            BigInteger remainder = results[1];
            values[0] = number(quotient);
            values[1] = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
    } else if (obj instanceof Bignum) {
            BigInteger divisor = ((Bignum)obj).getValue();
            BigInteger[] results = value.divideAndRemainder(divisor);
            BigInteger quotient = results[0];
            BigInteger remainder = results[1];
            values[0] = number(quotient);
            values[1] = (remainder.signum() == 0) ? Fixnum.ZERO : number(remainder);
    } else if (obj instanceof Ratio) {
            Ratio divisor = (Ratio) obj;
            LispObject quotient =
        multiplyBy(divisor.DENOMINATOR()).truncate(divisor.NUMERATOR());
            LispObject remainder =
        subtract(quotient.multiplyBy(divisor));
            values[0] = quotient;
            values[1] = remainder;
    } else
            throw new ConditionThrowable(new LispError("Bignum.truncate(): not implemented: " + obj.typeOf()));
        }
        catch (ArithmeticException e) {
            if (obj.zerop())
                throw new ConditionThrowable(new DivisionByZero());
            throw new ConditionThrowable(new ArithmeticError(e.getMessage()));
        }
        thread.setValues(values);
        return values[0];
    }

    public int hashCode()
    {
        return value.hashCode();
    }

    public String toString()
    {
        final LispThread thread = LispThread.currentThread();
        int base;
        try {
            base = Fixnum.getValue(_PRINT_BASE_.symbolValueNoThrow(thread));
        }
        catch (Throwable t) {
            Debug.trace(t);
            base = 10;
        }
        String s = value.toString(base).toUpperCase();
        if (_PRINT_RADIX_.symbolValueNoThrow(thread) != NIL) {
            StringBuffer sb = new StringBuffer();
            switch (base) {
                case 2:
                    sb.append("#b");
                    sb.append(s);
                    break;
                case 8:
                    sb.append("#o");
                    sb.append(s);
                    break;
                case 10:
                    sb.append(s);
                    sb.append('.');
                    break;
                case 16:
                    sb.append("#x");
                    sb.append(s);
                    break;
                default:
                    sb.append('#');
                    sb.append(String.valueOf(base));
                    sb.append('r');
                    sb.append(s);
                    break;
            }
            s = sb.toString();
        }
        return s;
    }
}
TOP

Related Classes of org.armedbear.lisp.Bignum

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.