Я подумал, что было бы интересно сравнить различные методы. Есть сюрпризы?
require 'benchmark'
require 'prime'
def duckets(num)
(1..1+num/2).each {|n| return true if n*n == num }
false
end
def steenslag(num)
Integer.sqrt(num)**2 == num
end
def iGian(num)
num.prime_division.all? { |_, exp| exp % 2 == 0 }
end
def cary(num)
(1..1+num/2).bsearch { |n| n*n >= num }**2 == num
end
def test(arr, meth)
arr.map { |num| method(meth).call(num) }
end
Этот метод сопоставляет каждый элемент arr
с true
если это идеальный квадрат (иначе false
), используя метод meth
(символ).
def benchem(arr)
Benchmark.bm do |x|
x.report("enumerate") { test(arr, :duckets) }
x.report("integer_sqrt") { test(arr, :steenslag) }
x.report("prime_divisors") { test(arr, :iGian) }
x.report("bsearch") { test(arr, :cary) }
end
end
benchem([*2..100])
user system total real
enumerate 0.000244 0.000000 0.000244 ( 0.000229) #3
integer_sqrt 0.000049 0.000000 0.000049 ( 0.000048) #1
prime_divisors 0.000963 0.000000 0.000963 ( 0.000967) #4
bsearch 0.000086 0.000000 0.000086 ( 0.000086) #2
benchem([*101..1000])
user system total real
enumerate 0.018636 0.000000 0.018636 ( 0.018662) #4
integer_sqrt 0.000252 0.000000 0.000252 ( 0.000255) #1
prime_divisors 0.003402 0.000000 0.003402 ( 0.003407) #3
bsearch 0.000870 0.000000 0.000870 ( 0.000872) #2
benchem([*1001..10000])
user system total real
enumerate 1.345501 0.000000 1.345501 ( 1.345650) #4
integer_sqrt 0.004647 0.000000 0.004647 ( 0.004655) #1
prime_divisors 0.048204 0.000000 0.048204 ( 0.048226) #3
bsearch 0.010349 0.000000 0.010349 ( 0.010362) #2
benchem([*10001..100000])
user system total real
enumerate 147.814253 0.000000 147.814253 (147.833672) #4
integer_sqrt 0.036118 0.000000 0.036118 ( 0.036115) #1
prime_divisors 0.889245 0.000000 0.889245 ( 0.889367) #3
bsearch 0.127438 0.000000 0.127438 ( 0.127459) #2