From: jzakiya@... Date: 2017-02-13T17:53:26+00:00 Subject: [ruby-core:79521] [Ruby trunk Misc#13209] fact.rb in ruby/sample variations Issue #13209 has been updated by Jabari Zakiya. Added another version using the **step** method, in **fact3**. It's faster than using **downto** and neck-in-neck with using **reduce** as n gets bigger. ``` def fact(n) return 1 if n == 0 f = 1 n.downto(1) do |i| f *= i end return f end def fact1(n) return 1 if n | 1 == 1 # if n 0 or 1 f = 2 n.downto(3) do |i| f *= i end return f end def fact2(n) return 1 if n | 1 == 1 # if n 0 or 1 (2..n).reduce(:*) end def fact3(n) return 1 if n | 1 == 1 # if n 0 or 1 f = 2 3.step(n) {|i| f *= i } f end require 'benchmark/ips' Benchmark.ips do |x| n = 100 puts "factorials tests for n = #{n}" x.report("original factorial") { fact n } x.report("modified factorial") { fact1 n } x.report("enhanced factorial") { fact2 n } x.report("withstep factorial") { fact3 n } x.compare! end ``` Here are benchmark results for various values of n. ``` 2.4.0 :074 > load 'factversiontest.rb' factorials tests for n = 50 Warming up -------------------------------------- original factorial 12.555k i/100ms modified factorial 13.201k i/100ms enhanced factorial 16.157k i/100ms withstep factorial 15.874k i/100ms Calculating ------------------------------------- original factorial 130.394k (�� 3.0%) i/s - 652.860k in 5.011491s modified factorial 139.530k (�� 3.4%) i/s - 699.653k in 5.020706s enhanced factorial 168.796k (�� 2.9%) i/s - 856.321k in 5.077542s withstep factorial 168.096k (�� 3.8%) i/s - 841.322k in 5.012920s Comparison: enhanced factorial: 168795.7 i/s withstep factorial: 168095.7 i/s - same-ish: difference falls within error modified factorial: 139530.0 i/s - 1.21x slower original factorial: 130394.5 i/s - 1.29x slower => true 2.4.0 :075 > load 'factversiontest.rb' factorials tests for n = 70 Warming up -------------------------------------- original factorial 6.986k i/100ms modified factorial 7.346k i/100ms enhanced factorial 8.775k i/100ms withstep factorial 8.729k i/100ms Calculating ------------------------------------- original factorial 74.263k (�� 4.1%) i/s - 377.244k in 5.088997s modified factorial 77.018k (�� 4.2%) i/s - 389.338k in 5.065362s enhanced factorial 91.759k (�� 3.1%) i/s - 465.075k in 5.073560s withstep factorial 90.324k (�� 3.5%) i/s - 453.908k in 5.031665s Comparison: enhanced factorial: 91759.4 i/s withstep factorial: 90323.5 i/s - same-ish: difference falls within error modified factorial: 77017.6 i/s - 1.19x slower original factorial: 74262.9 i/s - 1.24x slower => true 2.4.0 :076 > load 'factversiontest.rb' factorials tests for n = 80 Warming up -------------------------------------- original factorial 5.887k i/100ms modified factorial 6.193k i/100ms enhanced factorial 7.197k i/100ms withstep factorial 7.178k i/100ms Calculating ------------------------------------- original factorial 61.279k (�� 3.4%) i/s - 306.124k in 5.001437s modified factorial 59.091k (��17.6%) i/s - 284.878k in 5.066603s enhanced factorial 73.394k (�� 5.7%) i/s - 367.047k in 5.021211s withstep factorial 73.323k (�� 3.1%) i/s - 373.256k in 5.095652s Comparison: enhanced factorial: 73393.6 i/s withstep factorial: 73323.3 i/s - same-ish: difference falls within error original factorial: 61279.1 i/s - 1.20x slower modified factorial: 59091.0 i/s - same-ish: difference falls within error => true 2.4.0 :077 > load 'factversiontest.rb' factorials tests for n = 90 Warming up -------------------------------------- original factorial 5.058k i/100ms modified factorial 5.269k i/100ms enhanced factorial 6.110k i/100ms withstep factorial 5.910k i/100ms Calculating ------------------------------------- original factorial 52.231k (�� 3.1%) i/s - 263.016k in 5.040608s modified factorial 52.933k (�� 5.0%) i/s - 268.719k in 5.090458s enhanced factorial 62.426k (�� 3.1%) i/s - 317.720k in 5.094697s withstep factorial 61.210k (�� 4.1%) i/s - 307.320k in 5.030274s Comparison: enhanced factorial: 62426.3 i/s withstep factorial: 61210.0 i/s - same-ish: difference falls within error modified factorial: 52933.4 i/s - 1.18x slower original factorial: 52230.8 i/s - 1.20x slower => true 2.4.0 :078 > load 'factversiontest.rb' factorials tests for n = 100 Warming up -------------------------------------- original factorial 4.450k i/100ms modified factorial 4.580k i/100ms enhanced factorial 5.259k i/100ms withstep factorial 5.195k i/100ms Calculating ------------------------------------- original factorial 45.211k (�� 5.0%) i/s - 226.950k in 5.034319s modified factorial 46.402k (�� 3.7%) i/s - 233.580k in 5.040945s enhanced factorial 53.148k (�� 4.2%) i/s - 268.209k in 5.055701s withstep factorial 52.588k (�� 3.2%) i/s - 264.945k in 5.043348s Comparison: enhanced factorial: 53148.1 i/s withstep factorial: 52588.5 i/s - same-ish: difference falls within error modified factorial: 46401.9 i/s - 1.15x slower original factorial: 45210.5 i/s - 1.18x slower => true 2.4.0 :079 > load 'factversiontest.rb' factorials tests for n = 150 Warming up -------------------------------------- original factorial 2.699k i/100ms modified factorial 2.759k i/100ms enhanced factorial 3.071k i/100ms withstep factorial 2.960k i/100ms Calculating ------------------------------------- original factorial 27.169k (�� 4.6%) i/s - 137.649k in 5.078680s modified factorial 27.344k (�� 4.7%) i/s - 137.950k in 5.056891s enhanced factorial 30.398k (�� 3.9%) i/s - 153.550k in 5.059403s withstep factorial 29.730k (�� 3.5%) i/s - 150.960k in 5.084036s Comparison: enhanced factorial: 30398.2 i/s withstep factorial: 29730.3 i/s - same-ish: difference falls within error modified factorial: 27343.9 i/s - 1.11x slower original factorial: 27168.7 i/s - 1.12x slower => true 2.4.0 :080 > ``` ---------------------------------------- Misc #13209: fact.rb in ruby/sample variations https://bugs.ruby-lang.org/issues/13209#change-62968 * Author: Jabari Zakiya * Status: Open * Priority: Normal * Assignee: ---------------------------------------- I was looking at some of the Sample files that come with Ruby and saw the example for doing factorials. It's an old example that I thought I could make simpler/faster. Below are the results. Maybe upgrading to show the difference between coding idioms can be instructive to newer Ruby programmers. ``` def fact(n) return 1 if n == 0 f = 1 n.downto(1) do |i| f *= i end return f end def fact1(n) return 1 if n | 1 == 1 # if n 0 or 1 f = 2 n.downto(3) do |i| f *= i end return f end def fact2(n) return 1 if n | 1 == 1 # if n 0 or 1 (2..n).reduce(:*) end require 'benchmark/ips' Benchmark.ips do |x| x.report("original factorial") { fact 100 } x.report("modified factorial") { fact1 100 } x.report("enhanced factorial") { fact2 100 } x.compare! end ``` Timings using ruby-2.4.0 on Linux 64-bit, on I7 cpu system. ``` 2.4.0 :001 > load 'factversiontest.rb' Warming up -------------------------------------- original factorial 4.501k i/100ms modified factorial 4.594k i/100ms enhanced factorial 5.271k i/100ms Calculating ------------------------------------- original factorial 44.962k (�� 4.2%) i/s - 225.050k in 5.015176s modified factorial 46.288k (�� 3.2%) i/s - 234.294k in 5.066948s enhanced factorial 53.425k (�� 3.1%) i/s - 268.821k in 5.036635s Comparison: enhanced factorial: 53424.9 i/s modified factorial: 46288.0 i/s - 1.15x slower original factorial: 44961.5 i/s - 1.19x slower => true 2.4.0 :002 > ``` -- https://bugs.ruby-lang.org/ Unsubscribe: