Project Euler Problem 40
An irrational decimal fraction is created by concatenating the positive integers: It can be seen that the 12th digit of
Solution
Answer: 210
We construct the irrational decimal
$$0.12345678910111213141516\cdots$$
by concatenating the positive integers in order.
Let $d_n$ denote the $n$-th digit after the decimal point.
We must compute
$$d_1 d_{10} d_{100} d_{1000} d_{10000} d_{100000} d_{1000000}.$$
1. Mathematical analysis
The key idea is to locate which integer contains the $n$-th digit.
We group integers by their number of digits.
Step 1: Count digits contributed by each block
1-digit numbers
Numbers:
$$1,2,\dots,9$$
There are $9$ numbers, each contributing $1$ digit.
Total digits:
$$9 \times 1 = 9$$
2-digit numbers
Numbers:
$$10,11,\dots,99$$
There are
$$90$$
numbers, each contributing $2$ digits.
Total digits:
$$90 \times 2 = 180$$
Cumulative total:
$$9 + 180 = 189$$
3-digit numbers
$$100 \text{ to } 999$$
Count:
$$900$$
Digits contributed:
$$900 \times 3 = 2700$$
Cumulative:
$$2889$$
In general:
- $k$-digit numbers contribute
$$9 \cdot 10^{k-1} \cdot k$$
digits.
Finding $d_n$
To determine $d_n$:
- Determine which digit-length block contains position $n$.
- Determine which exact number inside that block.
- Determine which digit of that number.
Example: $d_{12}$
The first 9 digits come from $1$-digit numbers.
So position $12$ lies among the $2$-digit numbers.
Relative position inside the 2-digit block:
$$12 - 9 = 3$$
Each number contributes 2 digits.
$$(3-1)//2 = 1$$
So we are at the second 2-digit number after 10:
$$11$$
The digit index:
$$(3-1)\bmod 2 = 0$$
which is the first digit of $11$, namely:
$$1$$
So $d_{12}=1$, matching the statement.
Compute the required digits
We now determine:
$$d_1,d_{10},d_{100},d_{1000},d_{10000},d_{100000},d_{1000000}$$
The resulting digits are:
$$1,\ 1,\ 5,\ 3,\ 7,\ 2,\ 1$$
Thus the product is
$$1 \times 1 \times 5 \times 3 \times 7 \times 2 \times 1$$
$$= 210$$
2. Python implementation
def champernowne_digit(n):
"""
Return the nth digit of Champernowne's constant:
0.123456789101112...
"""
digit_length = 1
count = 9
start = 1
# Find which block contains the nth digit
while n > digit_length * count:
n -= digit_length * count
digit_length += 1
count *= 10
start *= 10
# Find the actual number containing the digit
number = start + (n - 1) // digit_length
# Find the digit inside that number
digit_index = (n - 1) % digit_length
return int(str(number)[digit_index])
# Required positions
positions = [1, 10, 100, 1000, 10000, 100000, 1000000]
product = 1
for p in positions:
product *= champernowne_digit(p)
print(product)
3. Code walkthrough
Function definition
def champernowne_digit(n):
Computes the $n$-th digit.
Initialize block information
digit_length = 1
count = 9
start = 1
These represent:
- current digit size,
- how many numbers in the block,
- first number in the block.
Initially:
- 1-digit numbers,
- 9 such numbers,
- starting at 1.
Locate the correct block
while n > digit_length * count:
If $n$ exceeds the digits in the current block, subtract them and move on.
Example:
- 2-digit block contributes $2 \times 90 = 180$.
Find the exact number
number = start + (n - 1) // digit_length
This computes which number within the block contains the target digit.
Find the digit position
digit_index = (n - 1) % digit_length
Determines which digit inside the number is needed.
Return the digit
return int(str(number)[digit_index])
Convert to string and extract the digit.
Small-example verification
For $n=12$:
- after removing the first 9 digits,
remaining position is $3$ inside the 2-digit block.
- second 2-digit number is $11$,
- first digit is $1$.
Correct.
4. Final verification
The digits found are:
$$d_1=1,\quad d_{10}=1,\quad d_{100}=5,\quad d_{1000}=3,\quad d_{10000}=7,\quad d_{100000}=2,\quad d_{1000000}=1$$
Their product:
$$1 \cdot 1 \cdot 5 \cdot 3 \cdot 7 \cdot 2 \cdot 1 = 210$$
The value is small and reasonable since many extracted digits are small.
Answer: 210