Task: Greedy algorithm for Egyptian fractions


C++: #include <iostream>
#include <optional>
#include <vector>
#include <string>
#include <sstream>
#include <boost/multiprecision/cpp_int.hpp>

typedef boost::multiprecision::cpp_int integer;

struct fraction {
    fraction(const integer& n, const integer& d) : numerator(n), denominator(d) {}
    integer numerator;
    integer denominator;
};

integer mod(const integer& x, const integer& y) {
    return ((x % y) + y) % y;
}

size_t count_digits(const integer& i) {
    std::ostringstream os;
    os << i;
    return os.str().length();
}

std::string to_string(const integer& i) {
    const int max_digits = 20;
    std::ostringstream os;
    os << i;
    std::string s = os.str();
    if (s.length() > max_digits) {
        s = s.substr(0, max_digits/2) + "..." + s.substr(s.length()-max_digits/2);
    }
    return s;
}

std::ostream& operator<<(std::ostream& out, const fraction& f) {
    return out << to_string(f.numerator) << '/' << to_string(f.denominator);
}

void egyptian(const fraction& f, std::vector<fraction>& result) {
    result.clear();
    integer x = f.numerator, y = f.denominator;
    while (x > 0) {
        integer z = (y + x - 1)/x;
        result.emplace_back(1, z);
        x = mod(-y, x);
        y = y * z;
    }
}

void print_egyptian(const std::vector<fraction>& result) {
    if (result.empty())
        return;
    auto i = result.begin();
    std::cout << *i++;
    for (; i != result.end(); ++i)
        std::cout << " + " << *i;
    std::cout << '\n';
}

void print_egyptian(const fraction& f) {
    std::cout << "Egyptian fraction for " << f << ": ";
    integer x = f.numerator, y = f.denominator;
    if (x > y) {
        std::cout << "[" << x/y << "] ";
        x = x % y;
    }
    std::vector<fraction> result;
    egyptian(fraction(x, y), result);
    print_egyptian(result);
    std::cout << '\n';
}

void show_max_terms_and_max_denominator(const integer& limit) {
    size_t max_terms = 0;
    std::optional<fraction> max_terms_fraction, max_denominator_fraction;
    std::vector<fraction> max_terms_result;
    integer max_denominator = 0;
    std::vector<fraction> max_denominator_result;
    std::vector<fraction> result;
    for (integer b = 2; b < limit; ++b) {
        for (integer a = 1; a < b; ++a) {
            fraction f(a, b);
            egyptian(f, result);
            if (result.size() > max_terms) {
                max_terms = result.size();
                max_terms_result = result;
                max_terms_fraction = f;
            }
            const integer& denominator = result.back().denominator;
            if (denominator > max_denominator) {
                max_denominator = denominator;
                max_denominator_result = result;
                max_denominator_fraction = f;
            }
        }
    }
    std::cout << "Proper fractions with most terms and largest denominator, limit = " << limit << ":\n\n";
    std::cout << "Most terms (" << max_terms << "): " << max_terms_fraction.value() << " = ";
    print_egyptian(max_terms_result);
    std::cout << "\nLargest denominator (" << count_digits(max_denominator_result.back().denominator)
        << " digits): " << max_denominator_fraction.value() << " = ";
    print_egyptian(max_denominator_result);
}

int main() {
    print_egyptian(fraction(43, 48));
    print_egyptian(fraction(5, 121));
    print_egyptian(fraction(2014, 59));
    show_max_terms_and_max_denominator(100);
    show_max_terms_and_max_denominator(1000);
    return 0;
}






Python: from fractions import Fraction
from math import ceil

class Fr(Fraction):
    def __repr__(self):
        return '%s/%s' % (self.numerator, self.denominator)

def ef(fr):
    ans = []
    if fr >= 1:
        if fr.denominator == 1:
            return [[int(fr)], Fr(0, 1)]
        intfr = int(fr)
        ans, fr = [[intfr]], fr - intfr
    x, y = fr.numerator, fr.denominator
    while x != 1:
        ans.append(Fr(1, ceil(1/fr)))
        fr = Fr(-y % x, y* ceil(1/fr))
        x, y = fr.numerator, fr.denominator
    ans.append(fr)
    return ans

if __name__ == '__main__':
    for fr in [Fr(43, 48), Fr(5, 121), Fr(2014, 59)]:
        print('%r ─► %s' % (fr, ' '.join(str(x) for x in ef(fr))))
    lenmax = denommax = (0, None) 
    for fr in set(Fr(a, b) for a in range(1,100) for b in range(1, 100)):
        e = ef(fr)
        
        elen, edenom = len(e), e[-1].denominator
        if elen > lenmax[0]:
            lenmax = (elen, fr, e)
        if edenom > denommax[0]:
            denommax = (edenom, fr, e)
    print('Term max is %r with %i terms' % (lenmax[1], lenmax[0]))
    dstr = str(denommax[0])
    print('Denominator max is %r with %i digits %s...%s' %
          (denommax[1], len(dstr), dstr[:5], dstr[-5:]))