'How do include the upper limit of `rand` in Clojure?
In Clojure's rand function, the lower limit 0 is included, but the upper limit is not.
How to define a rand function equivalent which includes the upper limit?
Solution 1:[1]
Edit (simple explanation): Because rand generates a random double between 0 and 1 by generating an integer and dividing my another integer, you can implement a version with inclusive upper bound as
(defn rand-with-nbits [nbits]
(let [m (bit-shift-left 1 nbits)]
(/ (double (rand-int m))
(double (dec m)))))
(apply max (repeatedly 1000 #(rand-with-nbits 3)))
;; => 1.0
In the implementation, 53 bits are used, that is (rand-with-nbits 53).
Longer answer:
Take a look at the source code of rand. It internally calls Math.random, which in turn calls Random.nextDouble, that has the following implementation:
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
...
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}
The above code essentially produces a random integer between 0 and 2^53-1 and divides it by by 2^53. To get an inclusive upper bound, you would instead have to divide it by 2^53-1. The above code calls the next method which is protected, so to make our own tweaked implementation, we use proxy:
(defn make-inclusive-rand [lbits rbits]
(let [denom (double
(dec ; <-- `dec` makes upper bound inclusive
(bit-shift-left
1 (+ lbits rbits))))
g (proxy [java.util.Random] []
(nextDouble []
(/ (+ (bit-shift-left
(proxy-super next lbits) rbits)
(proxy-super next rbits))
denom)))]
(fn [] (.nextDouble g))))
(def my-rand (make-inclusive-rand 26 27))
It is unlikely that you will ever generate the upper bound:
(apply max (repeatedly 10000000 my-rand))
;; => 0.9999999980774417
However, if the underlying integers are generated with fewer bits, you will see that it works:
(def rand4 (make-inclusive-rand 2 2))
(apply max (repeatedly 100 rand4))
;; => 1.0
By the way, the above implementation is not thread-safe.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
