Tim Varley Logo
Tim Varley Systems Engineer
Problem #57 medium

Square root convergents

View on Project Euler

It is possible to show that the square root of two can be expressed as an infinite continued fraction.

2=1+12+12+12+\sqrt 2 =1+ \frac 1 {2+ \frac 1 {2 +\frac 1 {2+ \dots}}}

By expanding this for the first four iterations, we get:

1+12=32=1.51 + \frac 1 2 = \frac 32 = 1.5 1+12+12=75=1.41 + \frac 1 {2 + \frac 1 2} = \frac 7 5 = 1.4 1+12+12+12=1712=1.416661 + \frac 1 {2 + \frac 1 {2+\frac 1 2}} = \frac {17}{12} = 1.41666 \dots 1+12+12+12+12=4129=1.413791 + \frac 1 {2 + \frac 1 {2+\frac 1 {2+\frac 1 2}}} = \frac {41}{29} = 1.41379 \dots

The next three expansions are 9970\frac {99}{70}, 239169\frac {239}{169}, and 577408\frac {577}{408}, but the eighth expansion, 1393985\frac {1393}{985}, is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.

In the first one-thousand expansions, how many fractions contain a numerator with more digits than the denominator?

Implementations

cpp
// https://projecteuler.net/problem=57
// Square Root Convergents
// It is possible to show that the square root of two can be expressed as an infinite continued fraction.
// \sqrt 2 =1+ \frac 1 {2+ \frac 1 {2 +\frac 1 {2+ \dots}}}
// By expanding this for the first four iterations, we get:
// 1 + \frac 1 2 = \frac 32 = 1.5
// 1 + \frac 1 {2 + \frac 1 2} = \frac 7 5 = 1.4
// 1 + \frac 1 {2 + \frac 1 {2+\frac 1 2}} = \frac {17}{12} = 1.41666 \dots
// 1 + \frac 1 {2 + \frac 1 {2+\frac 1 {2+\frac 1 2}}} = \frac {41}{29} = 1.41379 \dots
// The next three expansions are \frac {99}{70}, \frac {239}{169}, and \frac {577}{408},
// but the eighth expansion, \frac {1393}{985}, is the first example where the number of digits
// in the numerator exceeds the number of digits in the denominator.
// In the first one-thousand expansions, how many fractions contain a numerator
// with more digits than the denominator?
// Answer: 153
#include <iostream>
#include <string>
#include <algorithm>
// Add two big integers represented as strings
static std::string add_strings(const std::string& a, const std::string& b) {
std::string result;
int carry = 0;
int i = a.size() - 1;
int j = b.size() - 1;
while (i >= 0 || j >= 0 || carry) {
int sum = carry;
if (i >= 0) sum += a[i--] - '0';
if (j >= 0) sum += b[j--] - '0';
carry = sum / 10;
result.push_back(sum % 10 + '0');
}
std::reverse(result.begin(), result.end());
return result;
}
// Multiply a big integer by 2 (just add to itself)
static std::string multiply_by_2(const std::string& s) {
return add_strings(s, s);
}
// Count expansions where numerator has more digits than denominator
int square_root_convergents() {
std::string a = "1"; // numerator
std::string b = "1"; // denominator
int count = 0;
for (int i = 0; i < 1000; ++i) {
// a(n+1) = 2*b(n) + a(n)
// b(n+1) = b(n) + a(n)
std::string two_b = multiply_by_2(b);
std::string next_a = add_strings(two_b, a);
std::string next_b = add_strings(b, a);
a = next_a;
b = next_b;
if (a.size() > b.size()) {
++count;
}
}
return count;
}
#if ! defined UNITTEST_MODE
int main(int argc, char const *argv[]) {
std::cout << square_root_convergents() << std::endl;
}
#endif // UNITTEST_MODE

Solution Notes

Mathematical Background

Diving into the elegant world of continued fractions, where 2\sqrt{2} unfolds as an infinite series of fractions. Each convergent brings us closer to the irrational truth, with numerators and denominators growing in fascinating patterns governed by recursive relations.

Algorithm Analysis

The solution brilliantly iterates through 1000 convergents, using string-based big integer arithmetic to handle enormous numbers. Each step computes the next fraction via the recurrence relations, checking digit lengths with simple string comparisons—no fancy libraries needed.

Key Insights

Out of the first 1000 expansions, 153 boast numerators with more digits than their denominators—a testament to the explosive growth of these mathematical beasts. The eighth convergent marks the first such occurrence, setting the stage for this counting challenge.

Educational Value

This problem masterfully illustrates recurrence relations and big integer handling in code, bridging abstract math with practical programming. It’s a gateway to understanding how computers tame infinite processes through finite approximations.