Problem 16: Power Digit Sum
View on Project EulerProject Euler Problem 16 Solution
EulerSolve provides an optimized solution for Project Euler Problem 16, Power Digit Sum, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary The problem asks for the sum of the decimal digits of \(2^{1000}\). The smaller example \(2^{15}=32768\) has digit sum \(3+2+7+6+8=26\), so the actual task is the same operation on a much larger power of two. The main issue is size, not number theory. Since $\#\text{digits}(2^{1000})=\left\lfloor 1000\log_{10}2\right\rfloor+1=302,$ the number does not fit in an ordinary fixed-width integer, so the computation must treat the decimal expansion as a multi-digit object. Mathematical Approach Write the decimal expansion of \(2^n\) as $2^n=\sum_{i=0}^{k-1} d_i 10^i,\qquad 0\le d_i\le 9,$ so the desired quantity is simply $S(2^n)=\sum_{i=0}^{k-1} d_i.$ The subtle part is that the digit sum cannot be updated from the previous digit sum alone, because carries depend on the entire decimal state. That is why the natural mathematical object is the full vector of decimal digits. The Right State Is the Decimal Expansion Suppose after \(t\) doublings we know the digits of \(2^t\): $2^t=\sum_{i=0}^{m_t-1} a_i^{(t)}10^i.$ Knowing only \(S(2^t)\) is not enough to determine \(S(2^{t+1})\). For example, the numbers 19 and 28 both have digit sum 10, but doubling gives 38 and 56, whose digit sums are 11 and 11 after different carry patterns. In general the carry behavior depends on every digit, so the state must keep the whole decimal representation....
Detailed mathematical approach
Problem Summary
The problem asks for the sum of the decimal digits of \(2^{1000}\). The smaller example \(2^{15}=32768\) has digit sum \(3+2+7+6+8=26\), so the actual task is the same operation on a much larger power of two.
The main issue is size, not number theory. Since
$\#\text{digits}(2^{1000})=\left\lfloor 1000\log_{10}2\right\rfloor+1=302,$
the number does not fit in an ordinary fixed-width integer, so the computation must treat the decimal expansion as a multi-digit object.
Mathematical Approach
Write the decimal expansion of \(2^n\) as
$2^n=\sum_{i=0}^{k-1} d_i 10^i,\qquad 0\le d_i\le 9,$
so the desired quantity is simply
$S(2^n)=\sum_{i=0}^{k-1} d_i.$
The subtle part is that the digit sum cannot be updated from the previous digit sum alone, because carries depend on the entire decimal state. That is why the natural mathematical object is the full vector of decimal digits.
The Right State Is the Decimal Expansion
Suppose after \(t\) doublings we know the digits of \(2^t\):
$2^t=\sum_{i=0}^{m_t-1} a_i^{(t)}10^i.$
Knowing only \(S(2^t)\) is not enough to determine \(S(2^{t+1})\). For example, the numbers 19 and 28 both have digit sum 10, but doubling gives 38 and 56, whose digit sums are 11 and 11 after different carry patterns. In general the carry behavior depends on every digit, so the state must keep the whole decimal representation.
Repeated Doubling Gives an Exact Recurrence
To pass from \(2^t\) to \(2^{t+1}\), process the digits from least significant to most significant with a carry. Set \(c_0=0\), and for each position \(i\) define
$u_i=2a_i^{(t)}+c_i,\qquad a_i^{(t+1)}=u_i\bmod 10,\qquad c_{i+1}=\left\lfloor\frac{u_i}{10}\right\rfloor.$
Because \(0\le a_i^{(t)}\le 9\) and \(c_i\in\{0,1\}\), we always have \(0\le u_i\le 19\), so every new carry is again either 0 or 1. If the final carry is 1, it becomes a new most significant digit. Starting from \(2^0=1\), repeating this update \(n\) times constructs the exact decimal digits of \(2^n\).
The Carry Invariant
The correctness of the schoolbook update rests on a simple invariant. After the first \(r\) digits have been processed in one doubling step, the digits already written are exactly the last \(r\) decimal digits of \(2^{t+1}\), and the carry holds the amount that must be transferred into the remaining higher-order part. In other words, the algorithm never loses information: it only postpones part of the doubled value into the carry that will be added to the next digit.
This is the same positional-value principle used in hand arithmetic. The recurrence above is therefore not an approximation; it is a digit-by-digit proof that the decimal array after \(n\) rounds is the true expansion of \(2^n\).
Digit Growth and Why the Direct Method Is Fast Enough
The number of decimal digits of \(2^n\) is determined by
$10^{k-1}\le 2^n<10^k,$
which gives
$k=\left\lfloor n\log_{10}2\right\rfloor+1.$
So the decimal length grows linearly with \(n\). The \(t\)-th doubling touches \(k(t)=\Theta(t)\) digits, and the total amount of single-digit work is therefore
$\sum_{t=1}^n \Theta(k(t))=\Theta\!\left(\sum_{t=1}^n t\right)=\Theta(n^2).$
For \(n=1000\), that quadratic bound is still tiny, because the final number has only 302 digits.
Worked Example: Reaching \(2^{15}\)
A concrete example shows the recurrence in action. Start from
$2^{11}=2048.$
Double digit by digit. From right to left in ordinary notation, or equivalently from least significant to most significant in the digit array:
$8\mapsto 16\Rightarrow 6\text{ with carry }1,$
$4\mapsto 2\cdot 4+1=9\Rightarrow 9\text{ with carry }0,$
$0\mapsto 0,\qquad 2\mapsto 4,$
so \(2^{12}=4096\). Repeating gives
$2^{13}=8192,\qquad 2^{14}=16384,\qquad 2^{15}=32768.$
Hence
$S(2^{15})=3+2+7+6+8=26.$
A Useful Modulo 9 Check
Because \(10\equiv 1\pmod 9\), every decimal number is congruent modulo 9 to the sum of its digits. Therefore
$S(2^n)\equiv 2^n\pmod 9.$
This does not determine the answer by itself, but it is an excellent sanity check. For the worked example, \(26\equiv 8\pmod 9\) and \(2^{15}\equiv 8\pmod 9\), so the result is consistent.
How the Code Works
The C++, Python, and Java implementations all compute the exact power and then sum its decimal digits, but they choose different representations for the intermediate number.
C++ Implementation
The C++ implementation mirrors the mathematics directly. It stores the decimal digits in little-endian order, starts from the single digit 1, and performs one doubling step for each increase of the exponent. Every pass applies the carry recurrence above, and any leftover carry is appended as a new most significant digit. Once all doublings are complete, a final linear scan adds the digits.
This version makes the invariant explicit: at every moment the digit array is an exact decimal representation of the current power of two.
Python Implementation
The Python implementation uses the language's native arbitrary-precision integers. It forms the exact integer \(2^n\), converts it to decimal text, and sums the characters as digits. The code is very short because the runtime handles the internal big-integer arithmetic automatically, but mathematically it is still computing the same decimal expansion and then evaluating the same digit-sum formula.
Java Implementation
The Java implementation uses the standard arbitrary-precision integer type provided by the language library. It raises 2 to the required exponent exactly, turns the result into a decimal string, and accumulates the digits. Like the Python version, it delegates the low-level multi-precision arithmetic to a library, but the mathematical object is still the exact integer \(2^n\), not a floating-point approximation.
The implementations also include simple checkpoints based on the problem statement, such as confirming that the exponent 15 produces the digit sum 26. The C++ implementation additionally checks the base case \(2^0=1\).
Complexity Analysis
For the manual decimal-doubling method, the final digit count is \(k(n)=\Theta(n)\), and the \(t\)-th doubling touches \(k(t)=\Theta(t)\) digits. That leads to
$O\!\left(\sum_{t=1}^n k(t)\right)=O(n^2)$
time and \(O(k(n))=O(n)\) memory.
For the specific target \(n=1000\), this is easily fast enough: only a few hundred thousand single-digit updates are needed. The Python and Java implementations rely on optimized arbitrary-precision libraries, but at this scale they are also effectively instantaneous for the same reason: the exact value has only 302 decimal digits.
Footnotes and References
- Problem page: https://projecteuler.net/problem=16
- Powers of two: Wikipedia - Power of two
- Positional notation: Wikipedia - Positional notation
- Arbitrary-precision arithmetic: Wikipedia - Arbitrary-precision arithmetic
- Digital root and modulo 9 checks: Wikipedia - Digital root