【问题标题】:Why won't std::uniform_real_distribution generate proper floating values?为什么 std::uniform_real_distribution 不会生成正确的浮点值?
【发布时间】:2020-11-12 06:12:28
【问题描述】:

我正在尝试打印随机浮点(32 位)值。为此,我尝试使用uniform_real_distribution。我写了以下代码,

int main()
{
  std::random_device rd{};
  std::mt19937 gen{rd()};

  std::uniform_real_distribution<float> dist(-1e18,1e18);

  float random_val = dist(gen);

  printf("%.20f\n", random_val);

  return 0;
}

现在,输出很奇怪。我得到的只是非常大的数字(总是接近上限或下限),没有分数。以下是我看到的一些输出,

-149399166081040384.00000000000000000000
128349565723082752.00000000000000000000
-323890424458510336.00000000000000000000
802221481969844224.00000000000000000000
817395979383734272.00000000000000000000

他们总是这样,我改变界限也没关系。这里有什么问题?

【问题讨论】:

标签: c++ random distribution


【解决方案1】:

float 通常为IEEE Single-precision floating-point format,其工作方式类似于科学计数法,有 1 个符号位、8 个指数位和 23+1 个小数位。 所以 817395979383734272.0 在内存中存储为 1.41795599 * 2^59 。该小数部分只有约 8 个十进制数字,因为这就是它可以挤入约 24 位的所有精度。 Mark Ransom 提醒我,因此,所有大于 ~100,000,000 的 floats 都将是整数,只是因为它们没有足够的位来存储任何小数部分。

由于小数部分大约有 24 位,这意味着它可以保存 7.2 位十进制数字的精度。所以前 7 个十进制数字是准确的,第 8 个十进制数字是半准确的,随后的十进制数字在将float 渲染为文本时实际上是随机的。

817395979383734272.0
^      ^^          
|      |basically random
|      semi-accurate
accurate

对于double(使用IEEE Double-precision floating-point format),它使用1 个符号位、11 个指数位和52+1 个小数位。这可以准确地存储 15.9 位十进制数字,因此仍然可以保存小数部分,直到值大于 ~1,000,000,000,000,000。

David Shwartz 还指出,通常假设随机浮点数会有一些小数和一些大数,但从数学上讲,几乎所有均匀随机生成的浮点数都在最大值的两个数量级之内。在你的情况下,那是 >1e16 和

【讨论】:

  • 一旦达到某个限制,由于二进制数的结构方式,所有浮点数都将是整数。没有足够的位给你任何分数。它与实现无关。
  • @MarkRansom:哦,对了!我完全忽略了这方面。
  • @DavidSchwartz:我认为这不是很重要,但以防万一,我添加了一条注释。
【解决方案2】:

数字没有小数位的原因是因为 32 位浮点无法存储带有小数位的大数字。使用 32 位浮点数只能获得大约 7 位十进制数字的精度。因此,任何大于 1e7 的数字都会有超过第 7 位的数字,这些数字充其量是不可靠的值,最终毫无意义。

在你的情况下,这恰好是一堆零。

您的数字偏大的原因是 [-1e18, 1e18) 范围内的大多数数字都很大。 [-1, 1) 范围内的数字集仅为 [-10, 10) 范围内数字的 10%(大约)。它本身只是 [-100, 100) 范围内数字的 10%(大约)。等等。因此,在 [-1e18, 1e18) 范围内获得偶数 5 位数字的机会是彩票中奖几率。

请记住:分布尝试在范围内随机均匀选择,而不是生成对应于有效浮点数的随机 32 位。

【讨论】:

    猜你喜欢
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    • 2017-07-11
    相关资源
    最近更新 更多