My little engineering students are studying a bit of probability as part of their first year mathematics, and their textbook is full of questions like “If two fair dice are thrown, what is the probability that the sum is at least 5?”. Like almost every probability textbook written since the dawn of time, it will include a table such as this:
or a picture such as this:
illustrating all possible throws of two dice. From either of these the number of ways of obtaining a sum is given by:
sum: 2 3 4 5 6 7 8 9 10 11 12 #: 1 2 3 4 5 6 5 4 3 2 1
From a table such as this it is easy to answer all probability questions from the book. Very few books, however, go into the question about sums from three or more dice. I imagine that there is little further learning of probability to be gained by thus extending the problem, so for multiple “throws” coins are used rather than dice.
However, the mathematics is quite fun. Suppose (6-sided, fair) dice are thrown. In how many ways can the sum be obtained? Let’s call this number . From the table above, you can see that, for example . But what is the value, for example, or , or of ?
Look at the case . We are interested in the number of sums where . Such a sum should immediately suggest a generating function, and for this example the generating function is
Thus . And in general is the coefficient of in . This result is of course also given on Mathworld. And we can calculate these with Sage:
sage: dx = x+x^2+x^3+x^4+x^5+x^6 sage: expand(dx^3).coeff(x,10) 27
There’s nothing to stop us trying larger numbers of dice and larger sums, for example 10 dice and the sum of 34 for the value of :
sage: expand(dx^10).coeff(x^34) 4325310
However, this can be slow. For large values of Sage has to do a lot of computation. When I tried with , my computer ground to a halt as all memory was sucked up by Sage, which crashed a bit later. (For those of you concerned about Sage abuse, I gave it a nice cup of tea after a restart and we’re still good friends.) So we would like a more efficient method of computing for large and .
Note that by the definition of as a coefficient of , and as we are using 6-sided dice, if follows that
If we let for less than or greater than we can produce a simple dice program:
sage: def dice(k): d = 6* for i in range(k-1): t = 5* + d + 5* d = [sum(t[i:i+6]) for i in range(len(t)-5)] return d ....:
sage: dice(2) [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1] sage: dice(3) [1, 3, 6, 10, 15, 21, 25, 27, 27, 25, 21, 15, 10, 6, 3, 1]
Notice that the outcome of dice(k) gives the number of sums for all starting at . So then
sage: def t(k,n): return dice(k)[n-k]
sage: t(2,10) 3 sage: t(3,10) 27 sage: t(100,350) 15237092858379903128111407924086725562812976591205826140530848189030092709496
Big enough for ya?
Thanks to a correspondent (see below) the use of polynomial rings vastly simplifies matters.
For example, without doing any programming:
sage: R.<x> = PolynomialRing(ZZ) sage: dx = R(*6)*x sage: dx x^6 + x^5 + x^4 + x^3 + x^2 + x sage: (dx^3) 27 sage: (dx^100) 15237092858379903128111407924086725562812976591205826140530848189030092709496
All results are given instantaneously. The nice thing about his approach is that it enables us to mix and match dice. Suppose we throw 11 cubical dice, 13 octahedral dice, and 15 dodecahedral dice. In how many ways can we obtain the sum of 200?
In one step:
sage: ((R(*6)*x)^11*(R(*8)*x)^13*(R(*12)*x)^15) 69232087336767815011624465024995662