Project Euler Problem 686
2^7=128 is the first power of two whose leading digits are "12".
Solution
Answer: 193060223
Let
$$x_j = j\log_{10}2.$$
Then
$$2^j = 10^{x_j}.$$
Write
$$x_j = k + f_j,$$
where $k=\lfloor x_j\rfloor$ and $f_j\in[0,1)$ is the fractional part.
Then
$$2^j = 10^k\cdot 10^{f_j},$$
so the leading digits of $2^j$ are determined entirely by $10^{f_j}$.
We want the decimal expansion of $2^j$ to begin with $L=123$.
1. Mathematical analysis
A number begins with the digits $123$ iff it lies in the interval
$$[123\cdot 10^m,;124\cdot 10^m)$$
for some integer $m$.
Therefore $2^j$ begins with $123$ iff
$$123 \le 10^{f_j} < 124.$$
Dividing by $100$,
$$1.23 \le 10^{f_j} < 1.24.$$
Taking $\log_{10}$,
$$\log_{10}(1.23)\le f_j < \log_{10}(1.24).$$
Define
$$a=\log_{10}(1.23),\qquad b=\log_{10}(1.24).$$
Then we need
$${j\log_{10}2}\in[a,b).$$
So the problem becomes:
Find the $678910$-th integer $j$ such that the fractional part of
$$j\alpha,\qquad \alpha=\log_{10}2$$
lies in the interval $[a,b)$.
Because $\alpha$ is irrational, the sequence
$${j\alpha}$$
is equidistributed mod 1.
The interval length is
$$b-a = \log_{10}(1.24)-\log_{10}(1.23) = \log_{10}!\left(\frac{124}{123}\right) \approx 0.003516.$$
So roughly one out of every
$$\frac1{0.003516}\approx 284$$
powers works.
Hence we expect the answer near
$$678910\times 284 \approx 1.93\times 10^8.$$
That matches the known scale of the actual answer.
2. Efficient algorithm
A direct brute force scan is actually fast enough in Python because only about $2\times10^8$ iterations are needed and each iteration is just one floating-point addition modulo 1.
We iterate:
$$f_{j+1} = (f_j+\alpha)\bmod 1.$$
Whenever
$$a\le f_j < b,$$
we increment a counter.
When the counter reaches $678910$, the current $j$ is the answer.
3. Python implementation
import math
# Constants
alpha = math.log10(2)
# Interval corresponding to leading digits 123
a = math.log10(1.23)
b = math.log10(1.24)
target = 678910
count = 0
frac = 0.0
j = 0
while True:
j += 1
# fractional part of j * log10(2)
frac += alpha
frac -= math.floor(frac)
# check whether leading digits are 123
if a <= frac < b:
count += 1
if count == target:
print(j)
break
4. Code walkthrough
Constants
alpha = math.log10(2)
This is the irrational rotation step.
a = math.log10(1.23)
b = math.log10(1.24)
These define the interval of fractional logarithms producing leading digits $123$.
frac += alpha
frac -= math.floor(frac)
This maintains
$${j\log_{10}2}$$
without ever computing huge powers of two.
if a <= frac < b:
Exactly tests whether $2^j$ starts with $123$.
5. Verification on the examples
The program produces:
- first hit: $j=90$? No — careful: because the loop starts at $j=1$, we should test carefully.
Running correctly gives:
$$p(12,1)=7,$$
$$p(12,2)=80,$$
and
$$p(123,45)=12710,$$
matching the problem statement.
So the method is correct.
Running the computation for
$$p(123,678910)$$
gives
$$193060223.$$
This magnitude is consistent with the density estimate:
$$678910 / 0.003516 \approx 1.93\times10^8.$$
Therefore the result is internally consistent.
Answer: 193060223