Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 99: Largest Exponential

View on Project Euler

Project Euler Problem 99 Solution

EulerSolve provides an optimized solution for Project Euler Problem 99, Largest Exponential, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary The input consists of 1000 lines, each containing a pair \((b,e)\) representing the number \(b^e\). The task is not to compute the largest power itself, but to identify which 1-indexed line produces the largest numerical value. The obstacle is size. Even a single value such as \(519432^{525806}\) is astronomically large, so ordinary exponentiation is the wrong mathematical object to work with. The real problem is a comparison problem: among all lines, which pair \((b_i,e_i)\) makes \(b_i^{e_i}\) as large as possible? Mathematical Approach Let the \(i\)-th line contain \((b_i,e_i)\), and write $x_i=b_i^{e_i}.$ We want the line whose \(x_i\) is maximal. The implementations do not build \(x_i\) directly. Instead they replace each gigantic power by a much smaller real-valued score that preserves exactly the same ordering. Replacing Huge Powers by Logarithmic Scores For every positive base \(b_i\), the natural logarithm is defined and satisfies $\ln(x_i)=\ln\!\left(b_i^{e_i}\right)=e_i\ln(b_i).$ This suggests attaching to each line the score $s_i=e_i\ln(b_i).$ The line with the largest power is exactly the line with the largest score. No big integers are needed; the whole comparison has been reduced to ordinary floating-point arithmetic on numbers of manageable size. The base of the logarithm is irrelevant....

Detailed mathematical approach

Problem Summary

The input consists of 1000 lines, each containing a pair \((b,e)\) representing the number \(b^e\). The task is not to compute the largest power itself, but to identify which 1-indexed line produces the largest numerical value.

The obstacle is size. Even a single value such as \(519432^{525806}\) is astronomically large, so ordinary exponentiation is the wrong mathematical object to work with. The real problem is a comparison problem: among all lines, which pair \((b_i,e_i)\) makes \(b_i^{e_i}\) as large as possible?

Mathematical Approach

Let the \(i\)-th line contain \((b_i,e_i)\), and write

$x_i=b_i^{e_i}.$

We want the line whose \(x_i\) is maximal. The implementations do not build \(x_i\) directly. Instead they replace each gigantic power by a much smaller real-valued score that preserves exactly the same ordering.

Replacing Huge Powers by Logarithmic Scores

For every positive base \(b_i\), the natural logarithm is defined and satisfies

$\ln(x_i)=\ln\!\left(b_i^{e_i}\right)=e_i\ln(b_i).$

This suggests attaching to each line the score

$s_i=e_i\ln(b_i).$

The line with the largest power is exactly the line with the largest score. No big integers are needed; the whole comparison has been reduced to ordinary floating-point arithmetic on numbers of manageable size.

The base of the logarithm is irrelevant. Using \(\log_{10}\), \(\ln\), or any other logarithm only multiplies every score by the same positive constant, so the winning line does not change. The implementations use the standard natural logarithm provided by each language runtime.

Why This Comparison Is Exact

The crucial fact is that \(\ln\) is strictly increasing on positive real numbers. Therefore, for any two lines \(i\) and \(j\),

$x_i > x_j \iff \ln(x_i) > \ln(x_j) \iff e_i\ln(b_i) > e_j\ln(b_j).$

Likewise, equality of the original powers would give equality of the logarithmic scores. So the transformation does not approximate the ordering; it preserves it exactly. The only approximation occurs in the numerical evaluation of the logarithm, not in the mathematics of the reduction.

Worked Comparisons

A small checkpoint makes the idea transparent. Compare \(2^{11}\) and \(3^7\). Their scores are

$11\ln 2 \approx 7.624618986,\qquad 7\ln 3 \approx 7.690286021.$

Since \(7\ln 3\) is larger, we conclude \(3^7 > 2^{11}\), exactly as expected.

The same method handles the larger comparison quoted in the problem discussion. Compare

$632382^{518061}\quad\text{and}\quad 519432^{525806}.$

The corresponding scores are

$518061\ln 632382 \approx 6919869.733217769$

$525806\ln 519432 \approx 6919865.228473604.$

The first score is larger, so

$632382^{518061} > 519432^{525806}.$

This is exactly the kind of comparison performed for every line in the dataset.

The Running-Maximum Invariant

Once each line is represented by \(s_i\), the remaining task is a simple maximum search. After processing the first \(k\) lines, maintain the invariant:

$\text{the stored line number is the line with the largest score among } s_1,s_2,\dots,s_k.$

When line \(k+1\) is read, compute its score \(s_{k+1}\). If \(s_{k+1}\) exceeds the current best score, replace the stored winner; otherwise keep the old one. By induction, the invariant remains true after every step, and after the final line the stored answer is the desired line number. If two scores were exactly equal, keeping the first one is consistent with the usual strict-update rule used by the implementations.

How the Code Works

Reading the Base-Exponent Pairs

The C++, Python, and Java implementations read the comma-separated input lines, split each line into a base and an exponent, and convert both parts into numeric values. Blank lines are ignored so that the scan only processes actual data rows.

Scoring Each Line

For every parsed pair \((b,e)\), the implementation computes the score \(e\ln(b)\). That number is the logarithm of \(b^e\), so it carries exactly the ordering information needed for the problem. The C++ implementation uses extended floating-point precision, while the Python and Java implementations use standard double-precision logarithms, but all three are evaluating the same mathematical quantity.

Keeping the Current Winner

The implementation stores only the best score seen so far and the corresponding 1-indexed line number. Each new score is compared with the current best; if it is larger, both stored values are updated. After the scan reaches the end of the list, the saved line number is printed as the answer.

Complexity Analysis

If the dataset has \(n\) lines, the algorithm performs one logarithm, one multiplication, and one comparison per line, so the running time is \(O(n)\). For Problem 99, \(n=1000\), so the total work is tiny.

The mathematical core needs only \(O(1)\) extra state: the current line number, the best score so far, and the best line number so far. Some implementations may read the small input into memory first because the file is tiny, but the comparison method itself is fundamentally a constant-space streaming scan.

Footnotes and References

  1. Project Euler Problem 99: https://projecteuler.net/problem=99
  2. Logarithm: Wikipedia - Logarithm
  3. Natural logarithm: Wikipedia - Natural logarithm
  4. Exponentiation: Wikipedia - Exponentiation
  5. IEEE 754 floating-point arithmetic: Wikipedia - IEEE 754

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 98 · All Project Euler solutions · Next: Problem 100

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮