Powers of Two
Find p(123,678910), the 678910 -th smallest exponent j such that the decimal expansion of 2^j begins with the digits 123.
Problem Statement
This archive keeps the full statement, math, and original media on the page.
\(2^7=128\) is the first power of two whose leading digits are "12".
The next power of two whose leading digits are "12" is \(2^{80}\).
Define \(p(L, n)\) to be the \(n\)th-smallest value of \(j\) such that the base 10 representation of \(2^j\) begins with the digits of \(L\).
So \(p(12, 1) = 7\) and \(p(12, 2) = 80\).
You are also given that \(p(123, 45) = 12710\).
Find \(p(123, 678910)\).
Problem 686: Powers of Two
Mathematical Foundation
Let .
Lemma 1. The number begins with the digits 123 if and only if
where denotes the fractional part of .
Proof. The leading digits of are 123 exactly when there exists an integer such that
Taking base- logarithms gives
Subtracting throughout yields
Conversely, that fractional-part condition implies the existence of such an , hence the same leading digits.
Theorem. Scanning the exponents and counting those satisfying the interval test from Lemma 1 yields .
Proof. By Lemma 1, the interval test is equivalent to the defining property. Therefore the -th hit in this scan is exactly the desired exponent.
Editorial
This is exactly what the existing Python and C++ implementations do. We precompute. We then iterate over . Finally, stop at the -th hit.
Pseudocode
Precompute
$\alpha = \log_{10} 2$,
$L = \log_{10}(1.23)$,
$U = \log_{10}(1.24)$
For $j=1,2,3,\dots$:
compute $\{j\alpha\}$,
if $L \le \{j\alpha\} < U$, increment the hit counter
Stop at the $678910$-th hit
Complexity Analysis
- Time: , with constant work per exponent.
- Space: .
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
/*
* Project Euler Problem 686: Powers of Two
*
* Find p(123, 678910): the 678910th smallest j such that 2^j starts with "123".
*
* Key insight: 2^j starts with digits L if and only if
* log10(L) <= frac(j * log10(2)) < log10(L+1)
* where frac(x) is the fractional part of x.
*
* We iterate j from 0, check the fractional part condition, and count.
*/
int main() {
const int target = 678910;
const double log10_2 = log10(2.0);
const double lo = log10(1.23); // log10(123) - 2 = log10(1.23)
const double hi = log10(1.24); // log10(124) - 2 = log10(1.24)
int count = 0;
long long j = 0;
while (count < target) {
j++;
double frac = j * log10_2;
frac -= floor(frac);
if (frac >= lo && frac < hi) {
count++;
}
}
cout << j << endl;
return 0;
}
"""
Project Euler Problem 686: Powers of Two
Find p(123, 678910): the 678910th smallest j such that 2^j starts with "123".
Key insight: 2^j starts with digits L iff
log10(L) <= frac(j * log10(2)) < log10(L+1)
where frac(x) is the fractional part of x.
We use the three known gaps between consecutive solutions to speed up the search.
The gaps between consecutive j values where 2^j starts with "123" cycle through
approximately three values: 196, 289, 485.
"""
import math
def solve():
log10_2 = math.log10(2)
lo = math.log10(1.23)
hi = math.log10(1.24)
target = 678910
count = 0
j = 0
while count < target:
j += 1
frac = (j * log10_2) % 1.0
if lo <= frac < hi:
count += 1
print(j)
if __name__ == "__main__":
solve()