summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-04-08 20:18:01 +0000
committerRich Hickey <richhickey@gmail.com>2008-04-08 20:18:01 +0000
commit182e2a0458c8c13704b6de0d235792cbd5e7ae63 (patch)
tree3128f98176f8ba8c897cbd17119316cb59a74d02 /src
parentef4136b83f4ac033e7b38aaf4a2f2a9160d68135 (diff)
added with-precision patch from Christophe Grand
Diffstat (limited to 'src')
-rw-r--r--src/boot.clj18
-rw-r--r--src/jvm/clojure/lang/Numbers.java43
-rw-r--r--src/jvm/clojure/lang/RT.java2
3 files changed, 54 insertions, 9 deletions
diff --git a/src/boot.clj b/src/boot.clj
index c9afa590..15323ab9 100644
--- a/src/boot.clj
+++ b/src/boot.clj
@@ -2284,4 +2284,20 @@ not-every? (comp not every?))
once, but any effects on Refs will be atomic."
[& exprs]
`(sync nil ~@exprs))
- \ No newline at end of file
+
+(defmacro with-precision
+ "Sets the precision and rounding mode to be used for BigDecimal operations.
+ Usage: (with-precision 10 (/ 1M 3))
+ or: (with-precision 10 :rounding HALF_DOWN (/ 1M 3))
+ The rounding mode is one of CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN,
+ UP, DOWN and UNNECESSARY; it defaults to HALF_UP."
+ [precision & exprs]
+ (let [[body mc]
+ (if (= (first exprs) :rounding)
+ [(rest (rest exprs))
+ (java.math.MathContext. precision
+ (. clojure.lang.Reflector getStaticField java.math.RoundingMode (name (second exprs))))]
+ [exprs
+ (java.math.MathContext. precision)])]
+ `(binding [*math-context* ~mc]
+ ~@body))) \ No newline at end of file
diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java
index 91dcefe9..1cf95bb4 100644
--- a/src/jvm/clojure/lang/Numbers.java
+++ b/src/jvm/clojure/lang/Numbers.java
@@ -14,6 +14,7 @@ package clojure.lang;
import java.math.BigInteger;
import java.math.BigDecimal;
+import java.math.MathContext;
public class Numbers{
@@ -628,6 +629,8 @@ final static class BigIntegerOps implements Ops{
}
final static class BigDecimalOps implements Ops{
+ final static Var MATH_CONTEXT = RT.MATH_CONTEXT;
+
public Ops combine(Ops y){
return y.opsWith(this);
}
@@ -655,23 +658,38 @@ final static class BigDecimalOps implements Ops{
}
final public Number add(Number x, Number y){
- return toBigDecimal(x).add(toBigDecimal(y));
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? toBigDecimal(x).add(toBigDecimal(y))
+ : toBigDecimal(x).add(toBigDecimal(y), mc);
}
final public Number multiply(Number x, Number y){
- return toBigDecimal(x).multiply(toBigDecimal(y));
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? toBigDecimal(x).multiply(toBigDecimal(y))
+ : toBigDecimal(x).multiply(toBigDecimal(y), mc);
}
public Number divide(Number x, Number y){
- return toBigDecimal(x).divide(toBigDecimal(y));
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? toBigDecimal(x).divide(toBigDecimal(y))
+ : toBigDecimal(x).divide(toBigDecimal(y), mc);
}
public Number quotient(Number x, Number y){
- return toBigDecimal(x).divideToIntegralValue(toBigDecimal(y));
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? toBigDecimal(x).divideToIntegralValue(toBigDecimal(y))
+ : toBigDecimal(x).divideToIntegralValue(toBigDecimal(y), mc);
}
public Number remainder(Number x, Number y){
- return toBigDecimal(x).remainder(toBigDecimal(y));
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? toBigDecimal(x).remainder(toBigDecimal(y))
+ : toBigDecimal(x).remainder(toBigDecimal(y), mc);
}
public boolean equiv(Number x, Number y){
@@ -684,17 +702,26 @@ final static class BigDecimalOps implements Ops{
//public Number subtract(Number x, Number y);
final public Number negate(Number x){
- return ((BigDecimal)x).negate();
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
+ return mc == null
+ ? ((BigDecimal)x).negate()
+ : ((BigDecimal)x).negate(mc);
}
public Number inc(Number x){
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
BigDecimal bx = (BigDecimal) x;
- return bx.add(BigDecimal.ONE);
+ return mc == null
+ ? bx.add(BigDecimal.ONE)
+ : bx.add(BigDecimal.ONE, mc);
}
public Number dec(Number x){
+ MathContext mc = (MathContext) MATH_CONTEXT.get();
BigDecimal bx = (BigDecimal) x;
- return bx.subtract(BigDecimal.ONE);
+ return mc == null
+ ? bx.subtract(BigDecimal.ONE)
+ : bx.subtract(BigDecimal.ONE, mc);
}
}
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index ed4de6b7..461763ee 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -115,6 +115,7 @@ final static public Var IN =
final static Keyword TAG_KEY = Keyword.intern(null, "tag");
final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
final static public Var MACRO_META = Var.intern(CLOJURE_NS, Symbol.create("*macro-meta*"), null);
+final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
static Keyword LINE_KEY = Keyword.intern(null, "line");
static Keyword FILE_KEY = Keyword.intern(null, "file");
//final static public Var CURRENT_MODULE = Var.intern(Symbol.create("clojure", "current-module"),
@@ -198,6 +199,7 @@ static
Symbol namesym = Symbol.create("name");
OUT.setTag(Symbol.create("java.io.Writer"));
CURRENT_NS.setTag(Symbol.create("clojure.lang.Namespace"));
+ MATH_CONTEXT.setTag(Symbol.create("java.math.MathContext"));
Var v;
v = Var.intern(CLOJURE_NS, IN_NAMESPACE, inNamespace);
v.setMeta(map(dockw, "Sets *ns* to the namespace named by the symbol, creating it if needed.",