在[0,1)中生成随机float64的一种简单方法是在[0,2?3)中生成均匀随机的int并将其除以2?3。本质上,这就是rand.Float64()
所做的。
但是,并不是所有可能的0到1之间的float64值都可以通过这种方式生成:例如,如果该值小于2⁻⁴,则有效位数的最后4位始终为0。或者,更简单地说,天真的方法总是返回2 3的倍数,并且并非所有0到1之间的浮点数都是2 3的倍数。
如何生成均匀随机的float64,例如每个可能的值都有返回的机会? (在这里,均匀随机均值表示实数区间 [0,1]:从概念上讲,我想选择一个介于0和1之间的均匀随机实数并返回最接近的浮点数。)
对于上下文,我需要这样做,因为我正在实现this paper,并且假设“表示0到1之间的所有可能值”对于保持结果至关重要。
答案 0 :(得分:2)
因为binary64浮点数的间距不是均匀的,所以无法生成均匀的分布,该分布可以返回小于1的所有可能值。
如果省略要求 uniform ,则必须生成最小正非正规数2^(-1074)
和零的所有可表示倍数。
答案 1 :(得分:2)
我认为,标准方法是生成最多1074bits的整数并将其映射到double。请注意,您的RNG应该具有至少1074位长的内部状态。
参考实现:http://xoshiro.di.unimi.it/random_real.c
有关此问题的讨论:http://xoshiro.di.unimi.it/
另一个好的链接:https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/
答案 2 :(得分:2)
移植this code(建议在Severin的答案中)。
我认为这等效于首先生成有效位(通过在[1,2]中生成随机浮点),然后从几何分布中选择指数(0.5的可能性为-1,0.25)是-2等)。
// uniform returns a uniformly random float in [0,1).
func uniform() float64 {
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())
}
// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64 {
b := 1
for rand.Uint64()%2 == 0 {
b++
}
return b
}
通过使用bits
包中的LeadingZeros*
函数之一,而不是每位硬币翻转一次,我们可能可以使geometric()更快。
答案 3 :(得分:1)
您可以通过生成16个随机字节并仅在[0,1)
中使用有效的float64时使用蛮力拒绝采样。这种方法应能使您在该范围内的所有值均呈正态分布,并且性能不会比基于简单基准测试的其他策略差很多。
例如(Go Playground):
import "math/rand"
func randFloat64() float64 {
for {
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0 {
return f
}
}
}
如果性能至关重要,则可以构建一个仅包含有效数字的庞大查找表,然后在该表中选择一个随机位置。可以通过枚举位域并仅存储有效数字,以与上述类似的方式提前生成该表。
答案 4 :(得分:-1)
您可以使用rand Float64 function返回[0,1)范围内的浮点数:
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Float64())
}
从文档中:
Float64从默认源返回[0.0,1.0)中的伪随机数作为float64。