Problem (legend of the inventor of chess). One grain of wheat on the first square, two on the second, four on the third, doubling each square. How much wheat is on the board?
Answer. grains, exactly ULLONG_MAX. At about 50 mg per grain that is roughly tonnes, over a thousand years of today’s world wheat harvest (about tonnes a year).
| Doubling fact | Value |
|---|---|
| square | grains |
| first squares | (always one less than the next square) |
| second half of the board vs the first | times as much |
| so , quick estimate (true ) | |
| lily pad doubling daily, lake full on day 48 | half full on day 47 |
| fold a 0.1 mm sheet 42 times | km, beyond the Moon |
| doubling time at growth rate | periods (rule of 70) |
Overflow in practice
The board is the natural boundary of 64-bit integers, which is why the puzzle doubles as a checklist of integer pitfalls.
| Expression | Problem | Fix |
|---|---|---|
1 << 40 | int shift, overflow | 1LL << 40 |
1ULL << 64 | shift by the full width is undefined | special-case , or ~0ULL |
1LL << 63 | sign bit; before C++20 undefined | use ull, or LLONG_MIN |
(ll)pow(10, 18) | double result may be after truncation | integer loop, or llround |
a * b with | overflows ll | __int128, or __builtin_mul_overflow |
sum += x over values up to | overflows at | check the bound first, or saturate |
a * b % m with | product overflows before % | (i128)a * b % m |
ull grainsUpTo(int k) { return k >= 64 ? ~0ULL : (1ULL << k) - 1; } // squares 1..k, k in [0, 64]
ll powSat(ll b, int e, ll cap) { // min(b^e, cap) for b >= 1, without overflow
ll r = 1;
while (e--) { if (r > cap / b) return cap; r *= b; }
return r;
}
ll mulSat(ll a, ll b) { // a * b clamped to [LLONG_MIN, LLONG_MAX]
ll r;
if (!__builtin_mul_overflow(a, b, &r)) return r;
return ((a < 0) ^ (b < 0)) ? LLONG_MIN : LLONG_MAX;
}Proof: the geometric sum and the saturating helpers
Sum. Let . Then (every other term cancels), so ; for this is the largest
unsigned long long. In particular square holds : one grain more than all previous squares together. The second half holds against in the first, a ratio of .powSat. Invariant: cap after steps. Before multiplying, iff (for integers ), so the check detects exactly the steps where the product would exceed cap, without computing it. mulSat relies on
__builtin_mul_overflow, which computes the exact product and reports whether it fits; on overflow the sign of the true product is the xor of the signs. Doubling time: , and for small , with . Checked against__int128for all and random bases and exponents.
Related notes
- C++ for Competitive Programming (integer types)
- Debugging and Stress Testing (overflow bugs)
- Tower of Hanoi (also moves for 64 discs)