如何在 Clojure 中包含 rand 的上限?
How do include the upper limit of `rand` in Clojure?
在Clojure的rand
函数中,包含了下限0,但没有包含上限。
如何定义包含上限的rand
等价函数?
编辑(简单解释):因为rand
通过生成一个整数除以我的另一个整数来生成0到1之间的随机double,可以实现一个版本包含上限为
(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
实现中使用了53位,即(rand-with-nbits 53)
。
更长的答案:
看看 source code of rand. It internally calls Math.random, which in turn calls Random.nextDouble,它有以下实现:
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;
}
上面的代码本质上是生成一个介于0
和2^53-1
之间的随机整数,并将它除以2^53
。要获得包含上限,您必须将其除以 2^53-1
。上面的代码调用了受保护的 next
方法,所以为了让我们自己调整实现,我们使用 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))
您不太可能生成上限:
(apply max (repeatedly 10000000 my-rand))
;; => 0.9999999980774417
但是,如果底层整数是用 更少的位 生成的,您会发现它有效:
(def rand4 (make-inclusive-rand 2 2))
(apply max (repeatedly 100 rand4))
;; => 1.0
对了,上面的实现是不是thread-safe。
在Clojure的rand
函数中,包含了下限0,但没有包含上限。
如何定义包含上限的rand
等价函数?
编辑(简单解释):因为rand
通过生成一个整数除以我的另一个整数来生成0到1之间的随机double,可以实现一个版本包含上限为
(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
实现中使用了53位,即(rand-with-nbits 53)
。
更长的答案:
看看 source code of rand. It internally calls Math.random, which in turn calls Random.nextDouble,它有以下实现:
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;
}
上面的代码本质上是生成一个介于0
和2^53-1
之间的随机整数,并将它除以2^53
。要获得包含上限,您必须将其除以 2^53-1
。上面的代码调用了受保护的 next
方法,所以为了让我们自己调整实现,我们使用 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))
您不太可能生成上限:
(apply max (repeatedly 10000000 my-rand))
;; => 0.9999999980774417
但是,如果底层整数是用 更少的位 生成的,您会发现它有效:
(def rand4 (make-inclusive-rand 2 2))
(apply max (repeatedly 100 rand4))
;; => 1.0
对了,上面的实现是不是thread-safe。