├── .circleci └── config.yml ├── .github └── CODEOWNERS ├── .gitignore ├── CHANGELOG.adoc ├── ORIGINATOR ├── README.md ├── project.clj ├── src ├── clj_commons │ ├── primitive_math.clj │ └── primitive_math │ │ └── Primitives.java ├── primitive_math.clj └── primitive_math │ └── Primitives.java └── test ├── clj_commons └── primitive_math_test.clj └── primitive_math_test.clj /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | workflows: 4 | build-deploy: 5 | jobs: 6 | - build: 7 | filters: 8 | tags: 9 | only: /.*/ 10 | 11 | - deploy: 12 | requires: 13 | - build 14 | filters: 15 | tags: 16 | only: /Release-.*/ 17 | context: 18 | - CLOJARS_DEPLOY 19 | 20 | jobs: 21 | build: 22 | docker: 23 | # specify the version you desire here 24 | - image: clojure:openjdk-8-lein-2.9.8-bullseye 25 | 26 | # Specify service dependencies here if necessary 27 | # CircleCI maintains a library of pre-built images 28 | # documented at https://circleci.com/docs/2.0/circleci-images/ 29 | # - image: circleci/postgres:9.4 30 | 31 | working_directory: ~/repo 32 | 33 | environment: 34 | LEIN_ROOT: "true" 35 | # Customize the JVM maximum heap limit 36 | JVM_OPTS: -Xmx3200m 37 | 38 | steps: 39 | - checkout 40 | 41 | # Download and cache dependencies 42 | - restore_cache: 43 | keys: 44 | - v1-dependencies-{{ checksum "project.clj" }} 45 | # fallback to using the latest cache if no exact match is found 46 | - v1-dependencies- 47 | 48 | - run: lein deps 49 | 50 | - save_cache: 51 | paths: 52 | - ~/.m2 53 | key: v1-dependencies-{{ checksum "project.clj" }} 54 | 55 | - run: 56 | name: Ensure No Reflection Warnings 57 | command: "! lein check 2>&1 | grep 'Reflection warning'" 58 | 59 | # run tests! 60 | - run: lein do clean, test 61 | 62 | deploy: 63 | docker: 64 | # specify the version you desire here 65 | - image: clojure:openjdk-8-lein-2.9.8-bullseye 66 | # Specify service dependencies here if necessary 67 | # CircleCI maintains a library of pre-built images 68 | # documented at https://circleci.com/docs/2.0/circleci-images/ 69 | # - image: circleci/postgres:9.4 70 | 71 | working_directory: ~/repo 72 | 73 | environment: 74 | LEIN_ROOT: "true" 75 | # Customize the JVM maximum heap limit 76 | JVM_OPTS: -Xmx3200m 77 | 78 | steps: 79 | - checkout 80 | 81 | # Download and cache dependencies 82 | - restore_cache: 83 | keys: 84 | - v1-dependencies-{{ checksum "project.clj" }} 85 | # fallback to using the latest cache if no exact match is found 86 | - v1-dependencies- 87 | 88 | # Download and cache dependencies 89 | - restore_cache: 90 | keys: 91 | - v1-dependencies-{{ checksum "project.clj" }} 92 | # fallback to using the latest cache if no exact match is found 93 | - v1-dependencies- 94 | 95 | - run: 96 | name: Install babashka 97 | command: | 98 | curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install -o install.sh 99 | bash install.sh 100 | rm install.sh 101 | - run: 102 | name: Install deployment-script 103 | command: | 104 | curl -s https://raw.githubusercontent.com/clj-commons/infra/main/deployment/circle-maybe-deploy.bb -o circle-maybe-deploy.bb 105 | chmod a+x circle-maybe-deploy.bb 106 | 107 | - run: lein deps 108 | 109 | - run: 110 | name: Setup GPG signing key 111 | command: | 112 | apt-get update 113 | apt-get install -y make gnupg 114 | GNUPGHOME="$HOME/.gnupg" 115 | export GNUPGHOME 116 | mkdir -p "$GNUPGHOME" 117 | chmod 0700 "$GNUPGHOME" 118 | 119 | echo "$GPG_KEY" \ 120 | | base64 --decode --ignore-garbage \ 121 | | gpg --batch --allow-secret-key-import --import 122 | 123 | gpg --keyid-format LONG --list-secret-keys 124 | 125 | - save_cache: 126 | paths: 127 | - ~/.m2 128 | key: v1-dependencies-{{ checksum "project.clj" }} 129 | - run: 130 | name: Deploy 131 | command: | 132 | GPG_TTY=$(tty) 133 | export GPG_TTY 134 | echo $GPG_TTY 135 | ./circle-maybe-deploy.bb lein deploy clojars 136 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @KingMob 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /lib 3 | /classes 4 | /checkouts 5 | /doc 6 | pom.xml 7 | pom.xml.asc 8 | *.jar 9 | *.class 10 | DS_Store 11 | push 12 | .lein-deps-sum 13 | .lein-failures 14 | .lein-plugins 15 | .lein-repl-history 16 | .nrepl* 17 | .clj-kondo/.cache 18 | .lsp/.cache 19 | .portal/vs-code.edn 20 | -------------------------------------------------------------------------------- /CHANGELOG.adoc: -------------------------------------------------------------------------------- 1 | == Changes 2 | 3 | === 1.0.1 4 | 5 | - Update arglists for docs 6 | - Add declarations to better support linters 7 | - Deprecate single-segment namespace 8 | - Add primitive `rem` versions for float and double 9 | 10 | Contributions by Daniel Compton and Matthew Davidson 11 | 12 | === 0.1.0 - 1.0.0 13 | 14 | Contributions by Zach Tellman, Matthew Davidson, Erik Assum, 15 | Michael du Breuil, and skynet. 16 | -------------------------------------------------------------------------------- /ORIGINATOR: -------------------------------------------------------------------------------- 1 | @ztellman 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Clojars Project](https://img.shields.io/clojars/v/org.clj-commons/primitive-math.svg)](https://clojars.org/org.clj-commons/primitive-math) 2 | [![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/primitive-math)](https://cljdoc.org/d/org.clj-commons/primitive-math) 3 | [![CircleCI](https://circleci.com/gh/clj-commons/primitive-math.svg?style=svg)](https://circleci.com/gh/clj-commons/primitive-math) 4 | 5 | ### About 6 | 7 | Clojure's numeric tower is useful, but it can put a lot of steps between you and simple arithmetic. Unfortunately, while Clojure will warn you when reflection is required to invoke a function, it will **not** warn you when reflection is required to perform math. The only reliable way to discover whether you're calling `clojure.lang.Number.add(Object, Object)` or `clojure.lang.Number.add(long, long)` is to use a profiler or decompiler. 8 | 9 | Or, you can just bypass Clojure's math operators altogether. 10 | 11 | In the `clj-commons.primitive-math` namespace, there are equivalents for every arithmetic operator and comparator that will give a reflection warning if it cannot compile down to a simple, predictable, unboxed mathematical operation. 12 | 13 | ```clojure 14 | clj-commons.primitive-math> (set! *warn-on-reflection* true) 15 | true 16 | clj-commons.primitive-math> (+ 3 3) 17 | 6 18 | clj-commons.primitive-math> (defn adder [x] (+ 1 x)) 19 | ;; gives a reflection warning 20 | clj-commons.primitive-math> (defn adder [^long x] (+ 1 x)) 21 | ;; no reflection warning 22 | clj-commons.primitive-math> (+ 3.0 3) 23 | ;; gives a reflection warning AND throws an exception 24 | ``` 25 | 26 | To support operations on both `long` and `double` types without any reflection, these operators are defined as macros. This means they cannot be used as higher-order functions: 27 | 28 | ```clojure 29 | clj-commons.primitive-math> (apply + [1 2 3]) 30 | ;; throws a 'cannot take value of macro' exception 31 | ``` 32 | 33 | In practice, it's usually preferable to import the namespace with a prefix, and use `p/+` and `p/==` operators alongside the normal Clojure functions. However, if in a particular namespace you never need to use higher-order operators, you can call `(primitive-math/use-primitive-operators)` to swap out the Clojure operators for their primitive equivalents. This can be reversed, using `(primitive-math/unuse-primitive-operators)`. 34 | 35 | ##### Notes 36 | 37 | Pre-1.0.0 versions of primitive-math used a single-segment namespace. This causes problems for Graal and clj-easy. For 1.0.0, everything was copied under the `clj-commons` namespace. The code is effectively identical, however, so unless you are using Graal, you don't need to make any changes. If you *are* using Graal, make sure you only require the `clj-commons.*` namespaces to avoid issues. 38 | 39 | ### Usage 40 | 41 | ```clojure 42 | ;;; Lein 43 | [org.clj-commons/primitive-math "1.0.1"] 44 | 45 | ;;; deps.edn 46 | org.clj-commons/primitive-math {:mvn/version "1.0.1"} 47 | ``` 48 | 49 | ### An exhaustive list of operators 50 | 51 | ```clojure 52 | + 53 | - 54 | * 55 | / ;; aliased as 'div' 56 | inc 57 | dec 58 | rem 59 | == 60 | not== 61 | zero? 62 | <= 63 | >= 64 | < 65 | > 66 | min 67 | max 68 | bool-and 69 | bool-or 70 | bool-not 71 | bool-xor 72 | true? 73 | false? 74 | bit-and 75 | bit-or 76 | bit-xor 77 | bit-not 78 | bit-shift-left ;; aliased as '<<' 79 | bit-shift-right ;; aliased as '>>' 80 | unsigned-bit-shift-right ;; aliased as '>>>' 81 | byte 82 | short 83 | int 84 | float 85 | long 86 | double 87 | byte->ubyte 88 | ubyte->byte 89 | short->ushort 90 | ushort->short 91 | int->uint 92 | uint->int 93 | long->ulong 94 | ulong->long 95 | reverse-short 96 | reverse-int 97 | reverse-long 98 | ``` 99 | 100 | Full documentation can be found at [cljdoc](https://cljdoc.org/d/org.clj-commons/primitive-math). 101 | 102 | ### License 103 | 104 | Copyright © 2016 Zachary Tellman 105 | 106 | Distributed under the [MIT License](http://opensource.org/licenses/MIT). 107 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject org.clj-commons/primitive-math 2 | (or (System/getenv "PROJECT_VERSION") "1.0.1") 3 | :description "Predictable, primitive math" 4 | :url "https://github.com/clj-commons/primitive-math" 5 | :license {:name "MIT License" 6 | :url "http://opensource.org/licenses/MIT"} 7 | :dependencies [] 8 | :deploy-repositories [["clojars" {:url "https://repo.clojars.org" 9 | :username :env/clojars_username 10 | :password :env/clojars_org_clj_commons_password 11 | :sign-releases true}]] 12 | :profiles {:dev {:dependencies [[criterium "0.4.6"] 13 | [org.clojure/clojure "1.11.1"]]}} 14 | :global-vars {*warn-on-reflection* true} 15 | :jvm-opts ^:replace ["-server"] 16 | :java-source-paths ["src"] 17 | :javac-options ["-target" "1.8" "-source" "1.8"]) 18 | -------------------------------------------------------------------------------- /src/clj_commons/primitive_math.clj: -------------------------------------------------------------------------------- 1 | (ns clj-commons.primitive-math 2 | (:refer-clojure 3 | :exclude [* + - / < > <= >= == rem bit-or bit-and bit-xor bit-not bit-shift-left bit-shift-right unsigned-bit-shift-right byte short int float long double inc dec zero? min max true? false?]) 4 | (:import 5 | (clj_commons.primitive_math Primitives) 6 | (java.nio ByteBuffer))) 7 | 8 | ;; Declare the variadic-* macro operators for linters 9 | (declare ^:macro + ^:macro - ^:macro * ^:macro / ^:macro div ^:macro bit-and 10 | ^:macro bit-or ^:macro bit-xor ^:macro bool-and ^:macro bool-or 11 | ^:macro bool-xor ^:macro min ^:macro max ^:macro > ^:macro < 12 | ^:macro <= ^:macro >= ^:macro == ^:macro not==) 13 | 14 | (defmacro ^:private variadic-proxy 15 | "Creates left-associative variadic forms for any operator." 16 | ([name fn] 17 | `(variadic-proxy ~name ~fn ~(str "A primitive macro version of `" name "`"))) 18 | ([name fn doc] 19 | `(variadic-proxy ~name ~fn ~doc identity)) 20 | ([name fn doc single-arg-form] 21 | (let [x-sym (gensym "x")] 22 | `(defmacro ~name 23 | ~doc 24 | {:arglists '([~'x] [~'x ~'y] [~'x ~'y & ~'rest])} 25 | ([~x-sym] 26 | ~((eval single-arg-form) x-sym)) 27 | ([x# y#] 28 | (list '~fn x# y#)) 29 | ([x# y# ~'& rest#] 30 | (list* '~name (list '~name x# y#) rest#)))))) 31 | 32 | (defmacro ^:private variadic-predicate-proxy 33 | "Turns variadic predicates into multiple pair-wise comparisons." 34 | ([name fn] 35 | `(variadic-predicate-proxy ~name ~fn ~(str "A primitive macro version of `" name "`"))) 36 | ([name fn doc] 37 | `(variadic-predicate-proxy ~name ~fn ~doc (constantly true))) 38 | ([name fn doc single-arg-form] 39 | (let [x-sym (gensym "x")] 40 | `(defmacro ~name 41 | ~doc 42 | {:arglists '([~'x] [~'x ~'y] [~'x ~'y & ~'rest])} 43 | ([~x-sym] 44 | ~((eval single-arg-form) x-sym)) 45 | ([x# y#] 46 | (list '~fn x# y#)) 47 | ([x# y# ~'& rest#] 48 | (list 'clj_commons.primitive_math.Primitives/and (list '~name x# y#) (list* '~name y# rest#))))))) 49 | 50 | (variadic-proxy + clj_commons.primitive_math.Primitives/add) 51 | (variadic-proxy - clj_commons.primitive_math.Primitives/subtract "A primitive macro version of `-`" (fn [x] `(list 'clj_commons.primitive_math.Primitives/negate ~x))) 52 | (variadic-proxy * clj_commons.primitive_math.Primitives/multiply) 53 | (variadic-proxy / clj_commons.primitive_math.Primitives/divide) 54 | (variadic-proxy div clj_commons.primitive_math.Primitives/divide) 55 | (variadic-proxy bit-and clj_commons.primitive_math.Primitives/bitAnd) 56 | (variadic-proxy bit-or clj_commons.primitive_math.Primitives/bitOr) 57 | (variadic-proxy bit-xor clj_commons.primitive_math.Primitives/bitXor) 58 | (variadic-proxy bool-and clj_commons.primitive_math.Primitives/and) 59 | (variadic-proxy bool-or clj_commons.primitive_math.Primitives/or) 60 | (variadic-proxy bool-xor clj_commons.primitive_math.Primitives/xor) 61 | (variadic-proxy min clj_commons.primitive_math.Primitives/min) 62 | (variadic-proxy max clj_commons.primitive_math.Primitives/max) 63 | 64 | (variadic-predicate-proxy > clj_commons.primitive_math.Primitives/gt) 65 | (variadic-predicate-proxy < clj_commons.primitive_math.Primitives/lt) 66 | (variadic-predicate-proxy <= clj_commons.primitive_math.Primitives/lte) 67 | (variadic-predicate-proxy >= clj_commons.primitive_math.Primitives/gte) 68 | (variadic-predicate-proxy == clj_commons.primitive_math.Primitives/eq) 69 | (variadic-predicate-proxy not== clj_commons.primitive_math.Primitives/neq "A primitive macro complement of `==`") 70 | 71 | (defmacro inc 72 | "A primitive macro version of `inc`." 73 | [x] 74 | `(Primitives/inc ~x)) 75 | 76 | (defmacro dec 77 | "A primitive macro version of `dec`." 78 | [x] 79 | `(Primitives/dec ~x)) 80 | 81 | (defmacro rem 82 | "A primitive macro version of `rem`." 83 | [n div] 84 | `(Primitives/rem ~n ~div)) 85 | 86 | (defmacro zero? 87 | "A primitive macro version of `zero?`." 88 | [x] 89 | `(Primitives/isZero ~x)) 90 | 91 | (defmacro bool-not 92 | "A primitive macro version of `not`." 93 | [x] 94 | `(Primitives/not ~x)) 95 | 96 | (defmacro bit-not 97 | "A primitive macro version of `bit-not`." 98 | [x] 99 | `(Primitives/bitNot ~x)) 100 | 101 | (defmacro true? 102 | "A primitive macro version of `true?`." 103 | [x] 104 | `(Primitives/isTrue ~x)) 105 | 106 | (defmacro false? 107 | "A primitive macro version of `false?`." 108 | [x] 109 | `(Primitives/isFalse ~x)) 110 | 111 | (defmacro bit-shift-left 112 | "A primitive macro version of `bit-shift-left`." 113 | [n bits] 114 | `(Primitives/shiftLeft ~n ~bits)) 115 | 116 | (defmacro bit-shift-right 117 | "A primitive macro version of `bit-shift-right`." 118 | [n bits] 119 | `(Primitives/shiftRight ~n ~bits)) 120 | 121 | ;; this was the original name, which doesn't match the Clojure name and is kept 122 | ;; around for legacy purposes 123 | (defmacro ^:no-doc bit-unsigned-shift-right 124 | [n bits] 125 | `(Primitives/unsignedShiftRight ~n ~bits)) 126 | 127 | (defmacro unsigned-bit-shift-right 128 | "A primitive macro which performs an unsigned right bit-shift." 129 | [n bits] 130 | `(Primitives/unsignedShiftRight ~n ~bits)) 131 | 132 | (defmacro << 133 | "An alias for `bit-shift-left`." 134 | [n bits] 135 | `(Primitives/shiftLeft ~n ~bits)) 136 | 137 | (defmacro >> 138 | "An alias for `bit-shift-right`." 139 | [n bits] 140 | `(Primitives/shiftRight ~n ~bits)) 141 | 142 | (defmacro >>> 143 | "An alias for `bit-unsigned-shift-right`." 144 | [n bits] 145 | `(Primitives/unsignedShiftRight ~n ~bits)) 146 | 147 | ;;; 148 | 149 | (def ^:private vars-to-exclude 150 | '[* + - / < > <= >= == rem bit-or bit-and bit-xor bit-not bit-shift-left bit-shift-right byte short int float long double inc dec zero? true? false? min max]) 151 | 152 | (defn- using-primitive-operators? [] 153 | (= #'clj-commons.primitive-math/+ (resolve '+))) 154 | 155 | (defonce ^:private hijacked? (atom false)) 156 | 157 | (defn- ns-wrapper 158 | "Makes sure that if a namespace that is using primitive operators is reloaded, it will automatically 159 | exclude the shadowed operators in `clojure.core`." 160 | [f] 161 | (fn [& x] 162 | (if-not (using-primitive-operators?) 163 | (apply f x) 164 | (let [refer-clojure (->> x 165 | (filter #(and (sequential? %) (= :refer-clojure (first %)))) 166 | first) 167 | refer-clojure-clauses (update-in 168 | (apply hash-map (rest refer-clojure)) 169 | [:exclude] 170 | #(concat % vars-to-exclude))] 171 | (apply f 172 | (concat 173 | (remove #{refer-clojure} x) 174 | [(list* :refer-clojure (apply concat refer-clojure-clauses))])))))) 175 | 176 | (defn use-primitive-operators 177 | "Replaces Clojure's arithmetic and number coercion functions with primitive equivalents. These are 178 | defined as macros, so they cannot be used as higher-order functions. This is an idempotent operation.." 179 | [] 180 | (when-not @hijacked? 181 | (reset! hijacked? true) 182 | (alter-var-root #'clojure.core/ns ns-wrapper)) 183 | (when-not (using-primitive-operators?) 184 | (doseq [v vars-to-exclude] 185 | (ns-unmap *ns* v)) 186 | (require (vector 'clj-commons.primitive-math :refer vars-to-exclude)))) 187 | 188 | (defn unuse-primitive-operators 189 | "Undoes the work of `use-primitive-operators`. This is idempotent." 190 | [] 191 | (doseq [v vars-to-exclude] 192 | (ns-unmap *ns* v)) 193 | (refer 'clojure.core)) 194 | 195 | ;;; 196 | 197 | (defn byte 198 | "Truncates a number to a byte, will not check for overflow." 199 | {:inline (fn [x] `(clj_commons.primitive_math.Primitives/toByte ~x))} 200 | ^long [^long x] 201 | (unchecked-long (Primitives/toByte x))) 202 | 203 | (defn short 204 | "Truncates a number to a short, will not check for overflow." 205 | {:inline (fn [x] `(clj_commons.primitive_math.Primitives/toShort ~x))} 206 | ^long [^long x] 207 | (unchecked-long (Primitives/toShort x))) 208 | 209 | (defn int 210 | "Truncates a number to an int, will not check for overflow." 211 | {:inline (fn [x] `(clj_commons.primitive_math.Primitives/toInteger ~x))} 212 | ^long [^long x] 213 | (unchecked-long (Primitives/toInteger x))) 214 | 215 | (defn float 216 | "Truncates a number to a float, will not check for overflow." 217 | {:inline (fn [x] `(clj_commons.primitive_math.Primitives/toFloat ~x))} 218 | ^double [^double x] 219 | (unchecked-double (Primitives/toFloat x))) 220 | 221 | (defn long 222 | "Converts a number to a long." 223 | {:inline (fn [x] `(unchecked-long ~x))} 224 | ^long [x] 225 | (unchecked-long x)) 226 | 227 | (defn double 228 | "Converts a number to a double." 229 | {:inline (fn [x] `(unchecked-double ~x))} 230 | ^double [x] 231 | (unchecked-double x)) 232 | 233 | (defn byte->ubyte 234 | "Converts a byte to an unsigned byte." 235 | {:inline (fn [x] `(->> ~x long (bit-and 0xFF) short))} 236 | ^long [^long x] 237 | (long (short (bit-and x 0xFF)))) 238 | 239 | (defn ubyte->byte 240 | "Converts an unsigned byte to a byte." 241 | {:inline (fn [x] `(byte (long ~x)))} 242 | ^long [^long x] 243 | (long (byte x))) 244 | 245 | (defn short->ushort 246 | "Converts a short to an unsigned short." 247 | {:inline (fn [x] `(->> ~x long (bit-and 0xFFFF) int))} 248 | ^long [^long x] 249 | (long (int (bit-and 0xFFFF x)))) 250 | 251 | (defn ushort->short 252 | "Converts an unsigned short to a short." 253 | {:inline (fn [x] `(short (long ~x)))} 254 | ^long [^long x] 255 | (long (short x))) 256 | 257 | (defn int->uint 258 | "Converts an integer to an unsigned integer." 259 | {:inline (fn [x] `(->> ~x long (bit-and 0xFFFFFFFF)))} 260 | ^long [^long x] 261 | (long (bit-and 0xFFFFFFFF x))) 262 | 263 | (defn uint->int 264 | "Converts an unsigned integer to an integer." 265 | {:inline (fn [x] `(int (long ~x)))} 266 | ^long [^long x] 267 | (long (int x))) 268 | 269 | (defn long->ulong 270 | "Converts a long to an unsigned long." 271 | [^long x] 272 | (BigInteger. 1 273 | (-> (ByteBuffer/allocate 8) (.putLong x) .array))) 274 | 275 | (defn ulong->long 276 | "Converts an unsigned long to a long." 277 | ^long [x] 278 | (.longValue ^clojure.lang.BigInt (bigint x))) 279 | 280 | (defn float->int 281 | "Converts a float to an integer." 282 | {:inline (fn [x] `(Float/floatToRawIntBits (float ~x)))} 283 | ^long [^double x] 284 | (long (Float/floatToRawIntBits x))) 285 | 286 | (defn int->float 287 | "Converts an integer to a float." 288 | {:inline (fn [x] `(Float/intBitsToFloat (int ~x)))} 289 | ^double [^long x] 290 | (double (Float/intBitsToFloat x))) 291 | 292 | (defn double->long 293 | "Converts a double to a long." 294 | {:inline (fn [x] `(Double/doubleToRawLongBits ~x))} 295 | ^long [^double x] 296 | (long (Double/doubleToRawLongBits x))) 297 | 298 | (defn long->double 299 | "Converts a long to a double." 300 | {:inline (fn [x] `(Double/longBitsToDouble ~x))} 301 | ^double [^long x] 302 | (double (Double/longBitsToDouble x))) 303 | 304 | (defn reverse-short 305 | "Inverts the endianness of a short." 306 | {:inline (fn [x] `(Primitives/reverseShort ~x))} 307 | ^long [^long x] 308 | (->> x Primitives/reverseShort long)) 309 | 310 | (defn reverse-int 311 | "Inverts the endianness of an int." 312 | {:inline (fn [x] `(Primitives/reverseInteger ~x))} 313 | ^long [^long x] 314 | (->> x Primitives/reverseInteger long)) 315 | 316 | (defn reverse-long 317 | "Inverts the endianness of a long." 318 | {:inline (fn [x] `(Primitives/reverseLong ~x))} 319 | ^long [^long x] 320 | (Primitives/reverseLong x)) 321 | 322 | (defn reverse-float 323 | "Inverts the endianness of a float." 324 | {:inline (fn [x] `(-> ~x float->int reverse-int int->float))} 325 | ^double [^double x] 326 | (-> x float->int reverse-int int->float)) 327 | 328 | (defn reverse-double 329 | "Inverts the endianness of a double." 330 | {:inline (fn [x] `(-> ~x double->long reverse-long long->double))} 331 | ^double [^double x] 332 | (-> x double->long reverse-long long->double)) 333 | -------------------------------------------------------------------------------- /src/clj_commons/primitive_math/Primitives.java: -------------------------------------------------------------------------------- 1 | package clj_commons.primitive_math; 2 | 3 | public class Primitives { 4 | 5 | public static byte toByte(long n) { 6 | return (byte) n; 7 | } 8 | 9 | public static short toShort(long n) { 10 | return (short) n; 11 | } 12 | 13 | public static int toInteger(long n) { 14 | return (int) n; 15 | } 16 | 17 | public static float toFloat(double n) { 18 | return (float) n; 19 | } 20 | 21 | public static short reverseShort(long n) { 22 | return (short) (((short) n << 8) 23 | | ((char) n >>> 8)); 24 | } 25 | 26 | public static int reverseInteger(long n) { 27 | int x = (int) n; 28 | return ((x << 24) 29 | | ((x & 0x0000ff00) << 8) 30 | | ((x & 0x00ff0000) >>> 8) 31 | | (x >>> 24)); 32 | } 33 | 34 | public static long reverseLong(long n) { 35 | return (((long) reverseInteger(n) << 32) 36 | | ((long) reverseInteger((n >>> 32)) & 0xffffffffL)); 37 | } 38 | 39 | //// 40 | 41 | public static boolean isTrue(boolean x) { 42 | return x == true; 43 | } 44 | 45 | public static boolean isFalse(boolean x) { 46 | return x == false; 47 | } 48 | 49 | public static boolean and(boolean a, boolean b) { 50 | return a && b; 51 | } 52 | 53 | public static boolean or(boolean a, boolean b) { 54 | return a || b; 55 | } 56 | 57 | public static boolean not(boolean a) { 58 | return !a; 59 | } 60 | 61 | public static boolean xor(boolean a, boolean b) { 62 | return (a || b) && !(a && b); 63 | } 64 | 65 | 66 | //// 67 | 68 | public static long bitAnd(long a, long b) { 69 | return a & b; 70 | } 71 | 72 | public static long bitOr(long a, long b) { 73 | return a | b; 74 | } 75 | 76 | public static long bitXor(long a, long b) { 77 | return a ^ b; 78 | } 79 | 80 | public static long bitNot(long a) { 81 | return ~a; 82 | } 83 | 84 | public static long shiftLeft(long a, long n) { 85 | return a << n; 86 | } 87 | 88 | public static long shiftRight(long a, long n) { 89 | return a >> n; 90 | } 91 | 92 | public static long unsignedShiftRight(long a, long n) { 93 | return a >>> n; 94 | } 95 | 96 | public static int unsignedShiftRight(int a, long n) { 97 | return a >>> n; 98 | } 99 | 100 | //// 101 | 102 | public static boolean lt(long a, long b) { 103 | return a < b; 104 | } 105 | 106 | public static boolean lt(float a, float b) { 107 | return a < b; 108 | } 109 | 110 | public static boolean lt(double a, double b) { 111 | return a < b; 112 | } 113 | 114 | public static boolean lte(double a, double b) { 115 | return a <= b; 116 | } 117 | 118 | public static boolean lte(float a, float b) { 119 | return a <= b; 120 | } 121 | 122 | public static boolean lte(long a, long b) { 123 | return a <= b; 124 | } 125 | 126 | public static boolean gt(long a, long b) { 127 | return a > b; 128 | } 129 | 130 | public static boolean gt(float a, float b) { 131 | return a > b; 132 | } 133 | 134 | public static boolean gt(double a, double b) { 135 | return a > b; 136 | } 137 | 138 | public static boolean gte(long a, long b) { 139 | return a >= b; 140 | } 141 | 142 | public static boolean gte(float a, float b) { 143 | return a >= b; 144 | } 145 | 146 | public static boolean gte(double a, double b) { 147 | return a >= b; 148 | } 149 | 150 | public static boolean eq(long a, long b) { 151 | return a == b; 152 | } 153 | 154 | public static boolean eq(float a, float b) { 155 | return a == b; 156 | } 157 | 158 | public static boolean eq(double a, double b) { 159 | return a == b; 160 | } 161 | 162 | public static boolean neq(long a, long b) { 163 | return a != b; 164 | } 165 | 166 | public static boolean neq(float a, float b) { 167 | return a != b; 168 | } 169 | 170 | public static boolean neq(double a, double b) { 171 | return a != b; 172 | } 173 | 174 | //// 175 | 176 | public static long rem(long n, long div) { 177 | return n % div; 178 | } 179 | 180 | public static float rem(float n, float div) { return n % div; } 181 | 182 | public static double rem(double n, double div) { return n % div; } 183 | 184 | public static long inc(long n) { 185 | return n + 1; 186 | } 187 | 188 | public static float inc(float n) { 189 | return n + 1.0f; 190 | } 191 | 192 | public static double inc(double n) { 193 | return n + 1.0; 194 | } 195 | 196 | public static long dec(long n) { 197 | return n - 1; 198 | } 199 | 200 | public static float dec(float n) { 201 | return n - 1.0f; 202 | } 203 | 204 | public static double dec(double n) { 205 | return n - 1.0; 206 | } 207 | 208 | public static boolean isZero(long n) { 209 | return n == 0; 210 | } 211 | 212 | public static boolean isZero(float n) { 213 | return n == 0.0f; 214 | } 215 | 216 | public static boolean isZero(double n) { 217 | return n == 0.0; 218 | } 219 | 220 | public static long add(long a, long b) { 221 | return a + b; 222 | } 223 | 224 | public static float add(float a, float b) { 225 | return a + b; 226 | } 227 | 228 | public static double add(double a, double b) { 229 | return a + b; 230 | } 231 | 232 | public static long subtract(long a, long b) { 233 | return a - b; 234 | } 235 | 236 | public static float subtract(float a, float b) { 237 | return a - b; 238 | } 239 | 240 | public static double subtract(double a, double b) { 241 | return a - b; 242 | } 243 | 244 | public static long negate(long n) { 245 | return -n; 246 | } 247 | 248 | public static float negate(float n) { 249 | return -n; 250 | } 251 | 252 | public static double negate(double n) { 253 | return -n; 254 | } 255 | 256 | public static long multiply(long a, long b) { 257 | return a * b; 258 | } 259 | 260 | public static float multiply(float a, float b) { 261 | return a * b; 262 | } 263 | 264 | public static double multiply(double a, double b) { 265 | return a * b; 266 | } 267 | 268 | public static long divide(long a, long b) { 269 | return a / b; 270 | } 271 | 272 | public static float divide(float a, float b) { 273 | return a / b; 274 | } 275 | 276 | public static double divide(double a, double b) { 277 | return a / b; 278 | } 279 | 280 | ;;; 281 | 282 | public static long max(long a, long b) { 283 | return a < b ? b : a; 284 | } 285 | 286 | public static long min(long a, long b) { 287 | return a > b ? b : a; 288 | } 289 | 290 | public static float max(float a, float b) { 291 | return a < b ? b : a; 292 | } 293 | 294 | public static float min(float a, float b) { 295 | return a > b ? b : a; 296 | } 297 | 298 | public static double max(double a, double b) { 299 | return a < b ? b : a; 300 | } 301 | 302 | public static double min(double a, double b) { 303 | return a > b ? b : a; 304 | } 305 | 306 | } 307 | -------------------------------------------------------------------------------- /src/primitive_math.clj: -------------------------------------------------------------------------------- 1 | (ns primitive-math 2 | "Use clj-commons.primitive-math instead." 3 | {:deprecated "1.0.0" 4 | :superseded-by "clj-commons.primitive-math" 5 | :no-doc true} 6 | (:refer-clojure 7 | :exclude [* + - / < > <= >= == rem bit-or bit-and bit-xor bit-not bit-shift-left bit-shift-right unsigned-bit-shift-right byte short int float long double inc dec zero? min max true? false?]) 8 | (:import 9 | [primitive_math Primitives] 10 | [java.nio ByteBuffer])) 11 | 12 | ;;; 13 | 14 | (defmacro ^:private variadic-proxy 15 | "Creates left-associative variadic forms for any operator." 16 | ([name fn] 17 | `(variadic-proxy ~name ~fn ~(str "A primitive macro version of `" name "`"))) 18 | ([name fn doc] 19 | `(variadic-proxy ~name ~fn ~doc identity)) 20 | ([name fn doc single-arg-form] 21 | (let [x-sym (gensym "x")] 22 | `(defmacro ~name 23 | ~doc 24 | ([~x-sym] 25 | ~((eval single-arg-form) x-sym)) 26 | ([x# y#] 27 | (list '~fn x# y#)) 28 | ([x# y# ~'& rest#] 29 | (list* '~name (list '~name x# y#) rest#)))))) 30 | 31 | (defmacro ^:private variadic-predicate-proxy 32 | "Turns variadic predicates into multiple pair-wise comparisons." 33 | ([name fn] 34 | `(variadic-predicate-proxy ~name ~fn ~(str "A primitive macro version of `" name "`"))) 35 | ([name fn doc] 36 | `(variadic-predicate-proxy ~name ~fn ~doc (constantly true))) 37 | ([name fn doc single-arg-form] 38 | (let [x-sym (gensym "x")] 39 | `(defmacro ~name 40 | ~doc 41 | ([~x-sym] 42 | ~((eval single-arg-form) x-sym)) 43 | ([x# y#] 44 | (list '~fn x# y#)) 45 | ([x# y# ~'& rest#] 46 | (list 'primitive_math.Primitives/and (list '~name x# y#) (list* '~name y# rest#))))))) 47 | 48 | (variadic-proxy + primitive_math.Primitives/add) 49 | (variadic-proxy - primitive_math.Primitives/subtract "A primitive macro version of `-`" (fn [x] `(list 'primitive_math.Primitives/negate ~x))) 50 | (variadic-proxy * primitive_math.Primitives/multiply) 51 | (variadic-proxy / primitive_math.Primitives/divide) 52 | (variadic-proxy div primitive_math.Primitives/divide) 53 | (variadic-proxy bit-and primitive_math.Primitives/bitAnd) 54 | (variadic-proxy bit-or primitive_math.Primitives/bitOr) 55 | (variadic-proxy bit-xor primitive_math.Primitives/bitXor) 56 | (variadic-proxy bool-and primitive_math.Primitives/and) 57 | (variadic-proxy bool-or primitive_math.Primitives/or) 58 | (variadic-proxy bool-xor primitive_math.Primitives/xor) 59 | (variadic-proxy min primitive_math.Primitives/min) 60 | (variadic-proxy max primitive_math.Primitives/max) 61 | 62 | (variadic-predicate-proxy > primitive_math.Primitives/gt) 63 | (variadic-predicate-proxy < primitive_math.Primitives/lt) 64 | (variadic-predicate-proxy <= primitive_math.Primitives/lte) 65 | (variadic-predicate-proxy >= primitive_math.Primitives/gte) 66 | (variadic-predicate-proxy == primitive_math.Primitives/eq) 67 | (variadic-predicate-proxy not== primitive_math.Primitives/neq "A primitive macro complement of `==`") 68 | 69 | (defmacro inc 70 | "A primitive macro version of `inc`." 71 | [x] 72 | `(Primitives/inc ~x)) 73 | 74 | (defmacro dec 75 | "A primitive macro version of `dec`." 76 | [x] 77 | `(Primitives/dec ~x)) 78 | 79 | (defmacro rem 80 | "A primitive macro version of `rem`." 81 | [n div] 82 | `(Primitives/rem ~n ~div)) 83 | 84 | (defmacro zero? 85 | "A primitive macro version of `zero?`." 86 | [x] 87 | `(Primitives/isZero ~x)) 88 | 89 | (defmacro bool-not 90 | "A primitive macro version of `not`." 91 | [x] 92 | `(Primitives/not ~x)) 93 | 94 | (defmacro bit-not 95 | "A primitive macro version of `bit-not`." 96 | [x] 97 | `(Primitives/bitNot ~x)) 98 | 99 | (defmacro true? 100 | "A primitive macro version of `true?`." 101 | [x] 102 | `(Primitives/isTrue ~x)) 103 | 104 | (defmacro false? 105 | "A primitive macro version of `false?`." 106 | [x] 107 | `(Primitives/isFalse ~x)) 108 | 109 | (defmacro bit-shift-left 110 | "A primitive macro version of `bit-shift-left`." 111 | [n bits] 112 | `(Primitives/shiftLeft ~n ~bits)) 113 | 114 | (defmacro bit-shift-right 115 | "A primitive macro version of `bit-shift-right`." 116 | [n bits] 117 | `(Primitives/shiftRight ~n ~bits)) 118 | 119 | ;; this was the original name, which doesn't match the Clojure name and is kept 120 | ;; around for legacy purposes 121 | (defmacro ^:no-doc bit-unsigned-shift-right 122 | [n bits] 123 | `(Primitives/unsignedShiftRight ~n ~bits)) 124 | 125 | (defmacro unsigned-bit-shift-right 126 | "A primitive macro which performs an unsigned right bit-shift." 127 | [n bits] 128 | `(Primitives/unsignedShiftRight ~n ~bits)) 129 | 130 | (defmacro << 131 | "An alias for `bit-shift-left`." 132 | [n bits] 133 | `(Primitives/shiftLeft ~n ~bits)) 134 | 135 | (defmacro >> 136 | "An alias for `bit-shift-right`." 137 | [n bits] 138 | `(Primitives/shiftRight ~n ~bits)) 139 | 140 | (defmacro >>> 141 | "An alias for `bit-unsigned-shift-right`." 142 | [n bits] 143 | `(Primitives/unsignedShiftRight ~n ~bits)) 144 | 145 | ;;; 146 | 147 | (def ^:private vars-to-exclude 148 | '[* + - / < > <= >= == rem bit-or bit-and bit-xor bit-not bit-shift-left bit-shift-right byte short int float long double inc dec zero? true? false? min max]) 149 | 150 | (defn- using-primitive-operators? [] 151 | (= #'primitive-math/+ (resolve '+))) 152 | 153 | (defonce ^:private hijacked? (atom false)) 154 | 155 | (defn- ns-wrapper 156 | "Makes sure that if a namespace that is using primitive operators is reloaded, it will automatically 157 | exclude the shadowed operators in `clojure.core`." 158 | [f] 159 | (fn [& x] 160 | (if-not (using-primitive-operators?) 161 | (apply f x) 162 | (let [refer-clojure (->> x 163 | (filter #(and (sequential? %) (= :refer-clojure (first %)))) 164 | first) 165 | refer-clojure-clauses (update-in 166 | (apply hash-map (rest refer-clojure)) 167 | [:exclude] 168 | #(concat % vars-to-exclude))] 169 | (apply f 170 | (concat 171 | (remove #{refer-clojure} x) 172 | [(list* :refer-clojure (apply concat refer-clojure-clauses))])))))) 173 | 174 | (defn use-primitive-operators 175 | "Replaces Clojure's arithmetic and number coercion functions with primitive equivalents. These are 176 | defined as macros, so they cannot be used as higher-order functions. This is an idempotent operation.." 177 | [] 178 | (when-not @hijacked? 179 | (reset! hijacked? true) 180 | (alter-var-root #'clojure.core/ns ns-wrapper)) 181 | (when-not (using-primitive-operators?) 182 | (doseq [v vars-to-exclude] 183 | (ns-unmap *ns* v)) 184 | (require (vector 'primitive-math :refer vars-to-exclude)))) 185 | 186 | (defn unuse-primitive-operators 187 | "Undoes the work of `use-primitive-operators`. This is idempotent." 188 | [] 189 | (doseq [v vars-to-exclude] 190 | (ns-unmap *ns* v)) 191 | (refer 'clojure.core)) 192 | 193 | ;;; 194 | 195 | (defn byte 196 | "Truncates a number to a byte, will not check for overflow." 197 | {:inline (fn [x] `(primitive_math.Primitives/toByte ~x))} 198 | ^long [^long x] 199 | (unchecked-long (Primitives/toByte x))) 200 | 201 | (defn short 202 | "Truncates a number to a short, will not check for overflow." 203 | {:inline (fn [x] `(primitive_math.Primitives/toShort ~x))} 204 | ^long [^long x] 205 | (unchecked-long (Primitives/toShort x))) 206 | 207 | (defn int 208 | "Truncates a number to an int, will not check for overflow." 209 | {:inline (fn [x] `(primitive_math.Primitives/toInteger ~x))} 210 | ^long [^long x] 211 | (unchecked-long (Primitives/toInteger x))) 212 | 213 | (defn float 214 | "Truncates a number to a float, will not check for overflow." 215 | {:inline (fn [x] `(primitive_math.Primitives/toFloat ~x))} 216 | ^double [^double x] 217 | (unchecked-double (Primitives/toFloat x))) 218 | 219 | (defn long 220 | "Converts a number to a long." 221 | {:inline (fn [x] `(unchecked-long ~x))} 222 | ^long [x] 223 | (unchecked-long x)) 224 | 225 | (defn double 226 | "Converts a number to a double." 227 | {:inline (fn [x] `(unchecked-double ~x))} 228 | ^double [x] 229 | (unchecked-double x)) 230 | 231 | (defn byte->ubyte 232 | "Converts a byte to an unsigned byte." 233 | {:inline (fn [x] `(->> ~x long (bit-and 0xFF) short))} 234 | ^long [^long x] 235 | (long (short (bit-and x 0xFF)))) 236 | 237 | (defn ubyte->byte 238 | "Converts an unsigned byte to a byte." 239 | {:inline (fn [x] `(byte (long ~x)))} 240 | ^long [^long x] 241 | (long (byte x))) 242 | 243 | (defn short->ushort 244 | "Converts a short to an unsigned short." 245 | {:inline (fn [x] `(->> ~x long (bit-and 0xFFFF) int))} 246 | ^long [^long x] 247 | (long (int (bit-and 0xFFFF x)))) 248 | 249 | (defn ushort->short 250 | "Converts an unsigned short to a short." 251 | {:inline (fn [x] `(short (long ~x)))} 252 | ^long [^long x] 253 | (long (short x))) 254 | 255 | (defn int->uint 256 | "Converts an integer to an unsigned integer." 257 | {:inline (fn [x] `(->> ~x long (bit-and 0xFFFFFFFF)))} 258 | ^long [^long x] 259 | (long (bit-and 0xFFFFFFFF x))) 260 | 261 | (defn uint->int 262 | "Converts an unsigned integer to an integer." 263 | {:inline (fn [x] `(int (long ~x)))} 264 | ^long [^long x] 265 | (long (int x))) 266 | 267 | (defn long->ulong 268 | "Converts a long to an unsigned long." 269 | [^long x] 270 | (BigInteger. 1 271 | (-> (ByteBuffer/allocate 8) (.putLong x) .array))) 272 | 273 | (defn ^long ulong->long 274 | "Converts an unsigned long to a long." 275 | ^long [x] 276 | (.longValue ^clojure.lang.BigInt (bigint x))) 277 | 278 | (defn float->int 279 | "Converts a float to an integer." 280 | {:inline (fn [x] `(Float/floatToRawIntBits (float ~x)))} 281 | ^long [^double x] 282 | (long (Float/floatToRawIntBits x))) 283 | 284 | (defn int->float 285 | "Converts an integer to a float." 286 | {:inline (fn [x] `(Float/intBitsToFloat (int ~x)))} 287 | ^double [^long x] 288 | (double (Float/intBitsToFloat x))) 289 | 290 | (defn double->long 291 | "Converts a double to a long." 292 | {:inline (fn [x] `(Double/doubleToRawLongBits ~x))} 293 | ^long [^double x] 294 | (long (Double/doubleToRawLongBits x))) 295 | 296 | (defn long->double 297 | "Converts a long to a double." 298 | {:inline (fn [x] `(Double/longBitsToDouble ~x))} 299 | ^double [^long x] 300 | (double (Double/longBitsToDouble x))) 301 | 302 | (defn reverse-short 303 | "Inverts the endianness of a short." 304 | {:inline (fn [x] `(Primitives/reverseShort ~x))} 305 | ^long [^long x] 306 | (->> x Primitives/reverseShort long)) 307 | 308 | (defn reverse-int 309 | "Inverts the endianness of an int." 310 | {:inline (fn [x] `(Primitives/reverseInteger ~x))} 311 | ^long [^long x] 312 | (->> x Primitives/reverseInteger long)) 313 | 314 | (defn reverse-long 315 | "Inverts the endianness of a long." 316 | {:inline (fn [x] `(Primitives/reverseLong ~x))} 317 | ^long [^long x] 318 | (Primitives/reverseLong x)) 319 | 320 | (defn reverse-float 321 | "Inverts the endianness of a float." 322 | {:inline (fn [x] `(-> ~x float->int reverse-int int->float))} 323 | ^double [^double x] 324 | (-> x float->int reverse-int int->float)) 325 | 326 | (defn reverse-double 327 | "Inverts the endianness of a double." 328 | {:inline (fn [x] `(-> ~x double->long reverse-long long->double))} 329 | ^double [^double x] 330 | (-> x double->long reverse-long long->double)) 331 | -------------------------------------------------------------------------------- /src/primitive_math/Primitives.java: -------------------------------------------------------------------------------- 1 | package primitive_math; 2 | 3 | public class Primitives { 4 | 5 | public static byte toByte(long n) { 6 | return (byte) n; 7 | } 8 | 9 | public static short toShort(long n) { 10 | return (short) n; 11 | } 12 | 13 | public static int toInteger(long n) { 14 | return (int) n; 15 | } 16 | 17 | public static float toFloat(double n) { 18 | return (float) n; 19 | } 20 | 21 | public static short reverseShort(long n) { 22 | return (short) (((short) n << 8) 23 | | ((char) n >>> 8)); 24 | } 25 | 26 | public static int reverseInteger(long n) { 27 | int x = (int) n; 28 | return ((x << 24) 29 | | ((x & 0x0000ff00) << 8) 30 | | ((x & 0x00ff0000) >>> 8) 31 | | (x >>> 24)); 32 | } 33 | 34 | public static long reverseLong(long n) { 35 | return (((long) reverseInteger(n) << 32) 36 | | ((long) reverseInteger((n >>> 32)) & 0xffffffffL)); 37 | } 38 | 39 | //// 40 | 41 | public static boolean isTrue(boolean x) { 42 | return x == true; 43 | } 44 | 45 | public static boolean isFalse(boolean x) { 46 | return x == false; 47 | } 48 | 49 | public static boolean and(boolean a, boolean b) { 50 | return a && b; 51 | } 52 | 53 | public static boolean or(boolean a, boolean b) { 54 | return a || b; 55 | } 56 | 57 | public static boolean not(boolean a) { 58 | return !a; 59 | } 60 | 61 | public static boolean xor(boolean a, boolean b) { 62 | return (a || b) && !(a && b); 63 | } 64 | 65 | 66 | //// 67 | 68 | public static long bitAnd(long a, long b) { 69 | return a & b; 70 | } 71 | 72 | public static long bitOr(long a, long b) { 73 | return a | b; 74 | } 75 | 76 | public static long bitXor(long a, long b) { 77 | return a ^ b; 78 | } 79 | 80 | public static long bitNot(long a) { 81 | return ~a; 82 | } 83 | 84 | public static long shiftLeft(long a, long n) { 85 | return a << n; 86 | } 87 | 88 | public static long shiftRight(long a, long n) { 89 | return a >> n; 90 | } 91 | 92 | public static long unsignedShiftRight(long a, long n) { 93 | return a >>> n; 94 | } 95 | 96 | public static int unsignedShiftRight(int a, long n) { 97 | return a >>> n; 98 | } 99 | 100 | //// 101 | 102 | public static boolean lt(long a, long b) { 103 | return a < b; 104 | } 105 | 106 | public static boolean lt(float a, float b) { 107 | return a < b; 108 | } 109 | 110 | public static boolean lt(double a, double b) { 111 | return a < b; 112 | } 113 | 114 | public static boolean lte(double a, double b) { 115 | return a <= b; 116 | } 117 | 118 | public static boolean lte(float a, float b) { 119 | return a <= b; 120 | } 121 | 122 | public static boolean lte(long a, long b) { 123 | return a <= b; 124 | } 125 | 126 | public static boolean gt(long a, long b) { 127 | return a > b; 128 | } 129 | 130 | public static boolean gt(float a, float b) { 131 | return a > b; 132 | } 133 | 134 | public static boolean gt(double a, double b) { 135 | return a > b; 136 | } 137 | 138 | public static boolean gte(long a, long b) { 139 | return a >= b; 140 | } 141 | 142 | public static boolean gte(float a, float b) { 143 | return a >= b; 144 | } 145 | 146 | public static boolean gte(double a, double b) { 147 | return a >= b; 148 | } 149 | 150 | public static boolean eq(long a, long b) { 151 | return a == b; 152 | } 153 | 154 | public static boolean eq(float a, float b) { 155 | return a == b; 156 | } 157 | 158 | public static boolean eq(double a, double b) { 159 | return a == b; 160 | } 161 | 162 | public static boolean neq(long a, long b) { 163 | return a != b; 164 | } 165 | 166 | public static boolean neq(float a, float b) { 167 | return a != b; 168 | } 169 | 170 | public static boolean neq(double a, double b) { 171 | return a != b; 172 | } 173 | 174 | //// 175 | 176 | public static long rem(long n, long div) { 177 | return n % div; 178 | } 179 | 180 | public static long inc(long n) { 181 | return n + 1; 182 | } 183 | 184 | public static float inc(float n) { 185 | return n + 1.0f; 186 | } 187 | 188 | public static double inc(double n) { 189 | return n + 1.0; 190 | } 191 | 192 | public static long dec(long n) { 193 | return n - 1; 194 | } 195 | 196 | public static float dec(float n) { 197 | return n - 1.0f; 198 | } 199 | 200 | public static double dec(double n) { 201 | return n - 1.0; 202 | } 203 | 204 | public static boolean isZero(long n) { 205 | return n == 0; 206 | } 207 | 208 | public static boolean isZero(float n) { 209 | return n == 0.0f; 210 | } 211 | 212 | public static boolean isZero(double n) { 213 | return n == 0.0; 214 | } 215 | 216 | public static long add(long a, long b) { 217 | return a + b; 218 | } 219 | 220 | public static float add(float a, float b) { 221 | return a + b; 222 | } 223 | 224 | public static double add(double a, double b) { 225 | return a + b; 226 | } 227 | 228 | public static long subtract(long a, long b) { 229 | return a - b; 230 | } 231 | 232 | public static float subtract(float a, float b) { 233 | return a - b; 234 | } 235 | 236 | public static double subtract(double a, double b) { 237 | return a - b; 238 | } 239 | 240 | public static long negate(long n) { 241 | return -n; 242 | } 243 | 244 | public static float negate(float n) { 245 | return -n; 246 | } 247 | 248 | public static double negate(double n) { 249 | return -n; 250 | } 251 | 252 | public static long multiply(long a, long b) { 253 | return a * b; 254 | } 255 | 256 | public static float multiply(float a, float b) { 257 | return a * b; 258 | } 259 | 260 | public static double multiply(double a, double b) { 261 | return a * b; 262 | } 263 | 264 | public static long divide(long a, long b) { 265 | return a / b; 266 | } 267 | 268 | public static float divide(float a, float b) { 269 | return a / b; 270 | } 271 | 272 | public static double divide(double a, double b) { 273 | return a / b; 274 | } 275 | 276 | ;;; 277 | 278 | public static long max(long a, long b) { 279 | return a < b ? b : a; 280 | } 281 | 282 | public static long min(long a, long b) { 283 | return a > b ? b : a; 284 | } 285 | 286 | public static float max(float a, float b) { 287 | return a < b ? b : a; 288 | } 289 | 290 | public static float min(float a, float b) { 291 | return a > b ? b : a; 292 | } 293 | 294 | public static double max(double a, double b) { 295 | return a < b ? b : a; 296 | } 297 | 298 | public static double min(double a, double b) { 299 | return a > b ? b : a; 300 | } 301 | 302 | } 303 | -------------------------------------------------------------------------------- /test/clj_commons/primitive_math_test.clj: -------------------------------------------------------------------------------- 1 | (ns clj-commons.primitive-math-test 2 | (:use 3 | clojure.test) 4 | (:require 5 | [clj-commons.primitive-math :as p])) 6 | 7 | (set! *warn-on-reflection* true) 8 | 9 | (def primitive-ops 10 | {:long `[p/long->ulong p/ulong->long p/reverse-long] 11 | :int `[p/int->uint p/uint->int p/reverse-int] 12 | :short `[p/short->ushort p/ushort->short p/reverse-short] 13 | :byte `[p/byte->ubyte p/ubyte->byte identity] 14 | :float ` [identity identity p/reverse-float] 15 | :double `[identity identity p/reverse-double]}) 16 | 17 | (deftest test-roundtrips 18 | (are [type nums] 19 | (let [[s->u u->s reverse-fn] (primitive-ops type)] 20 | (let [s->u' (eval s->u) 21 | u->s' (eval u->s) 22 | reverse-fn' (eval reverse-fn)] 23 | (every? 24 | (fn [x] 25 | (and 26 | ;; test both normal and inlined versions of the functions 27 | (= x (eval `(-> ~x ~s->u ~u->s))) 28 | (= x (-> x s->u' u->s')) 29 | (= x (eval `(-> ~x ~reverse-fn ~reverse-fn))) 30 | (= x (-> x reverse-fn' reverse-fn')))) 31 | nums))) 32 | 33 | :double [-1.0 0.0 1.0 Double/MIN_VALUE Double/MAX_VALUE] 34 | :float [-1.0 0.0 1.0 Float/MIN_VALUE Float/MAX_VALUE] 35 | :long [-1 0 1 Long/MIN_VALUE Long/MAX_VALUE] 36 | :int [-1 0 1 Integer/MIN_VALUE Integer/MAX_VALUE] 37 | :short [-1 0 1 Short/MIN_VALUE Short/MAX_VALUE] 38 | :byte [-1 0 1 Byte/MIN_VALUE Byte/MAX_VALUE])) 39 | 40 | (defn eval-assertions [x] 41 | (eval 42 | `(do 43 | ~@(map #(list `is %) x)))) 44 | 45 | (deftest test-arithmetic 46 | (p/use-primitive-operators) 47 | (try 48 | (eval-assertions 49 | '((== 6 (+ 1 2 3) (+ 3 3) (+ 6)) 50 | (== 0 (- 6 3 3) (- 6 6)) 51 | (== -3 (- 3)) 52 | (== 12 (* 2 2 3) (* 4 3)) 53 | (== 5 (/ 10 2) (/ 20 2 2) (/ 11 2)) 54 | 55 | (= true (and true) (and true true) (or true) (or false true)) 56 | (= false (and false) (or false) (and true false)) 57 | 58 | (== 6.0 (+ 1.0 2.0 3.0) (+ 3.0 3.0)) 59 | 60 | (== (float 6.0) (+ (float 1.0) (float 2.0) (float 3.0)) (+ (float 3.0) (float 3.0))) 61 | 62 | (== 1 (rem 10 9)) 63 | (== (float 0.5) (rem (float 6.5) (float 1.5))) 64 | (== 0.5 (rem 6.5 1.5)) 65 | 66 | (thrown? IllegalArgumentException 67 | (+ 1 2.0)))) 68 | (finally 69 | (p/unuse-primitive-operators))) 70 | 71 | (eval-assertions 72 | `((== 6 (+ 1 2 3) (+ 3 3)) 73 | (== 3.0 (+ 1 2.0))))) 74 | -------------------------------------------------------------------------------- /test/primitive_math_test.clj: -------------------------------------------------------------------------------- 1 | (ns primitive-math-test 2 | (:use 3 | clojure.test) 4 | (:require 5 | [primitive-math :as p])) 6 | 7 | (set! *warn-on-reflection* true) 8 | 9 | (def primitive-ops 10 | {:long `[p/long->ulong p/ulong->long p/reverse-long] 11 | :int `[p/int->uint p/uint->int p/reverse-int] 12 | :short `[p/short->ushort p/ushort->short p/reverse-short] 13 | :byte `[p/byte->ubyte p/ubyte->byte identity] 14 | :float ` [identity identity p/reverse-float] 15 | :double `[identity identity p/reverse-double]}) 16 | 17 | (deftest test-roundtrips 18 | (are [type nums] 19 | (let [[s->u u->s reverse-fn] (primitive-ops type)] 20 | (let [s->u' (eval s->u) 21 | u->s' (eval u->s) 22 | reverse-fn' (eval reverse-fn)] 23 | (every? 24 | (fn [x] 25 | (and 26 | ;; test both normal and inlined versions of the functions 27 | (= x (eval `(-> ~x ~s->u ~u->s))) 28 | (= x (-> x s->u' u->s')) 29 | (= x (eval `(-> ~x ~reverse-fn ~reverse-fn))) 30 | (= x (-> x reverse-fn' reverse-fn')))) 31 | nums))) 32 | 33 | :double [-1.0 0.0 1.0 Double/MIN_VALUE Double/MAX_VALUE] 34 | :float [-1.0 0.0 1.0 Float/MIN_VALUE Float/MAX_VALUE] 35 | :long [-1 0 1 Long/MIN_VALUE Long/MAX_VALUE] 36 | :int [-1 0 1 Integer/MIN_VALUE Integer/MAX_VALUE] 37 | :short [-1 0 1 Short/MIN_VALUE Short/MAX_VALUE] 38 | :byte [-1 0 1 Byte/MIN_VALUE Byte/MAX_VALUE])) 39 | 40 | (defn eval-assertions [x] 41 | (eval 42 | `(do 43 | ~@(map #(list `is %) x)))) 44 | 45 | (deftest test-arithmetic 46 | (p/use-primitive-operators) 47 | (try 48 | (eval-assertions 49 | '((== 6 (+ 1 2 3) (+ 3 3) (+ 6)) 50 | (== 0 (- 6 3 3) (- 6 6)) 51 | (== -3 (- 3)) 52 | (== 12 (* 2 2 3) (* 4 3)) 53 | (== 5 (/ 10 2) (/ 20 2 2) (/ 11 2)) 54 | 55 | (= true (and true) (and true true) (or true) (or false true)) 56 | (= false (and false) (or false) (and true false)) 57 | 58 | (== 6.0 (+ 1.0 2.0 3.0) (+ 3.0 3.0)) 59 | 60 | (== (float 6.0) (+ (float 1.0) (float 2.0) (float 3.0)) (+ (float 3.0) (float 3.0))) 61 | 62 | (thrown? IllegalArgumentException 63 | (+ 1 2.0)))) 64 | (finally 65 | (p/unuse-primitive-operators))) 66 | 67 | (eval-assertions 68 | `((== 6 (+ 1 2 3) (+ 3 3)) 69 | (== 3.0 (+ 1 2.0))))) 70 | --------------------------------------------------------------------------------