E (mathematical constant)
$e \approx 2.71828$ appears in several guises: the limit of $(1 + 1/n)^n$, the sum $\sum 1/k!$, the base whose exponential is its own derivative, and a number with a strikingly regular continued fraction. In Project Euler each guise shows up as a different kind of problem: an exact rational sequence (65), a calculus optimum (183), and a numerically delicate function (461). This page is about recognising which $e$ you are dealing with, because each one calls for a different tool.
The idea — four faces of one constant
| face | statement | what it gives a solution |
|---|---|---|
| continued fraction | $e = [2; 1, 2, 1, 1, 4, 1, 1, 6, \dots]$ | exact rational convergents by recurrence |
| calculus | $\frac{d}{dx}(x \ln(N/x)) = 0$ at $x = N/e$ | where products like $(N/k)^k$ peak |
| series | $e = \sum_{k \ge 0} 1/k!$, and $e^x = \sum x^k/k!$ | closed forms for factorial-weighted sums |
| exponential | $e^x - 1 \approx x$ for small $x$ | the need for expm1 to avoid cancellation |
The continued fraction is exceptional. Most irrationals have no pattern in their partial quotients, but $e$'s are $a_0 = 2$ and then the repeating triple $1, 2k, 1$ for $k = 1, 2, \dots$ (Euler, 1737). Its convergents therefore come from the usual recurrence $h_k = a_k h_{k-1} + h_{k-2}$ with an explicit $a_k$. The calculus face appears whenever a quantity is split into equal parts and then multiplied, because the maximiser of $(N/x)^x$ is $x = N/e$. The series face is behind any "expected number of uniform draws" or "sum of $1/i!$" problem. The probability that $n$ uniforms sum to less than 1 is $1/n!$, so the expected count of draws until their sum exceeds 1 is $\sum_{n \ge 0} 1/n! = e$.
Three faces across the problems
65, convergents of $e$: the continued fraction. The task is the numerator of the 100th convergent, then its digit
sum. The partial quotients are generated by rule rather than computed from $e$, so no floating point
is involved. The public Python encodes the rule (n is 1-indexed, so n == 1 is the leading 2):
def e_denominator(n: int) -> int:
if n == 1:
return 2
elif n % 3 == 0:
return 2 * n // 3
else:
return 1
The numerator grows roughly like $e^{n}$, so it needs arbitrary precision. See continued fraction for the convergent recurrence.
183, maximum product of parts: the calculus optimum. Splitting $N$ into $k$ equal parts
maximises $(N/k)^k$ at $k = N/e$. The integer optimum is $\lfloor N/e \rfloor$ or $\lceil N/e \rceil$, and the
solution compares the two in log space. The analysis is on concave function.
Here $e$ is a real constant (math.e, M_E), and the only care needed is that comparing
$k(\ln N - \ln k)$ in doubles picks the correct neighbour.
461, almost $\pi$: the exponential near zero. Four terms $f_n(k) = e^{k/n} - 1$ must sum as close to
$\pi$ as possible, with $n = 10^4$. A meet-in-the-middle
over sorted pair sums does the search. The $e$-specific point is numerical. For $k = 1$,
$e^{0.0001} - 1$ computed as exp(x) - 1 subtracts two numbers near 1 and loses about four of
its sixteen significant digits. The answer depends on matching $\pi$ to many digits, so the solution uses
expm1, which computes $e^x - 1$ directly without the cancellation.
The unsolved problems on the list use the series face. 330 defines $a(n)$ by factorial-weighted sums whose values have the form $(A e + B)/n!$. 969 and 970 start from $H(1) = e$, the expected number of uniform hops needed to pass 1.
Python and C
- 65: the two versions differ most here. Python evaluates the convergent top-down, recursing to depth $n$ and
unwinding $a + 1/\text{rest}$ with exact
Fractions. It raisessys.setrecursionlimit, and it carries numerators and denominators it never needs. C runs the numerator recurrence bottom-up over three rotating buffers of a hand-rolled base-$10^9$BigInt. The decimal base makes the digit sum a direct read of each limb, and sincelimb * a_k + limb + carrystays below $2^{64}$, no wider type is needed. - 183:
math.eandmath.logagainstM_Eandlog. These are the same doubles, so the two languages pick the same neighbour of $N/e$. - 461:
np.expm1over anarangeagainst a scalarexpm1loop. Both use the same libm routine, so the values match bit for bit. Python sorts the pair sums withnp.argsortand finds the best complement with chunkedsearchsorted. C sorts an array ofPairstructs with a hand-written introsort to avoidqsort's function-pointer calls over tens of millions of elements, then makes one two-pointer sweep.
How to reason about it
- Identify the face before choosing the tool. The continued fraction needs exact big-integer
recurrences, the calculus optimum needs a check of the two neighbouring integers, the series needs
factorial sums, and the exponential near zero needs
expm1. - Do not compute $e$ when its structure is known. 65 uses the partial-quotient rule and never needs $e$'s digits.
- Expect $N/e$ when equal parts are multiplied. $(N/k)^k$, and products of equal shares in general, peak there.
- Use
expm1andlog1pnear zero. $e^x - 1$ and $\ln(1 + x)$ for small $x$ lose digits when written naively. - For convergents, iterate rather than recurse. The bottom-up numerator recurrence needs no denominators and no recursion limit.