Project Euler Problem 686

2^7=128 is the first power of two whose leading digits are "12".

Project Euler Problem 686

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