Last active
May 23, 2016 05:41
-
-
Save mgaskill/96f04e7e1f72a86446f4939ac690759a to your computer and use it in GitHub Desktop.
Ruby benchmark program for a simple two-operand, one operator expression parser
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
require 'benchmark' | |
def match_gaskill(formula) | |
return [] unless (match = formula.match(/^\s*(-?\d+(?:\.\d+)?)\s*([+\/*-])\s*(-?\d+(?:\.\d+)?)\s*$/)) | |
return [match[1].to_f, match[2], match[3].to_f] | |
end | |
def match_sweaver(formula) | |
return [] unless (match = formula.match(/(?<operand1>(?:\d+(?:\.\d+)?)|(?:\.\d+))\s*(?<operator>[+\/*-])\s*(?<operand2>(?:\d+(?:\.\d+)?)|(?:\.\d+))/)) | |
return [match[1].to_f, match[2], match[3].to_f] | |
end | |
def scan_gaskill(formula) | |
return [] unless (match = formula.scan(/^\s*(-?\d+(?:\.\d+)?)\s*([+*\/-])\s*(-?\d+(?:\.\d+)?)\s*$/))[0] | |
return [match[0][0].to_f, match[0][1], match[0][2].to_f] | |
end | |
def scan_techbio(formula) | |
return [] unless (match = formula.scan(/(((\d\.?)+)|[\+\-\*\/])/)) | |
return match.map.with_index {|x,i| i.even? ? x[0].to_f : x[0] } | |
end | |
def split_gaskill(formula) | |
match = formula.split(/(-?\d+(?:\.\d+)?)\s*([+\/*-])\s*(-?\d+(?:\.\d+)?)/) | |
return [match[1].to_f, match[2], match[3].to_f] | |
end | |
def partition_swoveland(formula) | |
f,op,l = formula.delete(' ').partition(/(?<=\d)[^\d\.]/x) | |
return [f.to_f, op, l.to_f] | |
end | |
def split_swoveland(formula) | |
f,op,l = formula.split(/([+\/*-])/) | |
return [f.to_f, op, l.to_f] | |
end | |
def split_swoveland2(formula) | |
f,op,l = formula.split(/\b\s*([+\/*-])\s*/) | |
return [f.to_f, op, l.to_f] | |
end | |
def split_lilue(formula) | |
return formula.split(%r{(\+|\-|\/|\*)}).map do |x| | |
unless x =~ /(\+|\-|\/|\*)/ then x.to_f else x end | |
end | |
end | |
def operand_report(result, operands) | |
"#{(result == operands) ? 'Pass' : ' -- '}" | |
end | |
formulae = [ | |
["1+12", [1.0, "+", 12.0]], | |
["6/0.25", [6.0, "/", 0.25]], | |
["3/0.125", [3.0, "/", 0.125]], | |
["30-6", [30.0, "-", 6.0]], | |
["3*8", [3.0, "*", 8.0]], | |
["20--4", [20.0, "-", -4.0]], | |
["33+-9", [33.0, "+", -9.0]], | |
["-12*-2", [-12.0, "*", -2.0]], | |
["-72/-3", [-72.0, "/", -3.0]], | |
["34 - 10", [34.0, "-", 10.0]], | |
[" 15+ 9", [15.0, "+", 9.0]], | |
["4*6 ", [4.0, "*", 6.0]], | |
["b+0.5", []], | |
["8---0.5", []], | |
["8+6+10", []], | |
["15*x", []], | |
["1.A^ff", []] | |
] | |
puts "| Test Case | match | match | scan | scan |partition| split | split | split | split |" | |
puts "| | Gaskill | sweaver | Gaskill | techbio |Swoveland| Gaskill |Swoveland|Swoveland+| Lilue |" | |
puts "|------------------------------------------------------------------------------------------------------|" | |
formulae.each do |pair| | |
formula = pair[0] | |
result = pair[1] | |
func_a = operand_report result, match_gaskill(pair[0]) | |
func_b = operand_report result, match_sweaver(pair[0]) | |
func_c = operand_report result, scan_gaskill(pair[0]) | |
func_d = operand_report result, scan_techbio(pair[0]) | |
func_e = operand_report result, partition_swoveland(pair[0]) | |
func_f = operand_report result, split_gaskill(pair[0]) | |
func_g = operand_report result, split_swoveland(pair[0]) | |
func_h = operand_report result, split_swoveland2(pair[0]) | |
func_i = operand_report result, split_lilue(pair[0]) | |
puts "| #{formula.inspect.ljust(9)} | #{func_a.center(7)} | #{func_b.center(7)} | #{func_c.center(7)} | #{func_d.center(7)} | #{func_e.center(7)} | #{func_f.center(7)} | #{func_g.center(7)} | #{func_h.center(8)} | #{func_h.center(7)} |" | |
# puts "|------------------------------------------------------------------------------------------------------|" | |
end | |
numbers = (0..1000).map {|n| n / 8 } | |
operators = ["+", "-", "*", "/"] | |
a = 1_000_000.times.map {|n| "#{numbers.sample}#{operators.sample}#{numbers.sample}" } | |
puts "" | |
puts "" | |
puts RUBY_DESCRIPTION | |
puts "============================================================" | |
Benchmark.bm(25) do |x| | |
x.report("match (Gaskill):") { a.each {|formula| match_gaskill(formula) } } | |
x.report("match (sweaver2112):") { a.each {|formula| match_sweaver(formula) } } | |
x.report("scan (Gaskill):") { a.each {|formula| scan_gaskill(formula) } } | |
x.report("scan (techbio):") { a.each {|formula| scan_techbio(formula) } } | |
x.report("partition (Swoveland):") { a.each {|formula| partition_swoveland(formula) } } | |
x.report("split (Gaskill):") { a.each {|formula| split_gaskill(formula) } } | |
x.report("split (Swoveland):") { a.each {|formula| split_swoveland(formula) } } | |
x.report("split (Swoveland+):") { a.each {|formula| split_swoveland2(formula) } } | |
x.report("split (Lilue):") { a.each {|formula| split_lilue(formula) } } | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment