On 10/26/06, Phrogz <gavin / refinery.com> wrote: > Rick DeNatale wrote: > > (int & 1).zero? is probably faster than > > int[0].zero? > > > > Since the latter generates the mask using the bit position. > > > > and both should be faster than > > > > (int % 2).zero? > > > > But it it's performance critical, benchmarking is recommended to > > verify. One should never simply take 'rules of thumb' for granted. > > Let's just do it rather than speculating: > > require 'benchmark' > > ITERATIONS = 1_000_000 > MAX_INT = 2 ** 30 > NUMS = (1..ITERATIONS).map{ rand(MAX_INT) } > Benchmark.bmbm{ |x| > x.report '(n % 2).zero?' do > NUMS.each{ |n| > (n % 2).zero? > } > end > > x.report 'n[0].zero?' do > NUMS.each{ |n| > n[0].zero? > } > end > > x.report '(n & 1).zero?' do > NUMS.each{ |n| > (n & 1).zero? > } > end > } > > #=> Rehearsal ------------------------------------------------- > #=> (n % 2).zero? 2.060000 0.020000 2.080000 ( 2.244595) > #=> n[0].zero? 1.960000 0.010000 1.970000 ( 2.145238) > #=> (n & 1).zero? 1.990000 0.020000 2.010000 ( 2.275232) > #=> ---------------------------------------- total: 6.060000sec > #=> > #=> user system total real > #=> (n % 2).zero? 2.070000 0.010000 2.080000 ( 2.315105) > #=> n[0].zero? 1.960000 0.020000 1.980000 ( 2.143038) > #=> (n & 1).zero? 1.990000 0.010000 2.000000 ( 2.173120) > > There is a very, very, very small difference in speed. Which is why I suggested actually doing the benchmarks after explaining why mod would be expected to be slower. Now I took this benchmark and simplified it, taking out the zero? call in an attempt to isolate the cost of each approach. I also added a benchmark of an empty loop. On my machine this seems to make the hot run of mod FASTER than bit testing on 1.8, but not on 1.9: rick@frodo:/public/rubyscripts$ ruby bitbm.rb Rehearsal ---------------------------------------------- empty loop 1.840000 0.410000 2.250000 ( 3.366799) n % 2 3.680000 0.910000 4.590000 ( 5.636832) n[0] 3.650000 1.020000 4.670000 ( 9.325569) (n & 1) 3.890000 0.840000 4.730000 ( 6.346543) ------------------------------------ total: 16.240000sec user system total real empty loop 1.790000 0.480000 2.270000 ( 3.695585) n % 2 3.700000 0.880000 4.580000 ( 8.864955) n[0] 3.740000 0.910000 4.650000 ( 13.832782) (n & 1) 3.850000 0.870000 4.720000 ( 12.540741) rick@frodo:/public/rubyscripts$ ruby1.9 bitbm.rb Rehearsal ---------------------------------------------- empty loop 1.280000 0.010000 1.290000 ( 1.964290) n % 2 2.900000 0.010000 2.910000 ( 6.053066) n[0] 2.370000 0.000000 2.370000 ( 3.572928) (n & 1) 2.660000 0.010000 2.670000 ( 4.322753) ------------------------------------- total: 9.240000sec user system total real empty loop 1.230000 0.000000 1.230000 ( 2.415479) n % 2 2.750000 0.010000 2.760000 ( 4.028753) n[0] 2.390000 0.000000 2.390000 ( 3.322041) (n & 1) 2.400000 0.010000 2.410000 ( 3.548835) And n[0] seems faster than n & 1 which is a slight surprise, to me at least. By the way, is the actual meaning of user, system, total, and real documented anywhere. I've looked around a few times, and haven't uncovered it. I guess I could try to devine it by reading the code for benchmark, but... Here's my version of Phrogz benchmark code FWIW; require 'benchmark' ITERATIONS = 1_000_000 MAX_INT = 2 ** 30 NUMS = (1..ITERATIONS).map{ rand(MAX_INT) } Benchmark.bmbm{ |x| x.report 'empty loop' do NUMS.each {|n|} end x.report 'n % 2' do NUMS.each{ |n| n % 2 } end x.report 'n[0]' do NUMS.each{ |n| n[0] } end x.report '(n & 1)' do NUMS.each{ |n| (n & 1) } end } -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/