Вот что я придумал:
require 'benchmark'
class RangeRandom
def initialize(ranges=[])
# sanity checks need to go here for things like:
# backward/inverted ranges: (0..-1)
# range overlaps: (0..2 & 1..3)
# could combine ranges, or raise an exception
#
# Restrict to ranges that pass ".inclusive?"?
# the end value is informative only
@prepped_ranges = ranges.map{ |r| [ r.begin, r.end - r.begin, r.end ] }
end
def rand
range = @prepped_ranges[ Kernel::rand( @prepped_ranges.size ) ]
range[0] + Kernel::rand( range[1] )
end
end
Некоторые тесты:
range_random = RangeRandom.new([0..10, 90..100])
5.times do
puts range_random.rand
end
puts
# >> 94
# >> 97
# >> 92
# >> 92
# >> 8
n = 500_000
Benchmark.bm(7) do |x|
x.report('rand1:') { n.times do ; r = RangeRandom.new([ 0..1 ]); r.rand; end }
x.report('rand2:') { n.times do ; r = RangeRandom.new([ 0..1_000_000 ]); r.rand; end }
x.report('rand3:') { n.times do ; r = RangeRandom.new([ 0..1_000_000_000 ]); r.rand; end }
x.report('rand4:') { n.times do ; r = RangeRandom.new([ 0..1 ]); r.rand; end }
x.report('rand5:') { n.times do ; r = RangeRandom.new([ 0..1, 2..3, 4..5, 6..7 ]); r.rand; end }
x.report('rand6:') { r = RangeRandom.new([ 0..1 ]) ; n.times do ; r.rand; end }
x.report('rand7:') { r = RangeRandom.new([ 0..1_000_000_000 ]) ; n.times do ; r.rand; end }
end
Общее время выполнения для 500 000 итераций:
# >> user system total real
# >> rand1: 2.220000 0.000000 2.220000 ( 2.224894)
# >> rand2: 2.250000 0.010000 2.260000 ( 2.254730)
# >> rand3: 2.250000 0.000000 2.250000 ( 2.247406)
Время дляИнициализация нескольких диапазонов для 500 000 итераций:
# >> rand4: 2.220000 0.000000 2.220000 ( 2.222983)
# >> rand5: 4.340000 0.000000 4.340000 ( 4.337312)
Время для одной инициализации, затем маленький диапазон или большой диапазон для 500 000 итераций:
# >> rand6: 0.560000 0.000000 0.560000 ( 0.559673)
# >> rand7: 0.580000 0.000000 0.580000 ( 0.584331)
Время увеличивается при использовании большихдиапазоны, но это могут быть вариации из-за активности системы.Инициализация нескольких диапазонов в массиве имеет больший эффект, чего я и ожидал.