Created
January 4, 2017 06:24
-
-
Save stephancom/174aa5df0f8e689a30669328a111ee1d to your computer and use it in GitHub Desktop.
FizzBuzz - generalized, improved, tested, benchmarked
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# fizzbuzz benchmark - comparing different versions of the classic | |
# stephan.com | |
require 'rspec' | |
require 'benchmark' | |
require 'formatador' | |
# suppress output | |
def no_stdout | |
ostd = $stdout | |
$stdout = StringIO.new | |
yield | |
$stdout = ostd | |
end | |
# generalized version with classic method | |
def genfizz(n,msgs) | |
1.upto(n) do |i| | |
str = msgs.inject('') do |str, (m, text)| | |
(i%m==0) ? str + text : str | |
end | |
puts str.empty? ? i : str | |
end | |
end | |
def fizzbuzz(n) | |
genfizz(n, 3 => 'fizz', 5 => 'buzz') | |
end | |
# generalized version with seive method | |
def seivefizz(n, msgs) | |
texts = msgs.inject([]) do |texts, (m, text)| | |
(m..n).step(m) do |i| | |
texts[i] = (texts[i] || '') + text | |
end | |
texts | |
end | |
1.upto(n) do |i| | |
puts texts[i] || i | |
end | |
end | |
# tests to make sure these things actually work | |
shared_examples 'fizzbuzz' do | |
let(:count) { fizzout.length } | |
it 'should call puts N times' do | |
expect(STDOUT).to receive(:puts).exactly(count).times | |
end | |
it 'should print the expected output' do | |
fizzout.each_with_index do |str, i| | |
expect(STDOUT).to receive(:puts).once.with(str).ordered | |
end | |
end | |
end | |
describe 'classic fizzbuzz' do | |
let(:fizzout) { [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz'] } | |
it_should_behave_like 'fizzbuzz' | |
after do | |
fizzbuzz(count) | |
end | |
end | |
describe 'seive fizzbuzz' do | |
let(:msgs) { { 3 => 'fizz', 5 => 'buzz', 7 => 'yahoo', 11 => 'yada' } } | |
let(:fizzout) { [1, 2, 'fizz', 4, 'buzz', 'fizz', 'yahoo', 8, 'fizz', 'buzz', | |
'yada', 'fizz', 13, 'yahoo', 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', | |
'fizzyahoo', 'yada', 23, 'fizz', 'buzz', 26, 'fizz', 'yahoo', 29, 'fizzbuzz', | |
31, 32, 'fizzyada', 34, 'buzzyahoo', 'fizz', 37, 38, 'fizz', 'buzz'] } | |
it_should_behave_like 'fizzbuzz' | |
after do | |
seivefizz(count, msgs) | |
end | |
end | |
# generate seive of aristothenes for use in bechmarking | |
primecount = 4000 | |
primes = (0..primecount).to_a | |
2.upto(Math.sqrt(primecount)) do |p| | |
next unless primes[p] | |
((p*2)..primecount).step(p) do |i| | |
primes[i] = nil | |
end | |
end | |
primes = primes[2..-1].compact | |
# puts "#{primes.count} primes:", primes.inspect | |
# benchmarking | |
# versions = { | |
# 2 => { 3 => 'fizz', 5 => 'buzz' }, | |
# 4 => { 3 => 'fizz', 5 => 'buzz', 7 => 'yahoo', 11 => 'yada' } | |
# } | |
# create different fizzbuzz message sets for benchmarking | |
powers = [2, 4, 8, 16, 32, 64, 128, 256, 512] | |
versions = {} | |
powers.each do |power| | |
versions[power] = {} | |
primes[0..power].each do |p| | |
versions[power][p] = "fizz_#{p}_" | |
end | |
end | |
n_values = [10, 100, 1000, 10000, 100000, 1000000, 10000000] | |
marks = {} | |
progress = Formatador::ProgressBar.new(powers.count * n_values.count) | |
versions.each do |power, msgs| | |
marks[power] = {} | |
n_values.each do |n| | |
progress.increment | |
# puts "N=#{n}, #{power} msgs" | |
classic = Benchmark.measure { no_stdout { genfizz(n, msgs) }} | |
seive = Benchmark.measure { no_stdout { seivefizz(n, msgs) }} | |
marks[power][n] = if classic.utime == seive.utime | |
1 | |
elsif seive.utime == 0 | |
'inf' | |
else | |
(classic.utime / seive.utime).round(2) # store ratio of classic to seive time | |
end | |
# Benchmark.bm do |b| | |
# b.report("classic") { no_stdout { genfizz(n, msgs) } } | |
# b.report("seive") { no_stdout { seivefizz(n, msgs) } } | |
# end | |
end | |
marks[power]['msgs'] = power | |
end | |
Formatador.display_table marks.values |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment