How to generate repeatable random sequences with rand-int

前端 未结 7 1584
你的背包
你的背包 2021-02-08 18:22

I want to be able to generate repeatable numbers using rand in Clojure. (Specifically, I want results of calls to rand-nth or Incanter\'s sample

7条回答
  •  醉话见心
    2021-02-08 18:45

    Clojure's rand relies on the random method in java.lang.Math:

    user=> (source rand)
    (defn rand
      "Returns a random floating point number between 0 (inclusive) and
      n (default 1) (exclusive)."
      {:added "1.0"
       :static true}
      ([] (. Math (random)))
      ([n] (* n (rand))))
    

    According to the Oracle Java 7 documentation at https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#random()

    public static double random()

    Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.

    When this method is first called, it creates a single new pseudorandom-number generator, exactly as if by the expression

    new java.util.Random()

    This new pseudorandom-number generator is used thereafter for all calls to this method and is used nowhere else.

    This method is properly synchronized to allow correct use by more than one thread. However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.

    Returns:

    a pseudorandom double greater than or equal to 0.0 and less than 1.0.

    If you browse the java.lang.Math documentation, you will see that it does not have an API to allow setting of a random number generator seed. Code using the random() API does not get the ability to set the seed or hold onto different copies of the random number generator.

    The original question was:

    I want to be able to generate repeatable numbers using rand in Clojure. [e.g. clojure.core/rand]

    This is not possible, unless you use your own rand function. So, instead of clojure.core/rand, I suggesting using clojure.data.generators which exposes the random number generator as a dynamic var *rnd*:

    (def ^:dynamic ^java.util.Random
         *rnd*
         "Random instance for use in generators. By consistently using this
    instance you can get a repeatable basis for tests."
         (java.util.Random. 42))
    

    Use gen/*rnd* as shown in this example:

    (require '[clojure.data.generators :as gen])
    (binding [gen/*rnd* (java.util.Random. 12345)]
      (gen/int))
    

    This always returns -593551136.

提交回复
热议问题