Teaser 3307: A dish best served cold
From The Sunday Times, 8th February 2026 [link] [link]
King Otto’s birthday cake was a giant mousse. Its tiers were two concentric regular octagons. The upper tier’s span equalled the lower tier’s side-length (the diagrams show top and side views). Each tier’s height equalled the base tier octagon’s side-length (a two-figure whole number of inches under 20) divided by the square root of two (chef used a 45 degree right triangle gauge for this). When all tables at the party (arranged in three equal lines) were fully occupied (each set for the same number of couples) each person got an identical portion of eight cubic inches of cake (not necessarily in the shape of a cube). The small amount left over was less than this.
How many tables were there?
[teaser3307]










Jim Randell 7:57 am on 8 February 2026 Permalink |
(See also: Teaser 2976, Teaser 2921).
This Python program considers possible side lengths of the octagonal lower tier, calculates the total volume of both tiers, and then divides it into 8 cu in portions.
The number of portions is then allocated to three equal rows of tables, with the same number of guests at each table. (I allowed between 2 and 20 couples at each table, which gives a single answer).
It runs in 70ms. (Internal runtime is 87µs).
from enigma import (irange, sqrt, fdiv, intr, div, divisors_pairs, printf) r2 = sqrt(2) # area of an octagon with side x area = lambda x: 2 * x * x * (1 + r2) # consider possible side lengths of the larger octagon = x (2-digit numbers less than 20) for x in irange(10, 19): # calculate the height of the tiers = h h = fdiv(x, r2) # volume of the lower tier V1 = area(x) * h # volume of the upper tier z = fdiv(x, 1 + r2) V2 = area(z) * h # total volume of the cake (to the nearest cu in) V = intr(V1 + V2) # divide into portions = k; remainder = r (k, r) = divmod(V, 8) # there is a small amount remaining if r == 0: continue # there are 3 rows of tables, and some couples on each table p = div(k, 6) if p is None: continue # each seating the same number of couples = a, with tables per row = b for (a, b) in divisors_pairs(p, every=1): if not (a > 1): continue # more than 1 couple per table if a > 20: break # but no more than 20 # output scenario printf("x={x} h={h:.2f} -> V={V} k={k} r={r}") printf("-> 3 rows of: {p} portions = {a} couples on {b} tables", p=2*p) printf("--> total tables = {T}", T=3*b) printf()Solution: There were 183 tables.
The tables are arranged in 3 rows, each with 61 tables, and each table seats 3 couples (= 6 guests), for a total of 1098 guests, which requires 8784 cu in of cake.
The lower tier of the cake has side length of 13 in, which makes the total volume of the cake 8788 cu in (leaving 4 cu in left over).
Without restrictions on the number of guests at each table we could seat 1098 guests using:
I decided to keep the tables a manageable size with 3 couples (= 6 guests) at each table.
But perhaps it would have been better if the total number of guests had been asked for (or the allowable number of guests per table specified).
If you determine the total volume of cake in terms of x (or let Wolfram Alpha determine it for you [ link ]), you will find:
Which can be used instead of lines 10-18 to directly to calculate the volume of the cake (without using floating point approximations).
And can also be used in a manual solution, as follows:
We see that for even x the volume will be an exact multiple of 8, and there will be no unused portion, so we can consider odd values for x, and calculate V (which will have leave a remainder of 4 cu in). The number of portions p must then be divisible by 6 (for each couple in each of the 3 rows).
Only x = 13, gives a viable number of portions. And we can further split 183 to give the four candidate scenarios given above:
Of these the first seems unlikely (1 couple per table), and we can reduce the remaining three to a single candidate by placing an upper limit (of 120 or fewer) on the number of guests per table.
Giving a solution of 3 rows, each with 61 tables, so 183 tables tables in total.
LikeLike
Jim Randell 10:55 am on 17 February 2026 Permalink |
If you don’t want to do the analysis yourself (or let Wolfram Alpha do it), and you don’t want to wheel out the big guns (like
SymPy), then the following class allows you to do simple arithmetic operations involving an irrational number.from enigma import enigma Q = enigma.Rational() # manipulate numbers of the form: a + b*sqrt(n) where n is an integer, and a and b are rational class Surd(object): def __init__(self, n, a=0, b=1): self.n = n self.a = a self.b = b def __repr__(self): return str.format("Surd[{a} + {b}*sqrt({n})]", a=self.a, b=self.b, n=self.n) # evaluate to a standard numeric type (you might get a float, or a complex, or a Q object) def val(self): (n, a, b) = (self.n, self.a, self.b) return (a if b == 0 else a + b * n**0.5) # extract (n, a, b, c, d) parameters def _params(self, other): if not isinstance(other, Surd): other = Surd(self.n, other, 0) if not (self.n == other.n): raise ValueError("Surd: incompatible values") return (self.n, self.a, self.b, other.a, other.b) # calculate self + other def __add__(self, other): (n, a, b, c, d) = self._params(other) return Surd(n, a + c, b + d) __radd__ = __add__ def __neg__(self): return Surd(self.n, -self.a, -self.b) def __sub__(self, other): (n, a, b, c, d) = self._params(other) return Surd(n, a - c, b - d) __rsub__ = lambda self, other: -self + other # calculate self * other def __mul__(self, other): (n, a, b, c, d) = self._params(other) return Surd(n, a * c + b * d * n, a * d + b * c) __rmul__ = __mul__ # calculate self / other def __truediv__(self, other): (n, a, b, c, d) = self._params(other) D = c * c - d * d * n return Surd(n, Q(a * c - b * d * n, D), Q(b * c - a * d, D)) def __rtruediv__(self, other): if not isinstance(other, Surd): other = Surd(self.n, other, 0) return other.__truediv__(self) # Python 2 support __div__ = __truediv__ __rdiv__ = __rtruediv__My program can then be modified to use this class, and we find that the irrational falls out of the expression and always leaves us with an exact integer volume for the cake.
from enigma import (irange, as_int, div, divisors_pairs, printf) # representation of sqrt(2) r2 = Surd(2) # area of an octagon with side x area = lambda x: 2 * x * x * (1 + r2) # consider possible side lengths of the larger octagon = x (2-digit numbers less than 20) for x in irange(10, 19): # calculate the height of the tiers = h h = x / r2 # volume of the lower tier V1 = area(x) * h # volume of the upper tier z = x / (1 + r2) V2 = area(z) * h # total volume of the cake V = V1 + V2 # retrieve the actual numeric value V = as_int(V.val()) # divide into portions = k; remainder = r (k, r) = divmod(V, 8) # there is a small amount remaining if r == 0: continue # there are 3 rows of tables, and some couples on each table p = div(k, 6) if p is None: continue # each seating the same number of couples = a, with tables per row = b for (a, b) in divisors_pairs(p, every=1): if not (a > 1): continue # more than 1 couple per table if a > 20: break # but no more than 20 # output scenario printf("x={x} h={h:.2f} -> V={V} k={k} r={r}", h=float(h.val())) printf("-> 3 rows of: {p} portions = {a} couples on {b} tables", p=2*p) printf("--> total tables = {T}", T=3*b) printf()LikeLike