diff options
Diffstat (limited to 'src/org/clojure/runtime/Num.java')
-rw-r--r-- | src/org/clojure/runtime/Num.java | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/org/clojure/runtime/Num.java b/src/org/clojure/runtime/Num.java new file mode 100644 index 00000000..688fb0b4 --- /dev/null +++ b/src/org/clojure/runtime/Num.java @@ -0,0 +1,164 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Common Public License 1.0 (http://opensource.org/licenses/cpl.php) + * which can be found in the file CPL.TXT at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +/* rich Mar 28, 2006 10:07:33 AM */ + +package org.clojure.runtime; + +import java.math.BigInteger; + +public abstract class Num extends Number { + + public final static Num ZERO = from(0); + public final static Num ONE = from(1); + + static public Num from(int val){ + //todo - cache a bunch of small fixnums + return new FixNum(val); + } + + static public Num from(double val){ + return new DoubleNum(val); + } + + static public Num from(long val){ + if(val <= Integer.MAX_VALUE && val >= Integer.MIN_VALUE) + return from((int)val); + else + return new BigNum(val); + } + + static public Num from(BigInteger val){ + if(val.bitLength() < 32) + return from(val.intValue()); + else + return new BigNum(val); + } + + static public Num from(Object x){ + if(x instanceof Num) + return (Num)x; + else{ + Class c = x.getClass(); + if(c == Integer.class) + return Num.from(((Integer)x).intValue()); + else if(c == Double.class || c == Float.class) + return Num.from(((Number)x).doubleValue()); + else if(c == Long.class) + return Num.from(((Long)x).longValue()); + else if(c == BigInteger.class) + return Num.from((BigInteger)x); + else + return Num.from(((Number)x).intValue()); + } + } + + static public Num add(Object x,Object y){ + //if(x instanceof Num && y instanceof Num) + //return ((Num)x).add((Num) y); + return Num.from(x).add(Num.from(y)); + } + abstract public Num add(Num rhs); + abstract public Num addTo(int x); + abstract public Num addTo(BigInteger x); + abstract public Num addTo(RatioNum x); + + static public Num subtract(Object x,Object y){ + return Num.from(y).subtractFrom(Num.from(x)); + } + //this double-dispatches to addTo(-self) + abstract public Num subtractFrom(Num rhs); + + static public Num multiply(Object x,Object y) { + return Num.from(x).multiplyBy(Num.from(y)); + } + abstract public Num multiplyBy(Num rhs); + abstract public Num multiply(int x); + abstract public Num multiply(BigInteger x); + abstract public Num multiply(RatioNum x); + + static public Num divide(Object x,Object y){ + return Num.from(x).divideBy(Num.from(y)); + } + + abstract public Num divideBy(Num rhs); + abstract public Num divide(int x); + abstract public Num divide(BigInteger x); + abstract public Num divide(RatioNum x); + + static public Object truncate(ThreadLocalData tld, Object num, Object div) { + return Num.from(div).truncateDivide(tld, Num.from(num)); + } + + abstract public Object truncateDivide(ThreadLocalData tld, Num rhs) ; + abstract public Object truncateBy(ThreadLocalData tld, int x) ; + abstract public Object truncateBy(ThreadLocalData tld, BigInteger x) ; + abstract public Object truncateBy(ThreadLocalData tld, RatioNum x) ; + + static public Object truncateBigints(ThreadLocalData tld, BigInteger n, BigInteger d){ + BigInteger[] result = n.divideAndRemainder(d); + return RT.setValues(tld,Num.from(result[0]),Num.from(result[1])); + } + + static public Num divide(BigInteger n,BigInteger d) { + BigInteger gcd = n.gcd(d); + if(gcd.equals(BigInteger.ZERO)) + return Num.ZERO; + n = n.divide(gcd); + d = d.divide(gcd); + if(d.equals(BigInteger.ONE)) + return Num.from(n); + return new RatioNum((IntegerNum)Num.from(d.signum() < 0 ? n.negate():n), + (IntegerNum)Num.from(d.signum() < 0 ? d.negate():d)); + } + + static public boolean equiv(Object x,Object y) throws Exception{ + return Num.from(x).equiv(Num.from(y)); + } + abstract public boolean equiv(Num rhs) ; + abstract public boolean equivTo(int x) ; + abstract public boolean equivTo(BigInteger x) ; + abstract public boolean equivTo(RatioNum x) ; + + static public boolean lt(Object x,Object y) throws Exception{ + return Num.from(x).lt(Num.from(y)); + } + static public boolean lte(Object x,Object y) throws Exception{ + Num lx = Num.from(x); + Num ly = Num.from(y); + return lx.lt(ly) || lx.equiv(ly); + } + + static public boolean gt(Object x,Object y) throws Exception{ + return Num.from(y).lt(Num.from(x)); + } + + static public boolean gte(Object x,Object y) throws Exception{ + Num lx = Num.from(x); + Num ly = Num.from(y); + return ly.lt(lx) || lx.equiv(ly); + } + + abstract public boolean lt(Num rhs) throws Exception; + abstract public boolean gt(int x) throws Exception; + abstract public boolean gt(BigInteger x) throws Exception; + abstract public boolean gt(RatioNum x) throws Exception; + + static public Num negate(Object x) throws Exception{ + return Num.from(x).negate(); + } + abstract public Num negate() throws Exception; + + abstract public boolean minusp(); + abstract public boolean plusp(); + abstract public Num oneMinus(); + abstract public Num onePlus(); + +} |