Adding the result of two independent probability distributions coincides with the folding of two distributions. If the distributions are discrete, then this is a discrete convolution.
So, if one stamp is presented as:
probs_1d6 = Array.new(6) { Rational(1,6) }
Then 2d6 can be calculated as follows:
probs_2d6 = [] probs_1d6.each_with_index do |prob_a,i_a| probs_1d6.each_with_index do |prob_b,i_b| probs_2d6[i_a + i_b] = ( probs_2d6[i_a + i_b] || 0 ) + prob_a * prob_b end end probs_2d6
Although this is an n-square for the sides of the cubes, a logical combination can reduce this, making it generally less flexible for more complex settings. The best part about this approach is that you can continue to add more cubes and make other more exotic combinations. For example, to get 4d6, you can drill two results for 2d6. Using smart solutions allows you to solve floating point problems.
I missed one detail, you need to save the initial offset (+1 for a normal six-sided matrix) and add it together to find out what the probabilities are connected with.
I made a more complex version of this logic in gem games_dice in a floating point, and not in Rational, which can handle several other combinations of dice.
Here's a basic rewrite of your method using the above approach in a naive way (just combining the effects of the cube one at a time):
def probability_of_sum(x, n, sides=6) return 0 if x < n single_die_probs = Array.new(sides) { Rational(1,sides) } combined_probs = [1]
Note that the method actually calculates the full probability distribution from 100 to 600, so you only need to call it once and save the array (plus offset +100) once, and you can do other useful things, such as the probability of getting more than a certain number . All with great accuracy due to the use of Rational numbers in Ruby.
Because in your situation you have only one type of cubes, we can avoid using Rational to the end, working only with integers (essentially counting combined values) and divide by the total number of combinations (sides to the power of the number of rolls). This is much faster and returns values ββfor 100 dice per second:
def probability_of_sum(x, n, sides=6) return 0 if x < n combined_probs = [1]