summaryrefslogtreecommitdiff
path: root/src/cli/runtime/Num.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/runtime/Num.cs')
-rw-r--r--src/cli/runtime/Num.cs252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/cli/runtime/Num.cs b/src/cli/runtime/Num.cs
new file mode 100644
index 00000000..86120be1
--- /dev/null
+++ b/src/cli/runtime/Num.cs
@@ -0,0 +1,252 @@
+/**
+ * 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 */
+
+using System;
+using java.math;
+
+namespace org.clojure.runtime
+{
+
+public abstract class Num : IComparable /* TODO: , IConvertible*/
+ {
+
+public static Num ZERO = from(0);
+public 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 <= Int32.MaxValue && val >= Int32.MinValue)
+ 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);
+ }
+
+ internal static BigInteger BIGTEN = BigInteger.valueOf(10);
+
+static public Num from(Object x)
+ {
+ if(x is Num)
+ return (Num) x;
+ else
+ {
+ IConvertible c = x as IConvertible;
+ if(c != null)
+ {
+ switch(c.GetTypeCode())
+ {
+ case TypeCode.Int32:
+ return Num.from((Int32) x);
+ case TypeCode.Double:
+ case TypeCode.Single:
+ return Num.from(Convert.ToDouble(x));
+ case TypeCode.Int64:
+ return Num.from((Int64) x);
+ //TODO: Decimal w/o string conversion
+ case TypeCode.Decimal:
+ BigDecimal d = new BigDecimal(x.ToString());
+ return Num.divide(d.movePointRight(d.scale()).toBigInteger(),
+ BIGTEN.pow(d.scale()));
+ default:
+ return Num.from(Convert.ToInt32(x));
+ }
+ }
+ else if(x is BigInteger)
+ return Num.from((BigInteger) x);
+ else
+ throw new ArgumentException("Cannot convert argument: " + x + " to Num");
+ }
+ }
+
+
+ abstract public double doubleValue();
+
+ abstract public float floatValue();
+
+ abstract public int intValue();
+
+ abstract public long longValue();
+
+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]));
+ }
+
+ internal static BigInteger BIG_ONE = BigInteger.valueOf(1);
+ internal static BigInteger BIG_ZERO = BigInteger.valueOf(0);
+
+static public Num divide(BigInteger n, BigInteger d)
+ {
+ BigInteger gcd = n.gcd(d);
+ if(gcd.Equals(BIG_ZERO))
+ return Num.ZERO;
+ n = n.divide(gcd);
+ d = d.divide(gcd);
+ if(d.Equals(BIG_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)
+ {
+ 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)
+ {
+ return Num.from(x).lt(Num.from(y));
+ }
+
+static public Boolean lte(Object x, Object y)
+ {
+ 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)
+ {
+ return Num.from(y).lt(Num.from(x));
+ }
+
+static public Boolean gte(Object x, Object y)
+ {
+ Num lx = Num.from(x);
+ Num ly = Num.from(y);
+ return ly.lt(lx) || lx.equiv(ly);
+ }
+
+abstract public Boolean lt(Num rhs);
+
+abstract public Boolean gt(int x);
+
+abstract public Boolean gt(BigInteger x);
+
+abstract public Boolean gt(RatioNum x);
+
+static public Num negate(Object x)
+ {
+ return Num.from(x).negate();
+ }
+
+abstract public Num negate();
+
+abstract public Boolean minusp();
+
+abstract public Boolean plusp();
+
+abstract public Num oneMinus();
+
+abstract public Num onePlus();
+
+public int CompareTo(Object obj)
+ {
+ Num other = Num.from(obj);
+ if(this.equiv(other))
+ return 0;
+ else if(this.lt(other))
+ return -1;
+ else
+ return 1;
+ }
+}
+}