生成均匀的随机浮点数,该浮点数可以返回所有可能的值

时间:2018-11-13 08:52:19

标签: go random floating-point

在[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之间的所有可能值”对于保持结果至关重要。

5 个答案:

答案 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。