6

With Clojure, how do I generate a random long number? I know Clojure has a rand-int function but it only works for integer. If a given number is long, I got this repl error:

IllegalArgumentException Value out of range for int: 528029243649 clojure.lang.RT.intCast (RT.java:1205)

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
danny
  • 3,046
  • 3
  • 23
  • 28

2 Answers2

9

If you take a look at the source of rand-int

(defn rand-int
  "Returns a random integer between 0 (inclusive) and n (exclusive)."
  [n] (int (rand n)))

You can do a similar thing

(long (rand n)))

Timothy Pratley
  • 10,586
  • 3
  • 34
  • 63
7

Clojure's rand and rand-int use java.util.Random as the underlying random number generator. If your application depends heavily on random numbers, you might want to consider using a higher-quality random number generator written in Java, such as MersenneTwisterFast. This has a nextLong() method, and it's very easy to use from Clojure. Java's standard class SecureRandom might be worth considering, too; it's designed for different purposes than the Mersenne Twister. There are other good Java random number generators available. Depends on what you're using the random numbers for. For occasional use of random numbers, java.util.Random might be just fine. There are additional options mentioned in comments by others.

I'll describe use of MersenneTwisterFast. Using the other classes I mentioned would be essentially the same, but without the initial steps.

With Leiningen, add something like this to project.clj:

  :java-source-paths ["src/java"]

and then put the Java source for MersenneTwisterFast.java in src/java/ec/util. Then you can do this:

(ns my.namespace
  (:import [ec.util MersenneTwisterFast]))

(def rng (MersenneTwisterFast. 42)) ; Specify a different seed, e.g. from system time.
(defn next-long [] (.nextLong rng))
Community
  • 1
  • 1
Mars
  • 8,689
  • 2
  • 42
  • 70
  • 1
    An alternate randomness source may be a good idea depending on OP's application, but it is certainly not necessary just to get a `long`. Just use the corresponding method in [j.u.Random](https://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextLong()) – amalloy Feb 07 '16 at 06:15
  • 3
    Since Java 8, there's also [`ThreadLocalRandom`](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html), which has a broader choice of methods and doesn't require creating an instance: `(.nextLong (java.util.concurrent.ThreadLocalRandom/current) 528029243649)`. – glts Feb 07 '16 at 09:30
  • Thanks @glts. I didn't know about `ThreadLocalRandom`. (Since I'm not familiar with it, I think I'll just let your comment be the information source, rather than continually adding options to my answer. I'll add a note pointing to comments, though.) – Mars Feb 08 '16 at 05:22