2

假设您想生成一个介于 1 到 10 亿之间的随机数:

rand(1..1_000_000_000)

每次调用这行代码时,Ruby 会从该范围创建一个数组吗?

Rubocop 建议结束这种方法,rand(1_000_000_000)+1但似乎有可能带来痛苦。

Ruby 的文档是这样说的:

# When +max+ is a Range, +rand+ returns a random number where
# range.member?(number) == true.

+max+传递给的参数在哪里rand,但它没有说明它是如何获得number参数的。我也不确定调用.member?范围是否有效。

有任何想法吗?

我可以使用基准,但仍然对这里的内部工作感到好奇。

4

1 回答 1

4

不,Ruby 不会从该范围创建数组,除非您显式调用对象.to_a上的方法Range。实际上,rand()不适用于数组 -.sample是用于从数组中返回随机元素的方法。

该类Range包括Enumerable,因此您无需将范围转换为数组即可获得 Enumerable 的迭代方法。Range 的下限和上限是(-Float::INFINITY..Float::INFINITY),但Numerical argument out of domain如果将其传递给rand.

至于.member?,该方法只是调用一个调用的 C 函数range_cover,该函数调用另一个调用的函数,该函数r_cover_p检查一个值是否介于两个数字或字符串之间。

rand要测试将范围传递给数组和调用数组之间的速度差异sample,可以执行以下测试:

require 'benchmark'

puts Benchmark.measure { rand(0..10_000_000) }
=> 0.000000   0.000000   0.000000 (  0.000009)

puts Benchmark.measure { (0..10_000_000).to_a.sample }
=> 0.300000   0.030000   0.330000 (  0.347752)

正如您在第一个示例中看到的,将 arange作为参数传递给 torand非常快。

相反,跟注.to_a.sample范围相当慢。这是由于数组创建过程需要将适当的数据分配到内存中。该.sample方法应该相对较快,因为它只是将随机且唯一的索引传递到数组中并返回该元素。

要查看代码,range 请查看此处

于 2017-12-31T21:54:39.180 回答