Mercurial > lasercutter
diff src/clojure/contrib/math.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/math.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,247 @@ 1.4 +;;; math.clj: math functions that deal intelligently with the various 1.5 +;;; types in Clojure's numeric tower, as well as math functions 1.6 +;;; commonly found in Scheme implementations. 1.7 + 1.8 +;; by Mark Engelberg (mark.engelberg@gmail.com) 1.9 +;; January 17, 2009 1.10 + 1.11 +;; expt - (expt x y) is x to the yth power, returns an exact number 1.12 +;; if the base is an exact number, and the power is an integer, 1.13 +;; otherwise returns a double. 1.14 +;; abs - (abs n) is the absolute value of n 1.15 +;; gcd - (gcd m n) returns the greatest common divisor of m and n 1.16 +;; lcm - (lcm m n) returns the least common multiple of m and n 1.17 + 1.18 +;; The behavior of the next three functions on doubles is consistent 1.19 +;; with the behavior of the corresponding functions 1.20 +;; in Java's Math library, but on exact numbers, returns an integer. 1.21 + 1.22 +;; floor - (floor n) returns the greatest integer less than or equal to n. 1.23 +;; If n is an exact number, floor returns an integer, 1.24 +;; otherwise a double. 1.25 +;; ceil - (ceil n) returns the least integer greater than or equal to n. 1.26 +;; If n is an exact number, ceil returns an integer, 1.27 +;; otherwise a double. 1.28 +;; round - (round n) rounds to the nearest integer. 1.29 +;; round always returns an integer. round rounds up for values 1.30 +;; exactly in between two integers. 1.31 + 1.32 + 1.33 +;; sqrt - Implements the sqrt behavior I'm accustomed to from PLT Scheme, 1.34 +;; specifically, if the input is an exact number, and is a square 1.35 +;; of an exact number, the output will be exact. The downside 1.36 +;; is that for the common case (inexact square root), some extra 1.37 +;; computation is done to look for an exact square root first. 1.38 +;; So if you need blazingly fast square root performance, and you 1.39 +;; know you're just going to need a double result, you're better 1.40 +;; off calling java's Math/sqrt, or alternatively, you could just 1.41 +;; convert your input to a double before calling this sqrt function. 1.42 +;; If Clojure ever gets complex numbers, then this function will 1.43 +;; need to be updated (so negative inputs yield complex outputs). 1.44 +;; exact-integer-sqrt - Implements a math function from the R6RS Scheme 1.45 +;; standard. (exact-integer-sqrt k) where k is a non-negative integer, 1.46 +;; returns [s r] where k = s^2+r and k < (s+1)^2. In other words, it 1.47 +;; returns the floor of the square root and the "remainder". 1.48 + 1.49 +(ns 1.50 + ^{:author "Mark Engelberg", 1.51 + :doc "Math functions that deal intelligently with the various 1.52 +types in Clojure's numeric tower, as well as math functions 1.53 +commonly found in Scheme implementations. 1.54 + 1.55 +expt - (expt x y) is x to the yth power, returns an exact number 1.56 + if the base is an exact number, and the power is an integer, 1.57 + otherwise returns a double. 1.58 +abs - (abs n) is the absolute value of n 1.59 +gcd - (gcd m n) returns the greatest common divisor of m and n 1.60 +lcm - (lcm m n) returns the least common multiple of m and n 1.61 + 1.62 +The behavior of the next three functions on doubles is consistent 1.63 +with the behavior of the corresponding functions 1.64 +in Java's Math library, but on exact numbers, returns an integer. 1.65 + 1.66 +floor - (floor n) returns the greatest integer less than or equal to n. 1.67 + If n is an exact number, floor returns an integer, 1.68 + otherwise a double. 1.69 +ceil - (ceil n) returns the least integer greater than or equal to n. 1.70 + If n is an exact number, ceil returns an integer, 1.71 + otherwise a double. 1.72 +round - (round n) rounds to the nearest integer. 1.73 + round always returns an integer. round rounds up for values 1.74 + exactly in between two integers. 1.75 + 1.76 + 1.77 +sqrt - Implements the sqrt behavior I'm accustomed to from PLT Scheme, 1.78 + specifically, if the input is an exact number, and is a square 1.79 + of an exact number, the output will be exact. The downside 1.80 + is that for the common case (inexact square root), some extra 1.81 + computation is done to look for an exact square root first. 1.82 + So if you need blazingly fast square root performance, and you 1.83 + know you're just going to need a double result, you're better 1.84 + off calling java's Math/sqrt, or alternatively, you could just 1.85 + convert your input to a double before calling this sqrt function. 1.86 + If Clojure ever gets complex numbers, then this function will 1.87 + need to be updated (so negative inputs yield complex outputs). 1.88 +exact-integer-sqrt - Implements a math function from the R6RS Scheme 1.89 + standard. (exact-integer-sqrt k) where k is a non-negative integer, 1.90 + returns [s r] where k = s^2+r and k < (s+1)^2. In other words, it 1.91 + returns the floor of the square root and the "remainder". 1.92 +"} 1.93 + clojure.contrib.math) 1.94 + 1.95 +(derive ::integer ::exact) 1.96 +(derive java.lang.Integer ::integer) 1.97 +(derive java.math.BigInteger ::integer) 1.98 +(derive java.lang.Long ::integer) 1.99 +(derive java.math.BigDecimal ::exact) 1.100 +(derive clojure.lang.Ratio ::exact) 1.101 +(derive java.lang.Double ::inexact) 1.102 +(derive java.lang.Float ::inexact) 1.103 + 1.104 +(defmulti ^{:arglists '([base pow]) 1.105 + :doc "(expt base pow) is base to the pow power. 1.106 +Returns an exact number if the base is an exact number and the power is an integer, otherwise returns a double."} 1.107 + expt (fn [x y] [(class x) (class y)])) 1.108 + 1.109 +(defn- expt-int [base pow] 1.110 + (loop [n pow, y (num 1), z base] 1.111 + (let [t (bit-and n 1), n (bit-shift-right n 1)] 1.112 + (cond 1.113 + (zero? t) (recur n y (* z z)) 1.114 + (zero? n) (* z y) 1.115 + :else (recur n (* z y) (* z z)))))) 1.116 + 1.117 +(defmethod expt [::exact ::integer] [base pow] 1.118 + (cond 1.119 + (pos? pow) (expt-int base pow) 1.120 + (zero? pow) 1 1.121 + :else (/ 1 (expt-int base (- pow))))) 1.122 + 1.123 +(defmethod expt :default [base pow] (Math/pow base pow)) 1.124 + 1.125 +(defn abs "(abs n) is the absolute value of n" [n] 1.126 + (cond 1.127 + (not (number? n)) (throw (IllegalArgumentException. 1.128 + "abs requires a number")) 1.129 + (neg? n) (- n) 1.130 + :else n)) 1.131 + 1.132 +(defmulti ^{:arglists '([n]) 1.133 + :doc "(floor n) returns the greatest integer less than or equal to n. 1.134 +If n is an exact number, floor returns an integer, otherwise a double."} 1.135 + floor class) 1.136 +(defmethod floor ::integer [n] n) 1.137 +(defmethod floor java.math.BigDecimal [n] (.. n (setScale 0 BigDecimal/ROUND_FLOOR) (toBigInteger))) 1.138 +(defmethod floor clojure.lang.Ratio [n] 1.139 + (if (pos? n) (quot (. n numerator) (. n denominator)) 1.140 + (dec (quot (. n numerator) (. n denominator))))) 1.141 +(defmethod floor :default [n] 1.142 + (Math/floor n)) 1.143 + 1.144 +(defmulti ^{:arglists '([n]) 1.145 + :doc "(ceil n) returns the least integer greater than or equal to n. 1.146 +If n is an exact number, ceil returns an integer, otherwise a double."} 1.147 + ceil class) 1.148 +(defmethod ceil ::integer [n] n) 1.149 +(defmethod ceil java.math.BigDecimal [n] (.. n (setScale 0 BigDecimal/ROUND_CEILING) (toBigInteger))) 1.150 +(defmethod ceil clojure.lang.Ratio [n] 1.151 + (if (pos? n) (inc (quot (. n numerator) (. n denominator))) 1.152 + (quot (. n numerator) (. n denominator)))) 1.153 +(defmethod ceil :default [n] 1.154 + (Math/ceil n)) 1.155 + 1.156 +(defmulti ^{:arglists '([n]) 1.157 + :doc "(round n) rounds to the nearest integer. 1.158 +round always returns an integer. Rounds up for values exactly in between two integers."} 1.159 + round class) 1.160 +(defmethod round ::integer [n] n) 1.161 +(defmethod round java.math.BigDecimal [n] (floor (+ n 0.5M))) 1.162 +(defmethod round clojure.lang.Ratio [n] (floor (+ n 1/2))) 1.163 +(defmethod round :default [n] (Math/round n)) 1.164 + 1.165 +(defn gcd "(gcd a b) returns the greatest common divisor of a and b" [a b] 1.166 + (if (or (not (integer? a)) (not (integer? b))) 1.167 + (throw (IllegalArgumentException. "gcd requires two integers")) 1.168 + (loop [a (abs a) b (abs b)] 1.169 + (if (zero? b) a, 1.170 + (recur b (mod a b)))))) 1.171 + 1.172 +(defn lcm 1.173 + "(lcm a b) returns the least common multiple of a and b" 1.174 + [a b] 1.175 + (when (or (not (integer? a)) (not (integer? b))) 1.176 + (throw (IllegalArgumentException. "lcm requires two integers"))) 1.177 + (cond (zero? a) 0 1.178 + (zero? b) 0 1.179 + :else (abs (* b (quot a (gcd a b)))))) 1.180 + 1.181 +; Length of integer in binary, used as helper function for sqrt. 1.182 +(defmulti ^{:private true} integer-length class) 1.183 +(defmethod integer-length java.lang.Integer [n] 1.184 + (count (Integer/toBinaryString n))) 1.185 +(defmethod integer-length java.lang.Long [n] 1.186 + (count (Long/toBinaryString n))) 1.187 +(defmethod integer-length java.math.BigInteger [n] 1.188 + (count (. n toString 2))) 1.189 + 1.190 +;; Produces the largest integer less than or equal to the square root of n 1.191 +;; Input n must be a non-negative integer 1.192 +(defn- integer-sqrt [n] 1.193 + (cond 1.194 + (> n 24) 1.195 + (let [n-len (integer-length n)] 1.196 + (loop [init-value (if (even? n-len) 1.197 + (bit-shift-left 1 (bit-shift-right n-len 1)) 1.198 + (bit-shift-left 2 (bit-shift-right n-len 1)))] 1.199 + (let [iterated-value (bit-shift-right (+ init-value (quot n init-value)) 1)] 1.200 + (if (>= iterated-value init-value) 1.201 + init-value 1.202 + (recur iterated-value))))) 1.203 + (> n 15) 4 1.204 + (> n 8) 3 1.205 + (> n 3) 2 1.206 + (> n 0) 1 1.207 + (> n -1) 0)) 1.208 + 1.209 +(defn exact-integer-sqrt "(exact-integer-sqrt n) expects a non-negative integer n, and returns [s r] where n = s^2+r and n < (s+1)^2. In other words, it returns the floor of the square root and the 'remainder'. 1.210 +For example, (exact-integer-sqrt 15) is [3 6] because 15 = 3^2+6." 1.211 + [n] 1.212 + (if (or (not (integer? n)) (neg? n)) 1.213 + (throw (IllegalArgumentException. "exact-integer-sqrt requires a non-negative integer")) 1.214 + (let [isqrt (integer-sqrt n), 1.215 + error (- n (* isqrt isqrt))] 1.216 + [isqrt error]))) 1.217 + 1.218 +(defmulti ^{:arglists '([n]) 1.219 + :doc "Square root, but returns exact number if possible."} 1.220 + sqrt class) 1.221 +(defmethod sqrt ::integer [n] 1.222 + (if (neg? n) Double/NaN 1.223 + (let [isqrt (integer-sqrt n), 1.224 + error (- n (* isqrt isqrt))] 1.225 + (if (zero? error) isqrt 1.226 + (Math/sqrt n))))) 1.227 + 1.228 +(defmethod sqrt clojure.lang.Ratio [n] 1.229 + (if (neg? n) Double/NaN 1.230 + (let [numerator (.numerator n), 1.231 + denominator (.denominator n), 1.232 + sqrtnum (sqrt numerator)] 1.233 + (if (float? sqrtnum) 1.234 + (Math/sqrt n) 1.235 + (let [sqrtden (sqrt denominator)] 1.236 + (if (float? sqrtnum) 1.237 + (Math/sqrt n) 1.238 + (/ sqrtnum sqrtden))))))) 1.239 + 1.240 +(defmethod sqrt java.math.BigDecimal [n] 1.241 + (if (neg? n) Double/NaN 1.242 + (let [frac (rationalize n), 1.243 + sqrtfrac (sqrt frac)] 1.244 + (if (ratio? sqrtfrac) 1.245 + (/ (BigDecimal. (.numerator sqrtfrac)) 1.246 + (BigDecimal. (.denominator sqrtfrac))) 1.247 + sqrtfrac)))) 1.248 + 1.249 +(defmethod sqrt :default [n] 1.250 + (Math/sqrt n))