Mendelian inheritance
Profiling and Benchmarking
Rather than benchmarking, which just does total time, you would be better off profiling, which is like recursive benchmarking.  I recommend you use the ruby-prof gem.
I profiled your code thusly:
require 'ruby-prof'

n = 500000
puts &quot;========================DOM 1=============================&quot;
RubyProf.start
(1..n).each { |n| probability_dominant_1(n, n, n) } 
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)

puts &quot;========================DOM 2=============================&quot;
RubyProf.start
(1..n).each { |n| probability_dominant_2(n, n, n) } 
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)

puts &quot;========================DOM 3=============================&quot;
RubyProf.start
(1..n).each { |n| probability_dominant_3(n, n, n) } 
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)

And got the following results:
========================DOM 1=============================
Measure Mode: wall_time
Thread ID: 1975060
Fiber ID: 22475080
Total: 4.755476
Sort by: self_time

 %self      total      self      wait     child     calls  name
 55.06      4.501     2.618     0.000     1.883   500000   Object#probability_dominant_1
 11.69      0.556     0.556     0.000     0.000  1434466   Fixnum#*
 10.14      0.482     0.482     0.000     0.000  1433660   Bignum#+
  7.95      0.378     0.378     0.000     0.000  1500000   Float#*
  6.60      0.314     0.314     0.000     0.000   934466   Bignum#-
  5.34      4.755     0.254     0.000     4.501        1   Range#each
  3.13      0.149     0.149     0.000     0.000   500000   Float#/
  0.08      0.004     0.004     0.000     0.000    24252   Fixnum#+
  0.00      4.755     0.000     0.000     4.755        1   Global#[No method]

* indicates recursively called methods
========================DOM 2=============================
Measure Mode: wall_time
Thread ID: 1975060
Fiber ID: 22475080
Total: 2.474247
Sort by: self_time

 %self      total      self      wait     child     calls  name
 60.31      2.258     1.492     0.000     0.766   500000   Object#probability_dominant_2
 10.67      0.264     0.264     0.000     0.000   952579   Bignum#+
  8.73      2.474     0.216     0.000     2.258        1   Range#each
  5.38      0.133     0.133     0.000     0.000   500000   Fixnum#*
  5.17      0.128     0.128     0.000     0.000   500000   Float#/
  4.73      0.117     0.117     0.000     0.000   500000   Float#+
  4.73      0.117     0.117     0.000     0.000   500000   Float#*
  0.28      0.007     0.007     0.000     0.000    31037   Fixnum#+
  0.00      2.474     0.000     0.000     2.474        1   Global#[No method]

* indicates recursively called methods
========================DOM 3=============================
Measure Mode: wall_time
Thread ID: 1975060
Fiber ID: 22475080
Total: 4.334434
Sort by: self_time

 %self      total      self      wait     child     calls  name
 50.85      4.074     2.204     0.000     1.870   500000   Object#probability_dominant_3
 17.44      0.756     0.756     0.000     0.000  2364956   Bignum#+
 16.66      0.722     0.722     0.000     0.000  3000000   Float#*
  6.00      4.334     0.260     0.000     4.074        1   Range#each
  5.42      0.235     0.235     0.000     0.000  1000000   Float#/
  3.39      0.147     0.147     0.000     0.000   476830   Bignum#-
  0.23      0.010     0.010     0.000     0.000    46340   Fixnum#+
  0.00      4.334     0.000     0.000     4.334        1   Global#[No method]

* indicates recursively called methods

Foreach function, these tables show the number of calls and time spent on function call, recursively all the way down.  Some portions, like the &quot;range#each&quot; can be ignored as part of of our testing overhead.
Looking at the results, I can spot why dominant_2 is the fastest.  Integer operations (FixNum) on a processor will always be faster.  Floating point (Float) is slow and floating point divisiondividing is slow, and big integers (integer numbers bigger than that hardware can natively support, typically 2^32 or 2^64) will also be slower.

Dom1 has 2M Float, ~2.4M BigNum, and ~1.4M FixNum operations.
Dom2 has 1.5M Float, ~1M BigNum, and ~530K FixNum operations.
Dom3 has 4M Float, ~2.3M BigNum, and ~46K FixNum operations.

Dom2 was the fastest because it has the fewest number of operations by far.
As a weak rule of thumb, when optimizing math, try to avoid BigNum and Float when feasible.  Also try to avoid things like converting numbers to strings and then back to numbers.
Conclusion
Know that more often though, that your slowdown will usually come from lots of branching and flow control, and being inefficient (like calculating the same things over and over rather than caching them), and those are the places to optimize.  If this problem were part of a larger, more complicated task, I can practically guarantee that your bottleneck would not be ANY of these functions, but something else entirely.