In January Mark Engelberg brought up the subject of certain "missing" math functions and provided some nice code to fix the situation. [1] I'm still pretty new to Clojure, and I don't understand all of the ins and outs of Mark's code, but I've come up with implementations of a couple of functions (namely "floor" and "ceiling") that seem to do the right thing but don't jump through all of the hoops as his multimethods do. I believe that as long as "quot" and "rem" do the right thing then my code does too. By "the right thing" here, I mean basically the result type is what "quot" does: user=> (class (quot 8.2 3.4)) java.lang.Integer user=> (class (quot 8.2M 3.4)) java.lang.Integer user=> (class (quot 8.2M 2)) java.math.BigDecimal user=> (class (quot (bigint 83) (bigint 2))) java.math.BigInteger user=> (class (quot (bigint 83) 2)) java.math.BigInteger user=> (class (quot 83 2)) java.lang.Integer
I guess it's trying to preserve the "exactness" of its input, so BigDecimal/Integer => BigDecimal but BigDecimal/Double is already "tainted" by inexactiude, and an Integer output is sufficient. I have based my versions on the behavior of FLOOR and CEILING in Common Lisp. In particular, each function takes a number and an optional divisor (1 by default). Unfortunately, since Clojure does not support multiple return values I have to call both "quot" and "rem" rather than capturing both from a single call to TRUNCATE as in CL. (defn floor ([p] (floor p 1)) ([p d] (let [q (quot p d) r (rem p d)] (if (neg? (* r d)) (- q 1) q)))) (defn ceiling ([p] (ceiling p 1)) ([p d] (let [q (quot p d) r (rem p d)] (if (pos? (* r d)) (+ q 1) q)))) user=> (class (floor 8.2M 3.4)) java.lang.Integer user=> (class (floor 8.2M 2)) java.math.BigDecimal user=> (class (floor (bigint 83) (bigint 2))) java.math.BigInteger By contrast with Common Lisp, these functions behave more like FFLOOR and FCEILING when given a BigDecimal arg, in other words, the return value is an integer value but not an integer type. However, this is how "quot" differs from TRUNCATE as well. Am I missing something (likely), or is this approach feasible? On a related note, shouldn't "quot" and "rem" also take an optional divisor? It seems tiresome to do (quot 8.2 1). An alternative would be to use "int" to truncate a number, but in certain cases "bigint" would be appropriate. A single-argument "quot" should be able to return the right type. Finally, Mark discussed the difference in behavior between Java's Math.round (0.5 rounded up) and CL's ROUND (0.5 rounded to nearest even int). Is this an issue? Should Clojure simply follow Java here? Aloha, David Sletten [1] http://groups.google.com/group/clojure/browse_frm/thread/ 416aafd8e1858c77 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---