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
-~----------~----~----~----~------~----~------~--~---

Reply via email to