StandardLispBignum.java :  » Scripting » Jatha » org » jatha » dynatype » Java Open Source

Java Open Source » Scripting » Jatha 
Jatha » org » jatha » dynatype » StandardLispBignum.java
/*
 * Jatha - a Common LISP-compatible LISP library in Java.
 * Copyright (C) 1997-2005 Micheal Scott Hewett
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * For further information, please contact Micheal Hewett at
 *   hewett@cs.stanford.edu
 *
 */

package org.jatha.dynatype;

import java.io.PrintStream;
import java.math.BigInteger;

import org.jatha.Jatha;



//------------------------------  LispBignum  -------------------------------

/**
 * Implements BigNums - large integers.
 */
public class StandardLispBignum extends StandardLispInteger implements LispBignum
{

  private  BigInteger value;

  // ---  static initializer  ---

  // ---  Constructors  ---

  public StandardLispBignum()
  {
    super();
  }

  public StandardLispBignum(Jatha lisp, BigInteger  theValue)
  {
    super(lisp);
    value = theValue;
  }

  public StandardLispBignum(Jatha lisp, long   theValue)
  {
    super(lisp);
    value = BigInteger.valueOf(theValue);
  }


  public StandardLispBignum(Jatha lisp, double theValue)
  {
    super(lisp);
    value = BigInteger.valueOf((long)theValue);
  }


  public StandardLispBignum(Jatha lisp)
  {
    super(lisp);
    value = ZERO;
  }

  public double  getDoubleValue()
  {
    return value.doubleValue();
  }

  public BigInteger getBigIntegerValue()
  {
    return value;
  }

  public long getLongValue()
  {
    return value.longValue();
  }

  public void    internal_princ(PrintStream os) { os.print(value); }
  public void    internal_prin1(PrintStream os) { os.print(value); }
  public void    internal_print(PrintStream os) { os.print(value); }
  public boolean basic_bignump()   { return true; }
  public boolean basic_integerp()  { return true; }


  /**
   * Returns a Java Double, Float or Integer object,
   * depending on the typeHint.
   */
  public Object toJava(String typeHint)
  {
    if (typeHint == null)
      return toJava();

    else if (typeHint.equalsIgnoreCase("Double"))
      return new Double(getDoubleValue());

    else if (typeHint.equalsIgnoreCase("Float"))
      return new Float(getDoubleValue());

    else if (typeHint.equalsIgnoreCase("Integer"))
      return new Integer((int)(getLongValue()));

    else if (typeHint.equalsIgnoreCase("Long"))
      return new Long(getLongValue());

    else
      return value;
  }


  public String  toString() { return value.toString(); }


  // ---  LISP methods  ---

  /**
   * Bignum implementation of abs.
   */
  public LispValue abs()
  {
    if (this.value.signum() > 0)
      return this;
    else
      return new StandardLispBignum(f_lisp, this.value.negate());
  }


  public LispValue eql(LispValue val)
  {
    if (val instanceof LispBignum)
      if (value.equals(((LispBignum)val).getBigIntegerValue()))
        return f_lisp.T;
      else
        return f_lisp.NIL;

    if (val instanceof LispInteger)
    {
      LispBignum n = new StandardLispBignum(f_lisp, ((LispInteger)val).getLongValue());
      if (value.equals(n.getBigIntegerValue()))
        return f_lisp.T;
      else
        return f_lisp.NIL;
    }

    if (val instanceof LispReal)
    {
      LispReal r = ((LispReal)val);

      if (StrictMath.round(r.getDoubleValue()) != r.getDoubleValue())  // If not integral
        return f_lisp.NIL;

      LispBignum n = new StandardLispBignum(f_lisp, r.getDoubleValue());
      if (value.equals(n.getBigIntegerValue()))
        return f_lisp.T;
      else
        return f_lisp.NIL;
    }


    return super.eql(val);
  }


  public LispValue equal(LispValue val)
  {
    return eql(val);
  }


  public LispValue     add         (LispValue  args)
  {
    // Args is a list of numbers that has already been evaluated.
    // Terminate if we hit any non-numbers.
    BigInteger sum = this.value;
    LispValue addend;

    while (args != f_lisp.NIL)
    {
      // System.out.println("LispBignum.add: " + sum + " and " + args);
      addend = args.car();
      if (addend.numberp() != f_lisp.T)
      {
        this.add(args.car());
        return(f_lisp.NIL);
      }

      // If an addend is a float, we need to convert the
      // pending result to a LispReal and add the rest of
      // the numbers as reals.
      if (addend.floatp() == f_lisp.T)
      {
        // Do we print a warning?
        LispReal realValue = f_lisp.makeReal(this.getDoubleValue());
        return realValue.add(args);
      }

      if (addend instanceof LispBignum)
        sum = sum.add(((LispBignum)addend).getBigIntegerValue());
      else // must be an integer
        sum = sum.add(BigInteger.valueOf(((LispInteger)addend).getLongValue()));

      args = args.cdr();
    };

    if ((sum.compareTo(MAXINT) <= 0)    // If LispInteger size...
            && (sum.compareTo(MININT) >= 0))
      return (f_lisp.makeInteger(sum.longValue()));
    else
      return (f_lisp.makeBignum(sum));
  }


  // @author  Micheal S. Hewett    hewett@cs.stanford.edu
  /**
   * DIVIDE adds any combination of real or integer numbers.
   *
   * @see LispReal
   * @see LispInteger
   *
   */
  public LispValue     divide      (LispValue   args)
  {
    BigInteger quotient    = this.getBigIntegerValue();
    BigInteger quotientAndRem[];
    BigInteger term_value;
    LispValue  term;
    int        argCount     = 1;

    while (args != f_lisp.NIL)
    {
      term = args.car();             /* Arglist is already evaluated. */
      if (term.numberp() != f_lisp.T)
      {
        this.divide(args.car());  // generate error
        return(f_lisp.NIL);
      }

      ++argCount;

      // If a term is a float, we need to convert the
      // pending result to a LispReal and divide the rest of
      // the numbers as reals.
      if (term.floatp() == f_lisp.T)
      {
        // Do we print a warning?
        LispReal realValue = f_lisp.makeReal(quotient.doubleValue());
        return realValue.divide(args);
      }


      // Do integer divide and check result.
      if (! (term instanceof LispBignum))
        term = new StandardLispBignum(f_lisp, ((LispInteger)term).getLongValue());

      term_value = ((LispBignum)term).getBigIntegerValue();

      if (term_value.compareTo(ZERO) != 0)
      {
        quotientAndRem = quotient.divideAndRemainder(term_value);
        if (quotientAndRem[1].compareTo(ZERO) != 0)
        {
          // Won't divide evenly, so convert to a real.
          return f_lisp.makeReal(quotient.doubleValue()).divide(args);
        }
        else
          quotient = quotientAndRem[0];
      }
      else
      {
        System.out.print("\n;; *** ERROR: Attempt to divide by 0.\n");
        return(f_lisp.NIL);
      }

      args = args.cdr();
    }

    if (argCount == 1)           /* Have to handle n-arg differently from 1-arg */
      if (quotient.compareTo(ZERO) != 0)
        return (f_lisp.makeReal(1.0 / quotient.doubleValue()));
      else
      {
        System.out.print("\n;; *** ERROR: Attempt to divide by 0.\n");
        return(f_lisp.NIL);
      }


    if ((quotient.compareTo(MAXINT) <= 0)    // If LispInteger size...
            && (quotient.compareTo(MININT) >= 0))
      return (f_lisp.makeInteger(quotient.longValue()));
    else
      return (f_lisp.makeBignum(quotient));
  }


  // @author  Micheal S. Hewett    hewett@cs.stanford.edu
    // 20050520 - fixed an error if args is not a list, but a single value instead.
  /**
   * MULTIPLY adds any combination of real or integer numbers.
   *
   * @see LispReal
   * @see LispInteger
   */
  public LispValue     multiply    (LispValue  args)
  {
    BigInteger product     = this.getBigIntegerValue();
    LispValue  term,arglist;

    // Make sure the argument is a list of numbers.
    arglist = args;
    if (! (arglist instanceof LispConsOrNil))
      arglist = f_lisp.makeList(arglist);

    while (arglist != f_lisp.NIL)
    {
      term = arglist.car();

      // Generate an error if the multiplicand is not a number.
      if (term.numberp() != f_lisp.T)
      {
        super.multiply(arglist.car());  // generates an error
        return(f_lisp.NIL);
      }

      // If a term is a float, we need to convert the
      // pending result to a LispReal and multiply the rest of
      // the numbers as reals.
      if (term.floatp() == f_lisp.T)
      {
        // Do we print a warning?
        LispReal realValue = f_lisp.makeReal(this.getDoubleValue());
        return realValue.multiply(arglist);
      }

      if (term instanceof LispBignum)
      {
        //System.out.print("Bignum: multiplying " + this + " by Bignum " + ((LispBignum)term).getBigIntegerValue());
        product = product.multiply(((LispBignum)term).getBigIntegerValue());
        //System.out.println(", producing " + product);
      }
      else // (term instanceof LispInteger)
      {
        //System.out.print("Bignum: multiplying " + this + " by Integer " + ((LispInteger)term).getLongValue());
        product = product.multiply(BigInteger.valueOf(((LispInteger)term).getLongValue()));
        //System.out.println(", producing " + product);
      }

      arglist = arglist.cdr();
    };

    if ((product.compareTo(MAXINT) <= 0)    // If LispInteger size...
            && (product.compareTo(MININT) >= 0))
      return (f_lisp.makeInteger(product.longValue()));
    else
      return (f_lisp.makeBignum(product));
  }


  // @author  Micheal S. Hewett    hewett@cs.stanford.edu
  /**
   * SUBTRACT adds any combination of real or integer numbers.
   *
   * @see LispReal
   * @see LispInteger
   */
  public LispValue     subtract         (LispValue  args)
  {
    // Args is a list of numbers that has already been evaluated.
    // Terminate if we hit any non-numbers.
    BigInteger sum = this.value.negate();
    LispValue term;
    int       argCount = 1;

    while (args != f_lisp.NIL)
    {
      // System.out.println("LispBignum.subtract: " + sum + " and " + args);
      term = args.car();
      if (term.numberp() != f_lisp.T)
      {
        this.subtract(args.car());  // generate error
        return(f_lisp.NIL);
      }

      // If a term is a float, we need to convert the
      // pending result to a LispReal and add the rest of
      // the numbers as reals.
      if (term.floatp() == f_lisp.T)
      {
        // Do we print a warning?
        LispReal realValue = f_lisp.makeReal(this.getDoubleValue());
        return realValue.subtract(args);
      }

      ++argCount;

      if (argCount == 2)
        sum = sum.negate();

      if (term instanceof LispBignum)
        sum = sum.subtract(((LispBignum)term).getBigIntegerValue());
      else // (term instanceof LispInteger)
        sum = sum.subtract(BigInteger.valueOf(((LispInteger)term).getLongValue()));

      args = args.cdr();
    };


    if ((sum.compareTo(MAXINT) <= 0)    // If LispInteger size...
            && (sum.compareTo(MININT) >= 0))
      return (f_lisp.makeInteger(sum.longValue()));
    else
      return (f_lisp.makeBignum(sum));
  }



  public LispValue bignump   ()  { return f_lisp.T; }
  public LispValue integerp  ()  { return f_lisp.T; }

  public LispValue negate()
  {
    return new StandardLispBignum(f_lisp, value.negate());
  }
  

  public LispValue type_of   ()  { return f_lisp.BIGNUM_TYPE;   }
  public LispValue typep(LispValue type)
  {
    LispValue result = super.typep(type);

    if ((result == f_lisp.T) || (type == f_lisp.BIGNUM_TYPE))
      return f_lisp.T;
    else
      return f_lisp.NIL;
  }

  public LispValue zerop     ()
  {
    if (value.equals(ZERO))
      return f_lisp.T;
    else
      return f_lisp.NIL;
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.