嗨,我正在做一个简单的函数,以升序生成一个float数组,但是我想知道是否有一种更简单的方法来做到这一点。 我将使用它来创建表,以便生成随机数学问题,以通过Lagrange数值方法解决它们。
lagrange方法使用X,F(X)和X0,其中X0必须在X的范围内,否则不能解决问题
到目前为止,这是我的代码
System.Drawing.Bitmap
编辑:更新了代码
答案 0 :(得分:0)
代码本身看起来不错,可以满足您的目的。是否将在何处使用上下文?因为“简单性”可能是由代码的上下文驱动的。
例如
您可以配置所需的随机数数量和随机数范围。您可以在外部配置排序顺序。
您可以将其封装在实用程序类中,并将其像API一样公开给其他类。
如果需要一百万个随机排序的数字,您是否希望数字流式传输?如果是这样,那就有Ruby库。
...还有更多。上下文将是有用的。希望这可以帮助。
答案 1 :(得分:0)
正如Sid所指出的那样,当您问“是否有更简单的方法来做到这一点”时,很大程度上取决于上下文。如果通过“更简单”的方法来寻找效率,那么答案不仅仅在于有多少行代码。
如果您真的想将所有订单统计信息看作一个集合,那么可以说使用Ruby的块构造函数将您的方法转换为单行代码更具可读性,并且从下面提供的实现中看到的时间表明它稍微快一些,但仅百分之几。
但是,如果您有一个非常大的N并按顺序处理这些值,那么您可能更喜欢生成器方法。下面实现为ordered_random_generator
的元素是每个元素O(1)的计算和存储,如果您在使用完每个元素后将其丢弃,则将O(N)生成整个集合,但是将O(1)存储。如果存储元素,则实际上这比基于排序的方法要慢,这是因为在计算中评估第k 个根的成本很高。
另一种可能性是,您实际上并不对整个值集合感兴趣,而是使用它来获取特定的分位数或顺序统计信息,例如,在100个有序元素中的第10个。在这种情况下,您可以在O(1)的时间内,以O(1)存储的正确distribution of the kth order statistic out of N来直接生成一个随机值。
这是各种选项的实现,显示了生成整个数组的三种方法的时序,并显示了第四种方法的分布有效性。
# Your original.
# O(N log N) time due to sort, O(N) storage.
def ordered_random1(n, range_spec = 1.0..n)
ary = []
n.times do
value = rand(range_spec)
ary << value
end
ary.sort!
end
# Same sort-based algorithm using Ruby's Array constructor with a block.
# O(N log N) time due to sort, O(N) storage.
def ordered_random2(n, range_spec = 1.0..n)
Array.new(n) { rand(range_spec) }.sort!
end
# Generator which uses distributional properties to generate the minimum of
# k uniforms from k = N down to 1, scaling the result down to the remaining
# sub-range of the original range.
# O(1) time per element, O(1) storage. However, computation time has a very
# large constant due to the transcendental function evaluation for kth root.
def ordered_random_generator(n, range_spec = 1.0..n)
x = range_spec.first
upper = range_spec.last
Enumerator.new do |yielder|
n.times do |i|
range = upper - x
u_min = 1.0 - rand ** (1.0 / (n - i))
x += range * u_min
yielder.yield x
end
end
end
# Use generator to fill array of size N.
# O(N) time and storage.
def ordered_random3(n, range_spec = 1.0..n)
gen = ordered_random_generator(n, range_spec)
Array.new(n) { gen.next }
end
require 'random_variates' # 'gem install random_variates' to get from rubygems
# Use distributional properties of uniform order statistics to directly
# generate instances of the kth of N values.
# O(1) time, O(1) storage.
def kth_of_n_generator(k:, n:, range_spec: 0.0..1.0)
# Uniform order stats have a beta distribution. Beta is a ratio of Gammas.
x = Gamma.new(alpha: k).next
y = Gamma.new(alpha: n - k + 1).next
beta = x / (x + y)
(range_spec.last - range_spec.first) * beta + range_spec.first
end
# Time for Demos!
my_range = 0.1..15.1
puts "SAMPLE OUTPUT FOR RANGE = #{my_range}:"
puts " original: #{ordered_random1(5, my_range)}"
puts "one-liner: #{ordered_random2(5, my_range)}"
puts "generator: #{ordered_random3(5, my_range)}"
puts "direct generation of min & max using kth_of_n_generator: #{
kth_of_n_generator(k: 1, n: 5, range_spec: my_range)
}, #{
kth_of_n_generator(k: 5, n: 5, range_spec: my_range)
}"
REPS = 10_000
n = 9
puts "\nDEMO DISTRIBUTIONAL CORRECTNESS OF SINGLETON GENERATOR (range = 0.0..1.0)"
(1..n).each do |k|
total = Array.new(REPS) { kth_of_n_generator(k: k, n: n) }.inject(:+)
quantile = k.to_f / (n + 1)
suffix = case k
when 1
"st"
when 2
"nd"
when 3
"rd"
else
"th"
end
print "Average of #{REPS} values of #{k}#{suffix} of #{n}: #{total / REPS} "
puts "[Expected value is #{quantile}]"
end
require 'benchmark/ips'
[100, 10_000].each do |n|
puts "\nBENCHMARKING ARRAYS OF SIZE #{n}"
Benchmark.ips do |b|
b.report(' original:') { ordered_random1(n, my_range) }
b.report('one-liner:') { ordered_random2(n, my_range) }
b.report('generator:') { ordered_random3(n, my_range) }
b.compare!
end
end
这是我的机器上的输出示例。您的时间安排会根据您的硬件,操作系统和所运行的Ruby版本而有所不同。由于随机性,每次运行的具体值会有所不同,但是是一致的。
SAMPLE OUTPUT FOR RANGE = 0.1..15.1:
original: [3.2143763318277223, 3.424117583339602, 4.98763316107166, 7.67915049946293, 13.002051529711663]
one-liner: [3.698584735327408, 3.7940473868424713, 8.133265097991108, 10.797493427133121, 13.519291528088747]
generator: [1.379949057529254, 3.330310564043854, 14.175279996588, 14.187770450655005, 14.747374304212487]
direct generation of min & max using kth_of_n_generator: 2.3844682728553956, 14.093371351681753
DEMO DISTRIBUTIONAL CORRECTNESS OF SINGLETON GENERATOR (range = 0.0..1.0)
Average of 10000 values of 1st of 9: 0.10061353514079374 [Expected value is 0.1]
Average of 10000 values of 2nd of 9: 0.19841217568287062 [Expected value is 0.2]
Average of 10000 values of 3rd of 9: 0.3018753486695847 [Expected value is 0.3]
Average of 10000 values of 4th of 9: 0.40002514960574265 [Expected value is 0.4]
Average of 10000 values of 5th of 9: 0.5003591617651723 [Expected value is 0.5]
Average of 10000 values of 6th of 9: 0.5974291957317844 [Expected value is 0.6]
Average of 10000 values of 7th of 9: 0.6980418879340753 [Expected value is 0.7]
Average of 10000 values of 8th of 9: 0.8012294219961899 [Expected value is 0.8]
Average of 10000 values of 9th of 9: 0.9002379495094114 [Expected value is 0.9]
BENCHMARKING ARRAYS OF SIZE 100
Warming up --------------------------------------
original: 4.037k i/100ms
one-liner: 4.242k i/100ms
generator: 773.000 i/100ms
Calculating -------------------------------------
original: 40.412k (± 2.0%) i/s - 205.887k in 5.096825s
one-liner: 41.852k (± 2.3%) i/s - 212.100k in 5.070662s
generator: 7.676k (± 4.2%) i/s - 38.650k in 5.045488s
Comparison:
one-liner:: 41852.1 i/s
original:: 40412.3 i/s - same-ish: difference falls within error
generator:: 7675.6 i/s - 5.45x slower
BENCHMARKING ARRAYS OF SIZE 10000
Warming up --------------------------------------
original: 29.000 i/100ms
one-liner: 30.000 i/100ms
generator: 7.000 i/100ms
Calculating -------------------------------------
original: 295.387 (± 2.0%) i/s - 1.479k in 5.009243s
one-liner: 304.406 (± 2.0%) i/s - 1.530k in 5.028485s
generator: 78.104 (± 2.6%) i/s - 392.000 in 5.020934s
Comparison:
one-liner:: 304.4 i/s
original:: 295.4 i/s - same-ish: difference falls within error
generator:: 78.1 i/s - 3.90x slower
请注意,对于此处测试的两种阵列大小,生成器方法都比两种基于排序的方法慢。由于O(N)与O(N log N)的渐近行为,对于较大的数组而言,这种差距正在缩小,但如果您的主要关注点是速度,那么可能不足以引起关注。