Reputation: 45
Simple code to find a perfect square
def perfect_square(num)
(1..num).each {|n| return true if n*n == num }
false
end``
Is there a way to get the first line to return false instead of having to use a new line with just false below it?
Upvotes: 1
Views: 164
Reputation: 110685
I thought it might be interesting to benchmark the various methods. Any surprises?
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
This method maps each element of arr
to true
if it is a perfect square (else false
), using method meth
(a symbol).
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
Upvotes: 1
Reputation: 80065
Ruby has Integer::sqrt since version 2.5
def perfect_square(num)
Integer.sqrt(num)**2 == num
end
Upvotes: 1
Reputation: 110685
For fun, here's another way:
def perfect_square(num)
(1..1+num/2).find { |n| n*n >= num }**2 == num
end
(1..200).select { |num| perfect_square(num) }
#=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196]
For greater efficiency the operative line could be replaced with
(1..1+num/2).bsearch { |n| n*n >= num }**2 == num
See Array#bsearch.
Upvotes: 1
Reputation: 11193
Since the product of perfect squares is a perfect square, using Prime#prime_division:
require 'prime'
def perfect_square?(n)
n.prime_division.all? { |_, exp| exp % 2 == 0 }
end
Upvotes: 2
Reputation: 191
You can do this instead
def perfect_square(num)
!(1..num).find { |n| n * n == num }.nil?
end
Find any number from 1
to num
that its square is num
, check if it's not nil.
Upvotes: 0
Reputation: 369458
Newlines are optional in Ruby, so you can always trivially implement anything, no matter how complex, as a one-liner by simply removing all newlines, potentially replacing them with the appropriate alternative separator:
def perfect_square(num) (1..num).each {|n| return true if n*n == num }; false end
Upvotes: 1