I’m wondering whether anyone has written anything discussing relationships between the Clojure 1.11’s clojure.math, and the older contrib API clojure.math.numeric-tower. I understand generally that clojure.math is a wrapper for Java math functions, and numeric-tower is supposed to deal in intelligent ways with Clojure numeric types, which are not always the same as Java numeric types. Not everything in numeric-tower is included in the 1.11 clojure.math, but there is some overlap. (And could it every be better to use java.lang.Math directly?) A discussion of pros and cons, when to use one or the other, etc. could be useful. Article, blog post, book chapter/section, etc.
(Bonus points for additional discussion of overlap with @generateme’s fastmath.)
Basic operations: * + - / > < >= <= == rem quot mod bit-or bit-and bit-xor bit-not bit-shift-left bit-shift-right unsigned-bit-shift-right inc dec zero? neg? pos? min max even? odd? abs - are macros backed by java static functions which work on long and double primitives only. There is no support for ratios, bigints, etc.
Trigonometry, rounding, log/exp/power stuff is backed by jafama
Additionally there are plenty of constants, special functions, macros which are stolen from C, Julia, R, Python, thi.ng, Apache Commons Math.
Most of functions / macros are type hinted (long/double) for arguments and returning value.
clojure.math as I see in the source code is a collection of type hinted wrapper functions. The difference between (clojure.math/sin 1.0) and (fastmath.core/sin 1.0) is that the latter is a macro and expands to direct static method invocation: (. net.jafama.FastMath sin 1.0). The former is a function and calls (Math/sin 1.0).
Calling Math/sin directly or fastmath.core/sin saves you one call jump. But it’s not a function and can’t be used in a map for example. That’s why clojure.math exists - to give you ready to use functions.
Hi, I wrote the clojure.math (JVM) stuff. math.numeric-tower was trying to replicate things from the Lisp/Scheme world whereas clojure.math is designed to be a high performance wrapper around what’s provided on the host. numeric-tower provides a pretty limited set of operations but generally a bit wider type support for numerics. That said, clojure.math covers most of the operations people actually use in numeric-tower plus many more and is vastly better performance wise (as many Math methods are backed by hotspot intrinsics that may go all the way down to the h/w). For any operation supported in both, you are much better off with the clojure.math one due to being built-in, portable (to CLJS, thanks to Paula Gearon), and fast. In my opinion you should no longer use numeric-tower.
Regarding direct access to Math, those functions are overloaded on multiple primitive types (float/double, int/long, etc) and naive use will result in reflection, so you are usually better served by clojure.math which narrows and coerces for you (plus, again - the same code works in CLJS). Additionally for a few functions in core (abs, min, max), these have the full polymorphic treatment in Clojure core.
fastmath covers a whole lot more, and certainly if you need the many additional things it provides, those are a good option. For the core function alternatives, I think if you are at the knowledge level or need the primitive math stuff, and understand all of the tradeoffs involved with macros vs fns etc, then you are probably also knowledgeable enough to write the correct code preserving primitives in the first place (assuming you just need basic math and things in c.math), so I do not think it’s worth using only for that.
Thanks @alexmiller. That’s extremely helpful. Exactly what I wanted to understand.
(About fastmath, I understand your point. I’m kind of at the border of that knowledge level, so sometimes I don’t mind trusting someone else’s work rather than thinking it through myself–although I guess I do have to do that somewhat to make sure it’s what I want.)