5 ms·
The very next sentence of the article points out that you can leverage Clojure's interop to invoke Math.pow(), but that's still limited to casting its arguments
by jffry 5y ago
The very next sentence of the article points out that you can leverage Clojure's interop to invoke Math.pow(), but that's still limited to casting its arguments down to java.lang.Double and suffering the limits therein
If you instead used the library org.clojure/math.numeric-tower [1] you can get much more precise answers, for example
# start a repl with an extra dep
$ clj -Sdeps '{:deps {org.clojure/math.numeric-tower {:mvn/version "0.0.4"}}}'
user=> (require 'clojure.math.numeric-tower)
nil
user=> (Math/pow 33 33)
1.2911004008776103E50
user=> (type *1)
java.lang.Double
user=> (clojure.math.numeric-tower/expt 33 33)
129110040087761027839616029934664535539337183380513N
user=> (type *1)
clojure.lang.BigInt
[1] https://github.com/clojure/math.numeric-tower https://github.com/clojure/math.numeric-tower
- didibus 5y ago> The very next sentence of the article points out that you can leverage Clojure's interop to invoke Math.pow() Hum, ok, to my defense it's not the very next sentence, it's much later at the very end when talking about Method invocation, so I hadn't read that far. +1 for linking to the numeric tower though
- jffry 5y agoMy apologies. I searched for Math/pow, saw that the sentence there started with "Clojure doesn't", and missed that we were looking at two different parts of the document :)
- dig1 5y agoYou need to be familiar with Java types and differences between them (Integer, BigInteger) and how Math.pow() behaves with different types. This is more up to Java, rather than Clojure. No need to pull the library for this, Clojure already has (biginteger) for that: user=> (.pow (biginteger 33) 33) 129110040087761027839616029934664535539337183380513
- kazinator 5y agoDidn't Clojure use the N suffix for big integers at one point? I don't see one on that output.
- jffry 5y agoThe N suffix is for clojure.lang.BigInt, which are created with (bigint) which was added in Clojure 1.3 and still work to this day (I did these examples in the latest 1.10.3 release) user=> (bigint "129110040087761027839616029934664535539337183380513") 129110040087761027839616029934664535539337183380513N user=> (type *1) clojure.lang.BigInt The Java-platform bigint is java.lang.BigInteger which are created with (biginteger) which was added in Clojure 1.0. Printing one of these will not include an N suffix: user=> (biginteger "129110040087761027839616029934664535539337183380513") 129110040087761027839616029934664535539337183380513 user=> (type *1) java.math.BigInteger Clojure BigInts are supposed to involve less unboxing and therefore be more performant. If you provide an integer literal that's too large to fit in a java.lang.Long, the reader will use a BigInt instead: user=> 129110040087761027839616029934664535539337183380513 129110040087761027839616029934664535539337183380513N user=> (type *1) clojure.lang.BigInt user=> 12345 12345 user=> (type *1) java.lang.Long If all this seems like a mess, well it sort of is. Clojure has a very strong commitment to backwards compatibility, so when the Clojure-specific big int representation was added, the old JDK-based one was not removed, because the operations that the two support are different.
- jffry 5y agoYeah if you know you're definitely dealing with integers that are large, and are willing to pay the cost to promote into biginteger territory, that's certainly a way to do it with the stdlib. The nice ergonomic thing about clojure.math.numeric-tower is you can shove any of the Clojure numeric types at it (longs, doubles, but also Ratio or BigNum etc) and it'll intelligently handle the various combinations of types in order to give you the best answer it can