using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace EgyptianFractions {
    class Program {
        class Rational : IComparable<Rational>, IComparable<int> {
            public BigInteger Num { get; }
            public BigInteger Den { get; }

            public Rational(BigInteger n, BigInteger d) {
                var c = Gcd(n, d);
                Num = n / c;
                Den = d / c;
                if (Den < 0) {
                    Num = -Num;
                    Den = -Den;
                }
            }

            public Rational(BigInteger n) {
                Num = n;
                Den = 1;
            }

            public override string ToString() {
                if (Den == 1) {
                    return Num.ToString();
                } else {
                    return string.Format("{0}/{1}", Num, Den);
                }
            }

            public Rational Add(Rational rhs) {
                return new Rational(Num * rhs.Den + rhs.Num * Den, Den * rhs.Den);
            }

            public Rational Sub(Rational rhs) {
                return new Rational(Num * rhs.Den - rhs.Num * Den, Den * rhs.Den);
            }

            public int CompareTo(Rational rhs) {
                var ad = Num * rhs.Den;
                var bc = Den * rhs.Num;
                return ad.CompareTo(bc);
            }

            public int CompareTo(int rhs) {
                var ad = Num * rhs;
                var bc = Den * rhs;
                return ad.CompareTo(bc);
            }
        }

        static BigInteger Gcd(BigInteger a, BigInteger b) {
            if (b == 0) {
                if (a < 0) {
                    return -a;
                } else {
                    return a;
                }
            } else {
                return Gcd(b, a % b);
            }
        }

        static List<Rational> Egyptian(Rational r) {
            List<Rational> result = new List<Rational>();

            if (r.CompareTo(1) >= 0) {
                if (r.Den == 1) {
                    result.Add(r);
                    result.Add(new Rational(0));
                    return result;
                }
                result.Add(new Rational(r.Num / r.Den));
                r = r.Sub(result[0]);
            }

            BigInteger modFunc(BigInteger m, BigInteger n) {
                return ((m % n) + n) % n;
            }

            while (r.Num != 1) {
                var q = (r.Den + r.Num - 1) / r.Num;
                result.Add(new Rational(1, q));
                r = new Rational(modFunc(-r.Den, r.Num), r.Den * q);
            }

            result.Add(r);
            return result;
        }

        static string FormatList<T>(IEnumerable<T> col) {
            StringBuilder sb = new StringBuilder();
            var iter = col.GetEnumerator();

            sb.Append('[');
            if (iter.MoveNext()) {
                sb.Append(iter.Current);
            }
            while (iter.MoveNext()) {
                sb.AppendFormat(", {0}", iter.Current);
            }
            sb.Append(']');

            return sb.ToString();
        }

        static void Main() {
            List<Rational> rs = new List<Rational> {
                new Rational(43, 48),
                new Rational(5, 121),
                new Rational(2014, 59)
            };
            foreach (var r in rs) {
                Console.WriteLine("{0} => {1}", r, FormatList(Egyptian(r)));
            }

            var lenMax = Tuple.Create(0UL, new Rational(0));
            var denomMax = Tuple.Create(BigInteger.Zero, new Rational(0));

            var query = (from i in Enumerable.Range(1, 100)
                         from j in Enumerable.Range(1, 100)
                         select new Rational(i, j))
                         .Distinct()
                         .ToList();
            foreach (var r in query) {
                var e = Egyptian(r);
                ulong eLen = (ulong) e.Count;
                var eDenom = e.Last().Den;
                if (eLen > lenMax.Item1) {
                    lenMax = Tuple.Create(eLen, r);
                }
                if (eDenom > denomMax.Item1) {
                    denomMax = Tuple.Create(eDenom, r);
                }
            }

            Console.WriteLine("Term max is {0} with {1} terms", lenMax.Item2, lenMax.Item1);
            var dStr = denomMax.Item1.ToString();
            Console.WriteLine("Denominator max is {0} with {1} digits {2}...{3}", denomMax.Item2, dStr.Length, dStr.Substring(0, 5), dStr.Substring(dStr.Length - 5, 5));
        }
    }
}


""" https://rosettacode.org/wiki/Earliest_difference_between_prime_gaps """

from primesieve import primes

LIMIT = 10**9
pri = primes(LIMIT * 5)
gapstarts = {}
for i in range(1, len(pri)):
    if pri[i] - pri[i - 1] not in gapstarts:
        gapstarts[pri[i] - pri[i - 1]] = pri[i - 1]

PM, GAP1, = 10, 2
while True:
    while GAP1 not in gapstarts:
        GAP1 += 2
    start1 = gapstarts[GAP1]
    GAP2 = GAP1 + 2
    if GAP2 not in gapstarts:
        GAP1 = GAP2 + 2
        continue
    start2 = gapstarts[GAP2]
    diff = abs(start2 - start1)
    if diff > PM:
        print(f"Earliest difference >{PM: ,} between adjacent prime gap starting primes:")
        print(f"Gap {GAP1} starts at{start1: ,}, gap {GAP2} starts at{start2: ,}, difference is{diff: ,}.\n")
        if PM == LIMIT:
            break
        PM *= 10
    else:
        GAP1 = GAP2


use Math::Primesieve;
use Lingua::EN::Numbers;

my $iterator = Math::Primesieve::iterator.new;
my @gaps;
my $last = 2;

for 1..9 {
    my $m = exp $_, 10;
    my $this;
    loop {
        $this = (my $p = $iterator.next) - $last;
        if !@gaps[$this].defined {
             @gaps[$this]= $last;
             check-gap($m, $this, @gaps) && last
               if $this > 2 and @gaps[$this - 2].defined and (abs($last - @gaps[$this - 2]) > $m);
        }
        $last = $p;
    }
}

sub check-gap ($n, $this, @p) {
    my %upto = @p[^$this].pairs.grep: *.value;
    my @upto = (1..$this).map: { last unless %upto{$_ * 2}; %upto{$_ * 2} }
    my $key = @upto.rotor(2=>-1).first( {.sink; abs(.[0] - .[1]) > $n}, :k );
    return False unless $key;
    say "Earliest difference > {comma $n} between adjacent prime gap starting primes:";
    printf "Gap %s starts at %s, gap %s starts at %s, difference is %s\n\n",
    |(2 * $key + 2, @upto[$key], 2 * $key + 4, @upto[$key+1], abs(@upto[$key] - @upto[$key+1]))».,
    True
}


#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;
}


// [dependencies]
// primal = "0.3"

fn main() {
    use std::collections::HashMap;

    let mut primes = primal::Primes::all();
    let mut last_prime = primes.next().unwrap();
    let mut gap_starts = HashMap::new();

    let mut find_gap_start = move |gap: usize| -> usize {
        if let Some(start) = gap_starts.get(&gap) {
            return *start;
        }
        loop {
            let prev = last_prime;
            last_prime = primes.next().unwrap();
            let diff = last_prime - prev;
            if !gap_starts.contains_key(&diff) {
                gap_starts.insert(diff, prev);
            }
            if gap == diff {
                return prev;
            }
        }
    };

    let limit = 100000000000;

    let mut pm = 10;
    let mut gap1 = 2;
    loop {
        let start1 = find_gap_start(gap1);
        let gap2 = gap1 + 2;
        let start2 = find_gap_start(gap2);
        let diff = if start2 > start1 {
            start2 - start1
        } else {
            start1 - start2
        };
        if diff > pm {
            println!(
                "Earliest difference > {} between adjacent prime gap starting primes:\n\
                Gap {} starts at {}, gap {} starts at {}, difference is {}.\n",
                pm, gap1, start1, gap2, start2, diff
            );
            if pm == limit {
                break;
            }
            pm *= 10;
        } else {
            gap1 = gap2;
        }
    }
}


func prime_gap_records(upto) {

    var gaps = []
    var p = 3

    each_prime(p.next_prime, upto, {|q|
        gaps[q-p] := p
        p = q
    })

    gaps.grep { defined(_) }
}

var gaps = prime_gap_records(1e8)

for m in (1 .. gaps.max.len) {
    gaps.each_cons(2, {|p,q|
        if (abs(q-p) > 10**m) {
            say "10^#{m} -> (#{p}, #{q}) with gaps (#{
            p.next_prime-p}, #{q.next_prime-q}) and difference #{abs(q-p)}"
            break
        }
    })
}


import "./math" for Int
import "/fmt" for Fmt

var limit = 1e9
var gapStarts = {}
var primes = Int.segmentedSieve(limit * 5, 8 * 1024 * 1024) // 8 MB cache
for (i in 1...primes.count) {
    var gap = primes[i] - primes[i-1]
    if (!gapStarts[gap]) gapStarts[gap] = primes[i-1]
}
var pm = 10
var gap1 = 2
while (true) {
    while (!gapStarts[gap1]) gap1 = gap1 + 2
    var start1 = gapStarts[gap1]
    var gap2 = gap1 + 2
    if (!gapStarts[gap2]) {
        gap1 = gap2 + 2
        continue
    }
    var start2 = gapStarts[gap2]
    var diff = (start2 - start1).abs
    if (diff > pm) {
        Fmt.print("Earliest difference > $,d between adjacent prime gap starting primes:", pm)
        Fmt.print("Gap $d starts at $,d, gap $d starts at $,d, difference is $,d.\n", gap1, start1, gap2, start2, diff)
        if (pm == limit) break
        pm = pm * 10
    } else {
        gap1 = gap2
    }
}


(defun egyption-fractions (x y &optional acc)
  (let* ((a (/ x y)))
    (cond
     ((> (numerator a) (denominator a))
      (multiple-value-bind (q r) (floor x y)
	(if (zerop r)
	    (cons q acc)
	    (egyption-fractions r y (cons q acc)))))
     ((= (numerator a) 1) (reverse (cons a acc)))
     (t (let ((b (ceiling y x)))
	  (egyption-fractions (mod (- y) x) (* y b) (cons (/ b) acc)))))))

(defun test (n fn)
  (car (sort (loop for i from 1 to n append
		   (loop for j from 2 to n collect
			 (cons (/ i j) (funcall fn (egyption-fractions i j)))))
	     #'>
	     :key #'cdr)))


import std.stdio, std.bigint, std.algorithm, std.range, std.conv, std.typecons,
       arithmetic_rational: Rat = Rational;

Rat[] egyptian(Rat r) pure nothrow {
    typeof(return) result;

    if (r >= 1) {
        if (r.denominator == 1)
            return [r, Rat(0, 1)];
        result = [Rat(r.numerator / r.denominator, 1)];
        r -= result[0];
    }

    static enum mod = (in BigInt m, in BigInt n) pure nothrow =>
        ((m % n) + n) % n;

    while (r.numerator != 1) {
        immutable q = (r.denominator + r.numerator - 1) / r.numerator;
        result ~= Rat(1, q);
        r = Rat(mod(-r.denominator, r.numerator), r.denominator * q);
    }

    result ~= r;
    return result;
}

void main() {
    foreach (immutable r; [Rat(43, 48), Rat(5, 121), Rat(2014, 59)])
        writefln("%s => %(%s %)", r, r.egyptian);

    Tuple!(size_t, Rat) lenMax;
    Tuple!(BigInt, Rat) denomMax;

    foreach (immutable r; iota(1, 100).cartesianProduct(iota(1, 100))
                          .map!(nd => nd[].Rat).array.sort().uniq) {
        immutable e = r.egyptian;
        immutable eLen = e.length;
        immutable eDenom = e.back.denominator;
        if (eLen > lenMax[0])
            lenMax = tuple(eLen, r);
        if (eDenom > denomMax[0])
            denomMax = tuple(eDenom, r);
    }
    writefln("Term max is %s with %d terms", lenMax[1], lenMax[0]);
    immutable dStr = denomMax[0].text;
    writefln("Denominator max is %s with %d digits %s...%s",
             denomMax[1], dStr.length, dStr[0 .. 5], dStr[$ - 5 .. $]);
}


-module(egypt).

-import(lists, [reverse/1, seq/2]).
-export([frac/2, show/2, rosetta/0]).

rosetta() ->
    Fractions = [{N, D, second(frac(N, D))} || N <- seq(2,99), D <- seq(N+1, 99)],
    {Longest, A1, B1} = findmax(fun length/1, Fractions),
    io:format("~b/~b has ~b terms.~n", [A1, B1, Longest]),
    {Largest, A2, B2} = findmax(fun (L) -> hd(reverse(L)) end, Fractions),
    io:format("~b/~b has a really long denominator. (~b)~n", [A2, B2, Largest]).

second({_, B}) -> B.

findmax(Fn, L) -> findmax(Fn, L, 0, 0, 0).
findmax(_, [], M, A, B) -> {M, A, B};
findmax(Fn, [{A,B,Frac}|Fracs], M, A0, B0) ->
    Val = Fn(Frac),
    case Val > M of
        true  -> findmax(Fn, Fracs, Val, A, B);
        false -> findmax(Fn, Fracs, M, A0, B0)
    end.

show(A, B) ->
    {W, R} = frac(A, B),
    case W of
        0 -> ok;
        _ -> io:format("[~b] ", [W])
    end,
    case R of
        [] -> ok;
        [D0|Ds] ->
            io:format("1/~b ", [D0]),
            [io:format("+ 1/~b ", [D]) || D <- Ds],
            ok
    end.

frac(A, B) ->
    {A div B, reverse(proper(A rem B, B, []))}.

proper(0, _, L) -> L;
proper(1, Y, L) -> [Y|L];
proper(X, Y, L) ->
    D = ceildiv(Y, X),
    X2 = mod(-Y, X),
    Y2 = Y*ceildiv(Y, X),
    proper(X2, Y2, [D|L]).

ceildiv(A, B) ->
    Q = A div B,
    case A rem B of
        0 -> Q;
        _ -> Q+1
    end.

mod(A, M) ->
    B = A rem M,
    if
        B < 0 -> B + M;
        true -> B
    end.


USING: backtrack formatting fry kernel locals make math
math.functions math.ranges sequences ;
IN: rosetta-code.egyptian-fractions

: >improper ( r -- str ) >fraction "%d/%d" sprintf ;

: improper ( x y -- a b ) [ /i ] [ [ rem ] [ nip ] 2bi / ] 2bi ;

:: proper ( x y -- a b )
    y x / ceiling :> d1 1 d1 / y neg x rem y d1 * / ;

: expand ( a -- b c )
    >fraction 2dup > [ improper ] [ proper ] if ;

: egyptian-fractions ( x -- seq )
    [ [ expand [ , ] dip dup 0 = not ] loop drop ] { } make ;

: part1 ( -- )
    43/48 5/121 2014/59 [
        [ >improper ] [ egyptian-fractions ] bi
        "%s => %[%u, %]\n" printf
    ] [email protected] ;

: all-longest ( seq -- seq )
    dup longest length '[ length _ = ] filter ;

: (largest-denominator) ( seq -- n )
    [ denominator ] map supremum ;

: most-terms ( seq -- )
    all-longest [ [ sum ] map ] [ first length ] bi
    "most terms: %[%u, %] => %d\n" printf ;

: largest-denominator ( seq -- )
    [ (largest-denominator) ] supremum-by
    [ sum ] [ (largest-denominator) ] bi
    "largest denominator: %u => %d\n" printf ;

: part2 ( -- )
    [
        99 [1,b] amb-lazy dup [1,b] amb-lazy swap /
        egyptian-fractions
    ] bag-of [ most-terms ] [ largest-denominator ] bi ;

: egyptian-fractions-demo ( -- ) part1 part2 ;

MAIN: egyptian-fractions-demo


' version 16-01-2017
' compile with: fbc -s console

#Define max 30

#Include Once "gmp.bi"

Dim Shared As Mpz_ptr num(max), den(max)

Function Egyptian_fraction(fraction As String, ByRef whole As Integer, range As Integer = 0) As Integer

    If InStr(fraction,"/") = 0 Then
        Print "Not a fraction, program will end"
        Sleep 5000, 1
        End
    End If

    Dim As Integer i, count

    Dim As Mpz_ptr tmp_num, tmp_den, x, y, q
    tmp_num = Allocate(Len(__Mpz_struct)) : Mpz_init(tmp_num)
    tmp_den = Allocate(Len(__Mpz_struct)) : Mpz_init(tmp_den)
    x = Allocate(Len(__Mpz_struct)) : Mpz_init(x)
    y = Allocate(Len(__Mpz_struct)) : Mpz_init(y)
    q = Allocate(Len(__Mpz_struct)) : Mpz_init(q)

    For i = 1 To max ' clear the list
        Mpz_set_ui(num(i), 0)
        Mpz_set_ui(den(i), 0)
    Next

    i = InStr(fraction,"/")
    Mpz_set_str(x, Left(fraction, i -1), 10)
    Mpz_set_str(y, Right(fraction, Len(fraction) - i), 10)

    ' if it's a improper fraction make it proper fraction
    If Mpz_cmp(x , y) > 0  Then
        Mpz_fdiv_q(q, x, y)
        whole = Mpz_get_ui(q)
        Mpz_fdiv_r(x, x, q)
    Else
        whole = 0
    End If

    Mpz_gcd(q, x, y) ' check if reduction is possible
    If Mpz_cmp_ui(q, 1) > 0 Then
        If range <> 0 Then ' return if we do a range test
            Return -1
        Else
            Mpz_fdiv_q(x, x, q)
            Mpz_fdiv_q(y, y, q)
        End If
    End If

    Mpz_set(num(count), x)
    Mpz_set(den(count), y)
    ' Fibonacci's Greedy algorithm for Egyptian fractions
    Do
        If Mpz_cmp_ui(num(count), 1) = 0 Then Exit Do
        Mpz_set(x, num(count))
        Mpz_set(y, den(count))
        Mpz_cdiv_q(q, y, x)
        Mpz_set_ui(num(count), 1)
        Mpz_set(den(count), q)
        Mpz_mul(tmp_den, y, q)
        Mpz_neg(y, y)
        Mpz_mod(tmp_num, y, x)
        count += 1
        Mpz_gcd(q, tmp_num, tmp_den) ' check if reduction is possible
        If Mpz_cmp_ui(q, 1) > 0 Then
            Mpz_fdiv_q(tmp_num, tmp_num, q)
            Mpz_fdiv_q(tmp_den, tmp_den, q)
        End If
        Mpz_set(num(count), tmp_num)
        Mpz_set(den(count), tmp_den)
    Loop

    Mpz_clear(tmp_num) : Mpz_clear(tmp_den)
    Mpz_clear(x) : Mpz_clear(y) :Mpz_clear(q)

    Return count

End Function

Sub prt_solution(fraction As String, whole As Integer, count As Integer)

    Print fraction; " = ";

    If whole <> 0 Then
        Print "["; Str(whole); "] + ";
    End If

    For i As Integer = 0 To count
        Gmp_printf("%Zd/%Zd ", num(i), den(i))
        If i <> count Then Print "+ ";
    Next
    Print

End Sub

' ------=< MAIN >=------

Dim As Integer n, d, number, improper, max_term,  max_size
Dim As String str_in, max_term_str, max_size_str, m_str
Dim As ZString Ptr gmp_str : gmp_str = Allocate(1000000)

For n = 0 To max
    num(n) = Allocate(Len(__Mpz_struct)) : Mpz_init(num(n))
    den(n) = Allocate(Len(__Mpz_struct)) : Mpz_init(den(n))
Next

Data "43/48", "5/121", "2014/59"
' 4/121 = 12/363 = 11/363 + 1/363 = 1/33 + 1/363
' 5/121 = 4/121 + 1/121 = 1/33 + 1/121 + 1/363
' 2014/59 = 34 + 8/59
' 8/59 = 1/8 + 5/472 = 1/8 + 4/472 + 1/472 = 1/8 + 1/118 + 1/472

For n = 1 To 3
    Read str_in
    number = Egyptian_fraction(str_in, improper)
    prt_solution(str_in, improper, number)
    Print
Next

Dim As Integer a = 1 , b = 99

Do
    For d = a To b
        For n = 1 To d -1
            str_in = Str(n) + "/" + Str(d)
            number = Egyptian_fraction(str_in, improper,1)
            If number = -1 Then Continue For ' skip
            If number > max_term Then
                max_term = number
                max_term_str = str_in
            ElseIf number = max_term Then
                max_term_str += ", " & str_in
            End If
            Mpz_get_str(gmp_str, 10, den(number))
            If Len(*gmp_str) > max_size Then
                max_size = Len(*gmp_str)
                max_size_str = str_in
                m_str = *gmp_str
            ElseIf max_size = Len(*gmp_str) Then
                max_size_str += ", " & str_in
            End If
        Next
    Next
    Print
    Print "for 1 to"; Len(Str(b)); " digits"
    Print "Largest number of terms is"; max_term +1; " for "; max_term_str
    Print "Largest size for denominator is"; max_size; " for "; max_size_str

    If b = 999 Then Exit Do
    a = b +1 : b = b * 10 +9
Loop

For n = 0 To max
    Mpz_clear(num(n))
    Mpz_clear(den(n))
Next

DeAllocate(gmp_str)

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


frac[p, q] :=
{
    a = makeArray[[0]]
    if p > q
    {
        a.push[floor[p / q]]
        p = p mod q
    }
    while p > 1
    {
        d = ceil[q / p]
        a.push[1/d]
        [p, q] = [-q mod p, d q]
    }
    if p == 1
        a.push[1/q]
    a
}

showApproximations[false]

egypt[p, q] := join[" + ", frac[p, q]]

rosetta[] :=
{
    lMax = 0
    longest = 0

    dMax = 0
    biggest = 0

    for n = 1 to 99
        for d = n+1 to 99
        {
            egypt = frac[n, d]
            if length[egypt] > lMax
            {
                lMax = length[egypt]
                longest = n/d
            }
            d2 = denominator[last[egypt, 1]@0]
            if d2 > dMax
            {
                dMax = d2
                biggest = n/d
            }
        }

    println["The fraction with the largest number of terms is $longest"]
    println["The fraction with the largest denominator is $biggest"]
}


package main

import (
    "fmt"
    "math/big"
    "strings"
)

var zero = new(big.Int)
var one = big.NewInt(1)

func toEgyptianRecursive(br *big.Rat, fracs []*big.Rat) []*big.Rat {
    if br.Num().Cmp(zero) == 0 {
        return fracs
    }
    iquo := new(big.Int)
    irem := new(big.Int)
    iquo.QuoRem(br.Denom(), br.Num(), irem)
    if irem.Cmp(zero) > 0 {
        iquo.Add(iquo, one)
    }
    rquo := new(big.Rat).SetFrac(one, iquo)
    fracs = append(fracs, rquo)
    num2 := new(big.Int).Neg(br.Denom())
    num2.Rem(num2, br.Num())
    if num2.Cmp(zero) < 0 {
        num2.Add(num2, br.Num())
    }
    denom2 := new(big.Int)
    denom2.Mul(br.Denom(), iquo)
    f := new(big.Rat).SetFrac(num2, denom2)
    if f.Num().Cmp(one) == 0 {
        fracs = append(fracs, f)
        return fracs
    }
    fracs = toEgyptianRecursive(f, fracs)
    return fracs
}

func toEgyptian(rat *big.Rat) []*big.Rat {
    if rat.Num().Cmp(zero) == 0 {
        return []*big.Rat{rat}
    }
    var fracs []*big.Rat
    if rat.Num().CmpAbs(rat.Denom()) >= 0 {
        iquo := new(big.Int)
        iquo.Quo(rat.Num(), rat.Denom())
        rquo := new(big.Rat).SetFrac(iquo, one)
        rrem := new(big.Rat)
        rrem.Sub(rat, rquo)
        fracs = append(fracs, rquo)
        fracs = toEgyptianRecursive(rrem, fracs)
    } else {
        fracs = toEgyptianRecursive(rat, fracs)
    }
    return fracs
}

func main() {
    fracs := []*big.Rat{big.NewRat(43, 48), big.NewRat(5, 121), big.NewRat(2014, 59)}
    for _, frac := range fracs {
        list := toEgyptian(frac)
        if list[0].Denom().Cmp(one) == 0 {
            first := fmt.Sprintf("[%v]", list[0].Num())
            temp := make([]string, len(list)-1)
            for i := 1; i < len(list); i++ {
                temp[i-1] = list[i].String()
            }
            rest := strings.Join(temp, " + ")
            fmt.Printf("%v -> %v + %s\n", frac, first, rest)
        } else {
            temp := make([]string, len(list))
            for i := 0; i < len(list); i++ {
                temp[i] = list[i].String()
            }
            all := strings.Join(temp, " + ")
            fmt.Printf("%v -> %s\n", frac, all)
        }
    }

    for _, r := range [2]int{98, 998} {
        if r == 98 {
            fmt.Println("\nFor proper fractions with 1 or 2 digits:")
        } else {
            fmt.Println("\nFor proper fractions with 1, 2 or 3 digits:")
        }
        maxSize := 0
        var maxSizeFracs []*big.Rat
        maxDen := zero
        var maxDenFracs []*big.Rat
        var sieve = make([][]bool, r+1) // to eliminate duplicates
        for i := 0; i <= r; i++ {
            sieve[i] = make([]bool, r+2)
        }
        for i := 1; i <= r; i++ {
            for j := i + 1; j <= r+1; j++ {
                if sieve[i][j] {
                    continue
                }
                f := big.NewRat(int64(i), int64(j))
                list := toEgyptian(f)
                listSize := len(list)
                if listSize > maxSize {
                    maxSize = listSize
                    maxSizeFracs = maxSizeFracs[0:0]
                    maxSizeFracs = append(maxSizeFracs, f)
                } else if listSize == maxSize {
                    maxSizeFracs = append(maxSizeFracs, f)
                }
                listDen := list[len(list)-1].Denom()
                if listDen.Cmp(maxDen) > 0 {
                    maxDen = listDen
                    maxDenFracs = maxDenFracs[0:0]
                    maxDenFracs = append(maxDenFracs, f)
                } else if listDen.Cmp(maxDen) == 0 {
                    maxDenFracs = append(maxDenFracs, f)
                }
                if i < r/2 {
                    k := 2
                    for {
                        if j*k > r+1 {
                            break
                        }
                        sieve[i*k][j*k] = true
                        k++
                    }
                }
            }
        }
        fmt.Println("  largest number of items =", maxSize)
        fmt.Println("  fraction(s) with this number :", maxSizeFracs)
        md := maxDen.String()
        fmt.Print("  largest denominator = ", len(md), " digits, ")
        fmt.Print(md[0:20], "...", md[len(md)-20:], "\b\n")
        fmt.Println("  fraction(s) with this denominator :", maxDenFracs)
    }
}


import Data.Ratio (Ratio, (%), denominator, numerator)

egyptianFraction :: Integral a => Ratio a -> [Ratio a]
egyptianFraction n
  | n < 0 = map negate (egyptianFraction (-n))
  | n == 0 = []
  | x == 1 = [n]
  | x > y = (x `div` y % 1) : egyptianFraction (x `mod` y % y)
  | otherwise = (1 % r) : egyptianFraction ((-y) `mod` x % (y * r))
  where
    x = numerator n
    y = denominator n
    r = y `div` x + 1


F reversed(Int =n)
   V result = 0
   L
      result = 10 * result + n % 10
      n I/= 10
      I n == 0
         R result

V limit = 1'000'000
V is_prime = [0B] * 2 [+] [1B] * (limit - 1)
L(n) 0 .< Int(limit ^ 0.5 + 1.5)
   I is_prime[n]
      L(i) (n * n .< limit + 1).step(n)
         is_prime[i] = 0B

F is_emirp(n)
   I !:is_prime[n]
      R 0B
   V r = reversed(n)
   R r != n & :is_prime[r]

print(‘First 20 emirps:’, end' ‘’)
V count = 0
L(n) 0 .< limit
   I is_emirp(n)
      print(‘ ’n, end' ‘’)
      I ++count == 20
         L.break
print()

print(‘Emirps between 7700 and 8000:’, end' ‘’)
L(n) 7700..8000
   I is_emirp(n)
      print(‘ ’n, end' ‘’)
print()

count = 0
L(n) 0 .< limit
   I is_emirp(n)
      I ++count == 10000
         print(‘The 10000th emirp: ’n)
         L.break


import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class EgyptianFractions {
    private static BigInteger gcd(BigInteger a, BigInteger b) {
        if (b.equals(BigInteger.ZERO)) {
            return a;
        }
        return gcd(b, a.mod(b));
    }

    private static class Frac implements Comparable<Frac> {
        private BigInteger num, denom;

        public Frac(BigInteger n, BigInteger d) {
            if (d.equals(BigInteger.ZERO)) {
                throw new IllegalArgumentException("Parameter d may not be zero.");
            }

            BigInteger nn = n;
            BigInteger dd = d;
            if (nn.equals(BigInteger.ZERO)) {
                dd = BigInteger.ONE;
            } else if (dd.compareTo(BigInteger.ZERO) < 0) {
                nn = nn.negate();
                dd = dd.negate();
            }
            BigInteger g = gcd(nn, dd).abs();
            if (g.compareTo(BigInteger.ZERO) > 0) {
                nn = nn.divide(g);
                dd = dd.divide(g);
            }
            num = nn;
            denom = dd;
        }

        public Frac(int n, int d) {
            this(BigInteger.valueOf(n), BigInteger.valueOf(d));
        }

        public Frac plus(Frac rhs) {
            return new Frac(
                num.multiply(rhs.denom).add(denom.multiply(rhs.num)),
                rhs.denom.multiply(denom)
            );
        }

        public Frac unaryMinus() {
            return new Frac(num.negate(), denom);
        }

        public Frac minus(Frac rhs) {
            return plus(rhs.unaryMinus());
        }

        @Override
        public int compareTo(Frac rhs) {
            BigDecimal diff = this.toBigDecimal().subtract(rhs.toBigDecimal());
            if (diff.compareTo(BigDecimal.ZERO) < 0) {
                return -1;
            }
            if (BigDecimal.ZERO.compareTo(diff) < 0) {
                return 1;
            }
            return 0;
        }

        @Override
        public boolean equals(Object obj) {
            if (null == obj || !(obj instanceof Frac)) {
                return false;
            }
            Frac rhs = (Frac) obj;
            return compareTo(rhs) == 0;
        }

        @Override
        public String toString() {
            if (denom.equals(BigInteger.ONE)) {
                return num.toString();
            }
            return String.format("%s/%s", num, denom);
        }

        public BigDecimal toBigDecimal() {
            BigDecimal bdn = new BigDecimal(num);
            BigDecimal bdd = new BigDecimal(denom);
            return bdn.divide(bdd, MathContext.DECIMAL128);
        }

        public List<Frac> toEgyptian() {
            if (num.equals(BigInteger.ZERO)) {
                return Collections.singletonList(this);
            }
            List<Frac> fracs = new ArrayList<>();
            if (num.abs().compareTo(denom.abs()) >= 0) {
                Frac div = new Frac(num.divide(denom), BigInteger.ONE);
                Frac rem = this.minus(div);
                fracs.add(div);
                toEgyptian(rem.num, rem.denom, fracs);
            } else {
                toEgyptian(num, denom, fracs);
            }
            return fracs;
        }

        public void toEgyptian(BigInteger n, BigInteger d, List<Frac> fracs) {
            if (n.equals(BigInteger.ZERO)) {
                return;
            }
            BigDecimal n2 = new BigDecimal(n);
            BigDecimal d2 = new BigDecimal(d);
            BigDecimal[] divRem = d2.divideAndRemainder(n2, MathContext.UNLIMITED);
            BigInteger div = divRem[0].toBigInteger();
            if (divRem[1].compareTo(BigDecimal.ZERO) > 0) {
                div = div.add(BigInteger.ONE);
            }
            fracs.add(new Frac(BigInteger.ONE, div));
            BigInteger n3 = d.negate().mod(n);
            if (n3.compareTo(BigInteger.ZERO) < 0) {
                n3 = n3.add(n);
            }
            BigInteger d3 = d.multiply(div);
            Frac f = new Frac(n3, d3);
            if (f.num.equals(BigInteger.ONE)) {
                fracs.add(f);
                return;
            }
            toEgyptian(f.num, f.denom, fracs);
        }
    }

    public static void main(String[] args) {
        List<Frac> fracs = List.of(
            new Frac(43, 48),
            new Frac(5, 121),
            new Frac(2014, 59)
        );
        for (Frac frac : fracs) {
            List<Frac> list = frac.toEgyptian();
            Frac first = list.get(0);
            if (first.denom.equals(BigInteger.ONE)) {
                System.out.printf("%s -> [%s] + ", frac, first);
            } else {
                System.out.printf("%s -> %s", frac, first);
            }
            for (int i = 1; i < list.size(); ++i) {
                System.out.printf(" + %s", list.get(i));
            }
            System.out.println();
        }

        for (Integer r : List.of(98, 998)) {
            if (r == 98) {
                System.out.println("\nFor proper fractions with 1 or 2 digits:");
            } else {
                System.out.println("\nFor proper fractions with 1, 2 or 3 digits:");
            }

            int maxSize = 0;
            List<Frac> maxSizeFracs = new ArrayList<>();
            BigInteger maxDen = BigInteger.ZERO;
            List<Frac> maxDenFracs = new ArrayList<>();
            boolean[][] sieve = new boolean[r + 1][];
            for (int i = 0; i < r + 1; ++i) {
                sieve[i] = new boolean[r + 2];
            }
            for (int i = 1; i < r; ++i) {
                for (int j = i + 1; j < r + 1; ++j) {
                    if (sieve[i][j]) continue;
                    Frac f = new Frac(i, j);
                    List<Frac> list = f.toEgyptian();
                    int listSize = list.size();
                    if (listSize > maxSize) {
                        maxSize = listSize;
                        maxSizeFracs.clear();
                        maxSizeFracs.add(f);
                    } else if (listSize == maxSize) {
                        maxSizeFracs.add(f);
                    }
                    BigInteger listDen = list.get(list.size() - 1).denom;
                    if (listDen.compareTo(maxDen) > 0) {
                        maxDen = listDen;
                        maxDenFracs.clear();
                        maxDenFracs.add(f);
                    } else if (listDen.equals(maxDen)) {
                        maxDenFracs.add(f);
                    }
                    if (i < r / 2) {
                        int k = 2;
                        while (true) {
                            if (j * k > r + 1) break;
                            sieve[i * k][j * k] = true;
                            k++;
                        }
                    }
                }
            }
            System.out.printf("  largest number of items = %s\n", maxSize);
            System.out.printf("fraction(s) with this number : %s\n", maxSizeFracs);
            String md = maxDen.toString();
            System.out.printf("  largest denominator = %s digits, ", md.length());
            System.out.printf("%s...%s\n", md.substring(0, 20), md.substring(md.length() - 20, md.length()));
            System.out.printf("fraction(s) with this denominator : %s\n", maxDenFracs);
        }
    }
}


with Ada.Text_IO, Miller_Rabin;

procedure Emirp_Gen is

   type Num is range 0 .. 2**63-1; -- maximum for the gnat Ada compiler

   MR_Iterations: constant Positive := 25;
     -- the probability Pr[Is_Prime(N, MR_Iterations) = Probably_Prime]
     -- is 1 for prime N and < 4**(-MR_Iterations) for composed N

   function Is_Emirp(E: Num) return Boolean is
      package MR is new Miller_Rabin(Num); use MR;

      function Rev(E: Num) return Num is
	 N: Num := E;
	 R: Num := 0;
      begin
	 while N > 0 loop
	    R := 10*R + N mod 10; -- N mod 10 is least significant digit of N
	    N := N / 10;          -- delete least significant digit of N
	 end loop;
	 return R;
      end Rev;

      R: Num := Rev(E);
   begin
      return E /= R and then
	     (Is_Prime(E, MR_Iterations) = Probably_Prime) and then
	     (Is_Prime(R, MR_Iterations) = Probably_Prime);
   end Is_Emirp;

   function Next(P: Num) return Num is
      N: Num := P+1;
   begin
      while not (Is_Emirp(N)) Loop
	 N := N + 1;
      end loop;
      return N;
   end Next;

   Current: Num;
   Count: Num := 0;

begin
   -- show the first twenty emirps
   Ada.Text_IO.Put("First 20 emirps:");
   Current := 1;
   for I in 1 .. 20 loop
      Current := Next(Current);
      Ada.Text_IO.Put(Num'Image(Current));
   end loop;
   Ada.Text_IO.New_Line;

   -- show the emirps between 7700 and 8000
   Ada.Text_IO.Put("Emirps between 7700 and 8000:");
   Current := 7699;
   loop
      Current := Next(Current);
      exit when Current > 8000;
       Ada.Text_IO.Put(Num'Image(Current));
   end loop;

   -- the 10_000th emirp
   Ada.Text_IO.Put("The 10_000'th emirp:");
   for I in 1 .. 10_000 loop
      Current := Next(Current);
   end loop;
   Ada.Text_IO.Put_Line(Num'Image(Current));
end Emirp_Gen;


# parse the command line - ignore errors                                      #
INT  emirp from  :=  1;        # lowest emirp required                        #
INT  emirp to    := 10;        # highest emirp required                       #
BOOL value range := FALSE;     # TRUE if the range is the value of the emirps #
                               # FALSE if the range is the ordinal of the     #
                               # emirps                                       #
INT  max number  := 1 000 000; # sieve size                                   #
# returns s converted to an integer - does not check s is a valid integer     #
PROC to int = ( STRING s )INT:
     BEGIN
        INT result := 0;
        FOR ch pos FROM LWB s TO UPB s DO
            result *:= 10;
            result +:= ABS s[ ch pos ] - ABS "0"
        OD;
        result
     END # to int # ;
FOR arg pos TO argc DO
    IF   argv( arg pos ) = "FROM"    THEN
        emirp from  := to int( argv( arg pos + 1 ) )
    ELIF argv( arg pos ) = "TO"      THEN
        emirp to    := to int( argv( arg pos + 1 ) )
    ELIF argv( arg pos ) = "VALUE"   THEN
        value range := TRUE
    ELIF argv( arg pos ) = "ORDINAL" THEN
        value range := FALSE
    ELIF argv( arg pos ) = "SIEVE"   THEN
        max number  := to int( argv( arg pos + 1 ) )
    FI
OD;

# construct a sieve of primes up to the maximum number required for the task  #
PR read "primes.incl.a68" PR
[]BOOL is prime = PRIMESIEVE max number;

# return TRUE if p is an emirp, FALSE otherwise                               #
PROC is emirp = ( INT p )BOOL:
     IF NOT is prime[ p ] THEN
        FALSE
     ELSE
        # reverse the digits of p, if this is a prime different from p,       #
        # p is an emirp                                                       #
        INT q    := 0;
        INT rest := ABS p;
        WHILE rest > 0 DO
            q    TIMESAB 10;
            q    PLUSAB  rest MOD 10;
            rest OVERAB  10
        OD;
        is prime[ q ] AND q /= p
     FI # is emirp # ;

# generate the required emirp list                                            #
IF value range THEN
    # find emirps with values in the specified range                          #
    print( ( "emirps between ", whole( emirp from, 0 ), " and ", whole( emirp to, 0 ), ":" ) );
    FOR p FROM emirp from TO emirp to DO
        IF is emirp( p ) THEN
            print( ( " ", whole( p, 0 ) ) )
        FI
    OD
ELSE
    # find emirps with ordinals in the specified range                        #
    INT emirp count := 0;
    IF emirp from = emirp to THEN
        print( ( "emirp ", whole( emirp from, 0 ), ":" ) )
    ELSE
        print( ( "emirps ", whole( emirp from, 0 ), " to ", whole( emirp to, 0 ), ":" ) )
    FI;
    FOR p TO max number WHILE emirp count < emirp to DO
        IF is emirp( p ) THEN
            # have another emirp                                              #
            emirp count +:= 1;
            IF emirp count >= emirp from THEN
                print( ( " ", whole( p, 0 ) ) )
            FI
        FI
    OD
FI;
print( ( newline ) )


struct EgyptianFraction{T<:Integer} <: Real
    int::T
    frac::NTuple{N,Rational{T}} where N
end

Base.show(io::IO, ef::EgyptianFraction) = println(io, "[", ef.int, "] ", join(ef.frac, " + "))
Base.length(ef::EgyptianFraction) = !iszero(ef.int) + length(ef.frac)
function Base.convert(::Type{EgyptianFraction{T}}, fr::Rational) where T
    fr, int::T = modf(fr)
    fractions = Vector{Rational{T}}(0)
    x::T, y::T = numerator(fr), denominator(fr)
    iszero(x) && return EgyptianFraction{T}(int, (x // y,))
    while x != one(x)
        push!(fractions, one(T) // cld(y, x))
        x, y = mod1(-y, x), y * cld(y, x)
        d = gcd(x, y)
        x ÷= d
        y ÷= d
    end
    push!(fractions, x // y)
    return EgyptianFraction{T}(int, tuple(fractions...))
end
Base.convert(::Type{EgyptianFraction}, fr::Rational{T}) where T = convert(EgyptianFraction{T}, fr)
Base.convert(::Type{EgyptianFraction{T}}, fr::EgyptianFraction) where T = EgyptianFraction{T}(convert(T, fr.int), convert.(Rational{T}, fr.frac))
Base.convert(::Type{Rational{T}}, fr::EgyptianFraction) where T = T(fr.int) + sum(convert.(Rational{T}, fr.frac))
Base.convert(::Type{Rational}, fr::EgyptianFraction{T}) where T = convert(Rational{T}, fr)

@show EgyptianFraction(43 // 48)
@show EgyptianFraction{BigInt}(5 // 121)
@show EgyptianFraction(2014 // 59)

function task(fractions::AbstractVector)
    fracs = convert(Vector{EgyptianFraction{BigInt}}, fractions)
    local frlenmax::EgyptianFraction{BigInt}
    local lenmax = 0
    local frdenmax::EgyptianFraction{BigInt}
    local denmax = 0
    for f in fracs
        if length(f) ≥ lenmax
            lenmax = length(f)
            frlenmax = f
        end
        if denominator(last(f.frac)) ≥ denmax
            denmax = denominator(last(f.frac))
            frdenmax = f
        end
    end
    return frlenmax, lenmax, frdenmax, denmax
end

fr = collect((x // y) for x in 1:100 for y in 1:100 if x != y) |> unique
frlenmax, lenmax, frdenmax, denmax = task(fr)
println("Longest fraction, with length $lenmax: \n", Rational(frlenmax), "\n = ", frlenmax)
println("Fraction with greatest denominator\n(that is $denmax):\n", Rational(frdenmax), "\n = ", frdenmax)

println("\n# For 1 digit-integers:")
fr = collect((x // y) for x in 1:10 for y in 1:10 if x != y) |> unique
frlenmax, lenmax, frdenmax, denmax = task(fr)
println("Longest fraction, with length $lenmax: \n", Rational(frlenmax), "\n = ", frlenmax)
println("Fraction with greatest denominator\n(that is $denmax):\n", Rational(frdenmax), "\n = ", frdenmax)

println("# For 3 digit-integers:")
fr = collect((x // y) for x in 1:1000 for y in 1:1000 if x != y) |> unique
frlenmax, lenmax, frdenmax, denmax = task(fr)
println("Longest fraction, with length $lenmax: \n", Rational(frlenmax), "\n = ", frlenmax)
println("Fraction with greatest denominator\n(that is $denmax):\n", Rational(frdenmax), "\n = ", frdenmax)


// version 1.2.10

import java.math.BigInteger
import java.math.BigDecimal
import java.math.MathContext

val bigZero = BigInteger.ZERO
val bigOne  = BigInteger.ONE
val bdZero  = BigDecimal.ZERO
val context = MathContext.UNLIMITED

fun gcd(a: BigInteger, b: BigInteger): BigInteger
    = if (b == bigZero) a else gcd(b, a % b)

class Frac : Comparable<Frac> {
    val num: BigInteger
    val denom: BigInteger

    constructor(n: BigInteger, d: BigInteger) {
        require(d != bigZero)
        var nn = n
        var dd = d
        if (nn == bigZero) {
            dd = bigOne
        }
        else if (dd < bigZero) {
            nn = -nn
            dd = -dd
        }
        val g = gcd(nn, dd).abs()
        if (g > bigOne) {
            nn /= g
            dd /= g
        }
        num = nn
        denom = dd
    }

    constructor(n: Int, d: Int) : this(n.toBigInteger(), d.toBigInteger())

    operator fun plus(other: Frac) =
        Frac(num * other.denom + denom * other.num, other.denom * denom)

    operator fun unaryMinus() = Frac(-num, denom)

    operator fun minus(other: Frac) = this + (-other)

    override fun compareTo(other: Frac): Int {
        val diff = this.toBigDecimal() - other.toBigDecimal()
        return when {
            diff < bdZero  -> -1
            diff > bdZero  -> +1
            else           ->  0
        }
    }

    override fun equals(other: Any?): Boolean {
       if (other == null || other !is Frac) return false
       return this.compareTo(other) == 0
    }

    override fun toString() = if (denom == bigOne) "$num" else "$num/$denom"

    fun toBigDecimal() = num.toBigDecimal() / denom.toBigDecimal()

    fun toEgyptian(): List<Frac> {
        if (num == bigZero) return listOf(this)
        val fracs = mutableListOf<Frac>()
        if (num.abs() >= denom.abs()) {
            val div = Frac(num / denom, bigOne)
            val rem = this - div
            fracs.add(div)
            toEgyptian(rem.num, rem.denom, fracs)
        }
        else {
            toEgyptian(num, denom, fracs)
        }
        return fracs
    }

    private tailrec fun toEgyptian(
        n: BigInteger,
        d: BigInteger,
        fracs: MutableList<Frac>
    ) {
        if (n == bigZero) return
        val n2 = n.toBigDecimal()
        val d2 = d.toBigDecimal()
        var divRem = d2.divideAndRemainder(n2, context)
        var div = divRem[0].toBigInteger()
        if (divRem[1] > bdZero) div++
        fracs.add(Frac(bigOne, div))
        var n3 = (-d) % n
        if (n3 < bigZero) n3 += n
        val d3 = d * div
        val f = Frac(n3, d3)
        if (f.num == bigOne) {
            fracs.add(f)
            return
        }
        toEgyptian(f.num, f.denom, fracs)
    }
}

fun main(args: Array<String>) {
    val fracs = listOf(Frac(43, 48), Frac(5, 121), Frac(2014,59))
    for (frac in fracs) {
        val list = frac.toEgyptian()
        if (list[0].denom == bigOne) {
            val first = "[${list[0]}]"
            println("$frac -> $first + ${list.drop(1).joinToString(" + ")}")
        }
        else {
            println("$frac -> ${list.joinToString(" + ")}")
        }
    }

    for (r in listOf(98, 998)) {
        if (r == 98)
            println("\nFor proper fractions with 1 or 2 digits:")
        else
            println("\nFor proper fractions with 1, 2 or 3 digits:")
        var maxSize = 0
        var maxSizeFracs = mutableListOf<Frac>()
        var maxDen = bigZero
        var maxDenFracs = mutableListOf<Frac>()
        val sieve = List(r + 1) { BooleanArray(r + 2) }  // to eliminate duplicates
        for (i in 1..r) {
            for (j in (i + 1)..(r + 1)) {
                if (sieve[i][j]) continue
                val f = Frac(i, j)
                val list = f.toEgyptian()
                val listSize = list.size
                if (listSize > maxSize) {
                    maxSize = listSize
                    maxSizeFracs.clear()
                    maxSizeFracs.add(f)
                }
                else if (listSize == maxSize) {
                    maxSizeFracs.add(f)
                }
                val listDen = list[list.lastIndex].denom
                if (listDen > maxDen) {
                    maxDen = listDen
                    maxDenFracs.clear()
                    maxDenFracs.add(f)
                }
                else if (listDen == maxDen) {
                    maxDenFracs.add(f)
                }
                if (i < r / 2) {
                   var k = 2
                   while (true) {
                       if (j * k > r + 1) break
                       sieve[i * k][j * k] = true
                       k++
                   }
                }
            }
        }
        println("  largest number of items = $maxSize")
        println("  fraction(s) with this number : $maxSizeFracs")
        val md = maxDen.toString()
        print("  largest denominator = ${md.length} digits, ")
        println("${md.take(20)}...${md.takeLast(20)}")
        println("  fraction(s) with this denominator : $maxDenFracs")
    }
}


emirps: function [upto][
    result: new []
    loop range .step: 2 11 upto 'x [
        if prime? x [
            reversed: to :integer reverse to :string x
            if x <> reversed [
                if prime? reversed ->
                    'result ++ x
            ]
        ]
    ]
    return result
]

lst: emirps 1000000

print "The first 20 emirps:"
print first.n: 20 lst

print ""
print "Emirps between 7700 and 8000:"
print select lst 'x -> and? x > 7700 x < 8000

print ""
print "The 10000th emirp:"
print lst\9999


SetBatchLines, -1
p := 1
Loop, 20 {
	p := NextEmirp(p)
	a .= p " "
}
p := 7700
Loop {
	p := NextEmirp(p)
	if (p > 8000)
		break
	b .= p " "
}
p :=1
Loop, 10000
	p := NextEmirp(p)
MsgBox, % "First twenty emirps: " a
	. "`nEmirps between 7,700 and 8,000: " b
	. "`n10,000th emirp: " p

IsPrime(n) {
	if (n < 2)
		return, 0
	else if (n < 4)
		return, 1
	else if (!Mod(n, 2))
		return, 0
	else if (n < 9)
		return 1
	else if (!Mod(n, 3))
		return, 0
	else {
		r := Floor(Sqrt(n))
		f := 5
		while (f <= r) {
			if (!Mod(n, f))
				return, 0
			if (!Mod(n, (f + 2)))
				return, 0
			f += 6
		}
		return, 1
	}
}

NextEmirp(n) {
	Loop
		if (IsPrime(++n)) {
			rev := Reverse(n)
			if (rev = n)
				continue
			if (IsPrime(rev))
				return n
		}
}

Reverse(s) {
	Loop, Parse, s
		r := A_LoopField r
	return r
}


frac[n_] /; IntegerQ[1/n] := frac[n] = {n};
frac[n_] :=
  frac[n] =
   With[{p = Numerator[n], q = Denominator[n]},
    Prepend[frac[Mod[-q, p]/(q Ceiling[1/n])], 1/Ceiling[1/n]]];
disp[f_] :=
  StringRiffle[
    SequenceCases[f,
     l : {_, 1 ...} :>
      If[Length[l] == 1 && l[[1]] < 1, ToString[l[[1]], InputForm],
       "[" <> ToString[Length[l]] <> "]"]], " + "] <> " = " <>
   ToString[Numerator[Total[f]]] <> "/" <>
   ToString[Denominator[Total[f]]];
Print[disp[frac[43/48]]];
Print[disp[frac[5/121]]];
Print[disp[frac[2014/59]]];
fracs = Flatten[Table[frac[p/q], {q, 99}, {p, q}], 1];
Print[disp[MaximalBy[fracs, [email protected]*Union][[1]]]];
Print[disp[MaximalBy[fracs, [email protected]*Last][[1]]]];
fracs = Flatten[Table[frac[p/q], {q, 999}, {p, q}], 1];
Print[disp[MaximalBy[fracs, [email protected]*Union][[1]]]];
Print[disp[MaximalBy[fracs, [email protected]*Last][[1]]]];


'Egyptian fractions - 26/07/2018
  xx=2014
  yy=59
  x=xx
  y=yy
  If x>=y Then
    q=Math.Floor(x/y)
    tt="+("+q+")"
    x=Math.Remainder(x,y)
  EndIf
  If x<>0 Then
    While x<>1
      'i=modulo(-y,x)
      u=-y
      v=x
      modulo()
      i=ret
      k=Math.Ceiling(y/x)
      m=m+1
      tt=tt+"+1/"+k
      j=y*k
      If i=1 Then
        tt=tt+"+1/"+j
      EndIf
      'n=gcd(i,j)
      x=i
      y=j
      gcd()
      n=ret
      x=i/n
      y=j/n
    EndWhile
  EndIf
  TextWindow.WriteLine(xx+"/"+yy+"="+Text.GetSubTextToEnd(tt,2))

Sub modulo
  wr=Math.Remainder(u,v)
  While wr<0
    wr=wr+v
  EndWhile
  ret=wr
EndSub

Sub gcd
  wx=i
  wy=j
  wr=1
  While wr<>0
    wr=Math.Remainder(wx,wy)
    wx=wy
    wy=wr
  EndWhile
  ret=wx
EndSub


import strformat, strutils
import bignum

let
  Zero = newInt(0)
  One = newInt(1)

#---------------------------------------------------------------------------------------------------

proc toEgyptianrecursive(rat: Rat; fracs: seq[Rat]): seq[Rat] =

  if rat.isZero: return fracs

  let iquo = cdiv(rat.denom, rat.num)
  let rquo = newRat(1, iquo)
  result = fracs & rquo
  let num2 = cmod(-rat.denom, rat.num)
  if num2 < Zero:
    num2 += rat.num
  let denom2 = rat.denom * iquo
  let f = newRat(num2, denom2)
  if f.num == One:
    result.add(f)
  else:
    result = f.toEgyptianrecursive(result)

#---------------------------------------------------------------------------------------------------

proc toEgyptian(rat: Rat): seq[Rat] =

  if rat.num.isZero: return @[rat]

  if abs(rat.num) >= rat.denom:
    let iquo = rat.num div rat.denom
    let rquo = newRat(iquo, 1)
    let rrem = rat - rquo
    result = rrem.toEgyptianrecursive(@[rquo])
  else:
    result = rat.toEgyptianrecursive(@[])

#———————————————————————————————————————————————————————————————————————————————————————————————————

for frac in [newRat(43, 48), newRat(5, 121), newRat(2014, 59)]:
  let list = frac.toEgyptian()
  if list[0].denom == One:
    let first = fmt"[{list[0].num}]"
    let rest = list[1..^1].join(" + ")
    echo fmt"{frac} -> {first} + {rest}"
  else:
    let all = list.join(" + ")
    echo fmt"{frac} -> {all}"

for r in [98, 998]:
  if r == 98:
    echo "\nFor proper fractions with 1 or 2 digits:"
  else:
    echo "\nFor proper fractions with 1, 2 or 3 digits:"

  var maxSize = 0
  var maxSizeFracs: seq[Rat]
  var maxDen = Zero
  var maxDenFracs: seq[Rat]
  var sieve = newSeq[seq[bool]](r + 1)  # To eliminate duplicates.

  for item in sieve.mitems: item.setLen(r + 2)
  for i in 1..r:
    for j in (i + 1)..(r + 1):
      if sieve[i][j]: continue

      let f = newRat(i, j)
      let list = f.toEgyptian()
      let listSize = list.len
      if listSize > maxSize:
        maxSize = listSize
        maxSizeFracs.setLen(0)
        maxSizeFracs.add(f)
      elif listSize == maxSize:
        maxSizeFracs.add(f)

      let listDen = list[^1].denom()
      if listDen > maxDen:
        maxDen = listDen
        maxDenFracs.setLen(0)
        maxDenFracs.add(f)
      elif listDen == maxDen:
        maxDenFracs.add(f)

      if i < r div 2:
        var k = 2
        while j * k <= r + 1:
          sieve[i * k][j * k] = true
          inc k

  echo fmt"  largest number of items = {maxSize}"
  echo fmt"  fraction(s) with this number : {maxSizeFracs.join("", "")}"
  let md = $maxDen
  echo fmt"  largest denominator = {md.len} digits, {md[0..19]}...{md[^20..^1]}"
  echo fmt"  fraction(s) with this denominator : {maxDenFracs.join("", "")}"


function is_prime(n,	p)
{
        if (!(n%2) || !(n%3)) {
		return 0 }
        p = 1
        while(p*p < n)
                if (n%(p += 4) == 0 || n%(p += 2) == 0) {
                        return 0 }
        return 1
}

function reverse(n,	r)
{
	r = 0
        for (r = 0; int(n) != 0; n /= 10)
                r = r*10 + int(n%10);
        return r
}

function is_emirp(n,   r)
{
        r = reverse(n)
	return ((r != n) && is_prime(n) && is_prime(r)) ? 1 : 0
}

BEGIN {
	c = 0
	for (x = 11; c < 20; x += 2) {
		if (is_emirp(x)) {
			printf(" %i,", x); ++c }
	}
	printf("\n")
	for (x = 7701; x < 8000; x += 2) {
		if (is_emirp(x)) {
			printf(" %i,", x); ++c }
	}
	printf("\n")
	c = 0
	for (x = 11; ; x += 2)
                        if (is_emirp(x) && ++c == 10000) {
                                printf(" %i", x);
                                break;
                        }
	printf("\n")
}


efrac(f)=my(v=List());while(f,my(x=numerator(f),y=denominator(f));listput(v,ceil(y/x));f=(-y)%x/y/v[#v]);Vec(v);
show(f)=my(n=f\1,v=efrac(f-n)); print1(f" = ["n"; "v[1]); for(i=2,#v,print1(", "v[i])); print("]");
best(n)=my(denom,denomAt,term,termAt,v); for(a=1,n-1,for(b=a+1,n, v=efrac(a/b); if(#v>term, termAt=a/b; term=#v); if(v[#v]>denom, denomAt=a/b; denom=v[#v]))); print("Most terms is "termAt" with "term); print("Biggest denominator is "denomAt" with "denom)
apply(show, [43/48, 5/121, 2014/59]);
best(9)
best(99)
best(999)


use strict;
use warnings;
use bigint;
sub isEgyption{
    my $nr = int($_[0]);
    my $de = int($_[1]);
    if($nr == 0 or $de == 0){
	#Invalid input
	return;
    }
    if($de % $nr == 0){
	# They divide so print
	printf "1/" . int($de/$nr);
	return;
    }
    if($nr % $de == 0){
	# Invalid fraction
	printf $nr/$de;
	return;
    }
    if($nr > $de){
        printf int($nr/$de) . " + ";
	isEgyption($nr%$de, $de);
	return;
    }
    # Floor to find ceiling and print as fraction
    my $tmp = int($de/$nr) + 1;
    printf "1/" . $tmp . " + ";
    isEgyption($nr*$tmp-$de, $de*$tmp);
}

my $nrI = 2014;
my $deI = 59;
printf "\nEgyptian Fraction Representation of " . $nrI . "/" . $deI . " is: \n\n";
isEgyption($nrI,$deI);


#include <stdio.h>

typedef unsigned uint;
int is_prime(uint n)
{
        if (!(n%2) || !(n%3)) return 0;
        uint p = 1;
        while(p*p < n)
                if (n%(p += 4) == 0 || n%(p += 2) == 0)
                        return 0;
        return 1;
}

uint reverse(uint n)
{
        uint r;
        for (r = 0; n; n /= 10)
                r = r*10 + (n%10);
        return r;
}

int is_emirp(uint n)
{
        uint r = reverse(n);
        return r != n && is_prime(n) && is_prime(r);
}

int main(int argc, char **argv)
{
        uint x, c = 0;
        switch(argc) { // advanced args parsing
        case 1: for (x = 11; c < 20; x += 2)
                        if (is_emirp(x))
                                printf(" %u", x), ++c;
                break;

        case 2: for (x = 7701; x < 8000; x += 2)
                        if (is_emirp(x))
                                printf(" %u", x);
                break;

        default:
                for (x = 11; ; x += 2)
                        if (is_emirp(x) && ++c == 10000) {
                                printf("%u", x);
                                break;
                        }
        }

        putchar('\n');
        return 0;
}


with javascript_semantics
include mpfr.e
function egyptian(integer num, denom)
    mpz n = mpz_init(num),
        d = mpz_init(denom),
        t = mpz_init()
    sequence result = {}
    while mpz_cmp_si(n,0)!=0 do
        mpz_cdiv_q(t, d, n)
        result = append(result,"1/"&mpz_get_str(t))
        mpz_neg(d,d)
        mpz_mod(n,d,n)
        mpz_neg(d,d)
        mpz_mul(d,d,t)
    end while
    {n,d} = mpz_free({n,d})
    return result
end function

procedure efrac(integer num, denom)
    string fraction = sprintf("%d/%d",{num,denom}),
           prefix = ""
    if num>=denom then
        integer whole = floor(num/denom)
        num -= whole*denom
        prefix = sprintf("[%d] + ",whole)
    end if
    string e = join(egyptian(num, denom)," + ")
    printf(1,"%s -> %s%s\n",{fraction,prefix,e})
end procedure

efrac(43,48)
efrac(5,121)
efrac(2014,59)

integer maxt = 0,
        maxd = 0
string maxts = "",
       maxds = "",
       maxda = ""

for r=98 to 998 by 900 do   -- (iterates just twice!)
    sequence sieve = repeat(repeat(false,r+1),r) -- to eliminate duplicates
    for n=1 to r do
        for d=n+1 to r+1 do
            if sieve[n][d]=false then
                string term = sprintf("%d/%d",{n,d})
                sequence terms = egyptian(n,d)
                integer nterms = length(terms)
                if nterms>maxt then
                    maxt = nterms
                    maxts = term
                elsif nterms=maxt then
                    maxts &= ", " & term
                end if
                integer mlen = length(terms[$])-2
                if mlen>maxd then
                    maxd = mlen
                    maxds = term
                    maxda = terms[$]
                elsif mlen=maxd then
                    maxds &= ", " & term
                end if
                if n<r/2 then
                    for k=2 to 9999 do
                        if d*k > r+1 then exit end if
                        sieve[n*k][d*k] = true
                    end for
                end if
            end if
        end for
    end for
    printf(1,"\nfor proper fractions with 1 to %d digits\n",{length(sprint(r))})
    printf(1,"Largest number of terms is %d for %s\n",{maxt,maxts})
    maxda = maxda[3..$] -- (strip the "1/")
    maxda[6..-6]="..."  -- (show only first/last 5 digits)
    printf(1,"Largest size for denominator is %d digits (%s) for %s\n",{maxd,maxda,maxds})
end for


using static System.Console;
using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main() {
        const int limit = 1_000_000;
        WriteLine("First 20:");
        WriteLine(FindEmirpPrimes(limit).Take(20).Delimit());
        WriteLine();

        WriteLine("Between 7700 and 8000:");
        WriteLine(FindEmirpPrimes(limit).SkipWhile(p => p < 7700).TakeWhile(p => p < 8000).Delimit());
        WriteLine();

        WriteLine("10000th:");
        WriteLine(FindEmirpPrimes(limit).ElementAt(9999));
    }

    private static IEnumerable<int> FindEmirpPrimes(int limit)
    {
        var primes = Primes(limit).ToHashSet();

        foreach (int prime in primes) {
            int reverse = prime.Reverse();
            if (reverse != prime && primes.Contains(reverse)) yield return prime;
	}
    }

    private static IEnumerable<int> Primes(int bound) {
        if (bound < 2) yield break;
        yield return 2;

        BitArray composite = new BitArray((bound - 1) / 2);
        int limit = ((int)(Math.Sqrt(bound)) - 1) / 2;
        for (int i = 0; i < limit; i++) {
            if (composite[i]) continue;
	    int prime = 2 * i + 3;
	    yield return prime;

	    for (int j = (prime * prime - 2) / 2; j < composite.Count; j += prime)
	        composite[j] = true;
        }
	for (int i = limit; i < composite.Count; i++)
	    if (!composite[i]) yield return 2 * i + 3;
    }
}

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) => new HashSet<T>(source);

    private const string defaultSeparator = " ";
    public static string Delimit<T>(this IEnumerable<T> source, string separator = defaultSeparator) =>
        string.Join(separator ?? defaultSeparator, source);

    public static int Reverse(this int number)
    {
	if (number < 0) return -Reverse(-number);
	if (number < 10) return number;
	int reverse = 0;
	while (number > 0) {
	    reverse = reverse * 10 + number % 10;
	    number /= 10;
	}
	return reverse;
    }
}


count_digits(Number, Count):-
    atom_number(A, Number),
    atom_length(A, Count).

integer_to_atom(Number, Atom):-
    atom_number(A, Number),
    atom_length(A, Count),
    (Count =< 20 ->
        Atom = A
        ;
        sub_atom(A, 0, 10, _, A1),
        P is Count - 10,
        sub_atom(A, P, 10, _, A2),
        atom_concat(A1, '...', A3),
        atom_concat(A3, A2, Atom)
    ).

egyptian(0, _, []):- !.
egyptian(X, Y, [Z|E]):-
    Z is (Y + X - 1)//X,
    X1 is -Y mod X,
    Y1 is Y * Z,
    egyptian(X1, Y1, E).

print_egyptian([]):- !.
print_egyptian([N|List]):-
    integer_to_atom(N, A),
    write(1/A),
    (List = [] -> true; write(' + ')),
    print_egyptian(List).

print_egyptian(X, Y):-
    writef('Egyptian fraction for %t/%t: ', [X, Y]),
    (X > Y ->
        N is X//Y,
        writef('[%t] ', [N]),
        X1 is X mod Y
        ;
        X1 = X
    ),
    egyptian(X1, Y, E),
    print_egyptian(E),
    nl.

max_terms_and_denominator1(D, Max_terms, Max_denom, Max_terms1, Max_denom1):-
    max_terms_and_denominator1(D, 1, Max_terms, Max_denom, Max_terms1, Max_denom1).

max_terms_and_denominator1(D, D, Max_terms, Max_denom, Max_terms, Max_denom):- !.
max_terms_and_denominator1(D, N, Max_terms, Max_denom, Max_terms1, Max_denom1):-
    Max_terms1 = f(_, _, _, Len1),
    Max_denom1 = f(_, _, _, Max1),
    egyptian(N, D, E),
    length(E, Len),
    last(E, Max),
    (Len > Len1 ->
        Max_terms2 = f(N, D, E, Len)
        ;
        Max_terms2 = Max_terms1
    ),
    (Max > Max1 ->
        Max_denom2 = f(N, D, E, Max)
        ;
        Max_denom2 = Max_denom1
    ),
    N1 is N + 1,
    max_terms_and_denominator1(D, N1, Max_terms, Max_denom, Max_terms2, Max_denom2).

max_terms_and_denominator(N, Max_terms, Max_denom):-
    max_terms_and_denominator(N, 1, Max_terms, Max_denom, f(0, 0, [], 0),
                              f(0, 0, [], 0)).

max_terms_and_denominator(N, N, Max_terms, Max_denom, Max_terms, Max_denom):-!.
max_terms_and_denominator(N, N1, Max_terms, Max_denom, Max_terms1, Max_denom1):-
    max_terms_and_denominator1(N1, Max_terms2, Max_denom2, Max_terms1, Max_denom1),
    N2 is N1 + 1,
    max_terms_and_denominator(N, N2, Max_terms, Max_denom, Max_terms2, Max_denom2).

show_max_terms_and_denominator(N):-
    writef('Proper fractions with most terms and largest denominator, limit = %t:\n', [N]),
    max_terms_and_denominator(N, f(N_max_terms, D_max_terms, E_max_terms, Len),
                              f(N_max_denom, D_max_denom, E_max_denom, Max)),
    writef('Most terms (%t): %t/%t = ', [Len, N_max_terms, D_max_terms]),
    print_egyptian(E_max_terms),
    nl,
    count_digits(Max, Digits),
    writef('Largest denominator (%t digits): %t/%t = ', [Digits, N_max_denom, D_max_denom]),
    print_egyptian(E_max_denom),
    nl.

main:-
    print_egyptian(43, 48),
    print_egyptian(5, 121),
    print_egyptian(2014, 59),
    nl,
    show_max_terms_and_denominator(100),
    nl,
    show_max_terms_and_denominator(1000).


#include <vector>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <cmath>

bool isPrime ( int number ) {
   if ( number <= 1 )
      return false ;
   if ( number == 2 )
      return true ;
   for ( int i = 2 ; i <= std::sqrt( number ) ; i++ ) {
      if ( number % i == 0 )
	 return false ;
   }
   return true ;
}

int reverseNumber ( int n ) {
   std::ostringstream oss ;
   oss << n ;
   std::string numberstring ( oss.str( ) ) ;
   std::reverse ( numberstring.begin( ) , numberstring.end( ) ) ;
   return std::stoi ( numberstring ) ;
}

bool isEmirp ( int n ) {
   return isPrime ( n ) && isPrime ( reverseNumber ( n ) )
      && n != reverseNumber ( n ) ;
}

int main( ) {
   std::vector<int> emirps ;
   int i = 1 ;
   while ( emirps.size( ) < 20 ) {
      if ( isEmirp( i ) ) {
         emirps.push_back( i ) ;
      }
      i++ ;
   }
   std::cout << "The first 20 emirps:\n" ;
   for ( int i : emirps )
      std::cout << i << " " ;
   std::cout << '\n' ;
   int newstart = 7700 ;
   while ( newstart < 8001 ) {
      if ( isEmirp ( newstart ) )
	std::cout << newstart << '\n' ;
      newstart++ ;
   }
   while ( emirps.size( ) < 10000 ) {
      if ( isEmirp ( i ) ) {
	 emirps.push_back( i ) ;
      }
      i++ ;
   }
   std::cout << "the 10000th emirp is " << emirps[9999] << " !\n" ;

   return 0 ;
}


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)
        #assert sum((f[0] if type(f) is list else f) for f in e) == fr, 'Whoops!'
        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:]))


(defn emirp? [v]
  (let [a (biginteger v)
        b (biginteger (clojure.string/reverse (str v)))]
    (and (not= a b)
         (.isProbablePrime a 16)
         (.isProbablePrime b 16))))

; Generate the output
(println "first20:    " (clojure.string/join " " (take 20 (filter emirp? (iterate inc 0)))))
(println "7700-8000:  " (clojure.string/join " " (filter emirp? (range 7700 8000))))
(println "10,000:     " (nth (filter emirp? (iterate inc 0)) 9999))


(defun primep (n)
  "Is N prime?"
  (and (> n 1)
       (or (= n 2) (oddp n))
       (loop for i from 3 to (isqrt n) by 2
	  never (zerop (rem n i)))))

(defun reverse-digits (n)
  (labels ((next (n v)
             (if (zerop n) v
                 (multiple-value-bind (q r)
                     (truncate n 10)
                   (next q (+ (* v 10) r))))))
    (next n 0)))

(defun emirp (&key (count nil) (start 10) (end nil) (print-all nil))
  (do* ((n start (1+ n))
        (c count) )
       ((or (and count (<= c 0)) (and end (>= n end))))
    (when (and (primep n) (not (= n (reverse-digits n))) (primep (reverse-digits n)))
      (when print-all (format t "~a " n))
      (when count (decf c)) )))

(progn
  (format t "First 20 emirps: ") (emirp :count 20 :print-all t)
  (format t "~%Emirps between 7700 and 8000: ") (emirp :start 7700 :end 8000 :print-all t)
  (format t "~%The 10,000'th emirp: ") (emirp :count 10000 :print-all nil) )


#lang racket
(define (real->egyptian-list R)
  (define (inr r rv)
    (match* ((exact-floor r) (numerator r) (denominator r))
      [(0 0 1) (reverse rv)]
      [(0 1 d) (reverse (cons (/ d) rv))]
      [(0 x y) (let ((^y/x (exact-ceiling (/ y x))))
                 (inr (/ (modulo (- y) x) (* y ^y/x)) (cons (/ ^y/x) rv)))]
      [(flr _ _) (inr (- r flr) (cons flr rv))]))
  (inr R null))

(define (real->egyptian-string f)
  (define e.f.-list (real->egyptian-list f))
  (define fmt-part
    (match-lambda
      [(? integer? (app number->string s)) s]
      [(app (compose number->string /) s) (format "/~a"s)]))
  (string-join (map fmt-part e.f.-list) " + "))

(define (stat-egyptian-fractions max-b+1)
  (define-values (max-l max-l-f max-d max-d-f)
    (for*/fold ((max-l 0) (max-l-f #f) (max-d 0) (max-d-f #f))
               ((b (in-range 1 max-b+1)) (a (in-range 1 b)) #:when (= 1 (gcd a b)))
      (define f (/ a b))
      (define e.f (real->egyptian-list (/ a b)))
      (define l (length e.f))
      (define d (denominator (last e.f)))
      (values (max max-l l) (if (> l max-l) f max-l-f)
              (max max-d d) (if (> d max-d) f max-d-f))))
  (printf #<<EOS
max #terms: ~a has ~a
[~.a]
max denominator: ~a has ~a
[~.a]

EOS
          max-l-f max-l (real->egyptian-string max-l-f)
          max-d-f max-d (real->egyptian-string max-d-f)))

(displayln (real->egyptian-string 43/48))
(displayln (real->egyptian-string 5/121))
(displayln (real->egyptian-string 2014/59))
(newline)
(stat-egyptian-fractions 100)
(newline)
(stat-egyptian-fractions 1000)

(module+ test (require tests/eli-tester)
  (test (real->egyptian-list 43/48) => '(1/2 1/3 1/16)))


role Egyptian {
    method gist {
	join ' + ',
	    ("[{self.floor}]" if self.abs >= 1),
	    map {"1/$_"}, self.denominators;
    }
    method denominators {
	my ($x, $y) = self.nude;
	$x %= $y;
	my @denom = gather ($x, $y) = -$y % $x, $y * take ($y / $x).ceiling
	    while $x;
    }
}

say .nude.join('/'), " = ", $_ but Egyptian for 43/48, 5/121, 2014/59;

my @sample = map { $_ => .denominators },
    grep * < 1,
        map {$_ but Egyptian},
            (2 .. 99 X/ 2 .. 99);

say .key.nude.join("/"),
    " has max denominator, namely ",
    .value.max
        given max :by(*.value.max), @sample;

say .key.nude.join("/"),
    " has max number of denominators, namely ",
    .value.elems
        given max :by(*.value.elems), @sample;


bool isEmirp(uint n) pure nothrow @nogc {
    bool isPrime(in uint n) pure nothrow @nogc {
        if (n == 2 || n == 3)
            return true;
        else if (n < 2 || n % 2 == 0 || n % 3 == 0)
            return false;
        for (uint div = 5, inc = 2; div ^^ 2 <= n;
             div += inc, inc = 6 - inc)
            if (n % div == 0)
                return false;

        return true;
    }

    uint reverse(uint n) pure nothrow @nogc {
        uint r;
        for (r = 0; n; n /= 10)
            r = r * 10 + (n % 10);
        return r;
    }

    immutable r = reverse(n);
    return r != n && isPrime(n) && isPrime(r);
}

void main() {
    import std.stdio, std.algorithm, std.range;

    auto uints = uint.max.iota;
    writeln("First 20:\n", uints.filter!isEmirp.take(20));
    writeln("Between 7700 and 8000:\n",
            iota(7_700, 8_001).filter!isEmirp);
    writeln("10000th: ", uints.filter!isEmirp.drop(9_999).front);
}


/*REXX program converts a fraction (can be improper) to an Egyptian fraction. */
parse arg fract '' -1 t;  z=$egyptF(fract)  /*compute the Egyptian fraction.  */
if t\==.  then say  fract   ' ───► '   z    /*show Egyptian fraction from C.L.*/
return z                                    /*stick a fork in it,  we're done.*/
/*────────────────────────────────$EGYPTF subroutine──────────────────────────*/
$egyptF: parse arg z 1 zn '/' zd,,$;   if zd==''  then zd=1   /*whole number ?*/
if z=''               then call erx  "no fraction was specified."
if zd==0              then call erx  "denominator can't be zero:"       zd
if zn==0              then call erx  "numerator can't be zero:"         zn
if zd<0 | zn<0        then call erx  "fraction can't be negative"       z
if \datatype(zn,'W')  then call erx  "numerator must be an integer:"    zn
if \datatype(zd,'W')  then call erx  "denominator must be an integer:"  zd
_=zn%zd                                /*check if it's an improper fraction.  */
if _>=1  then do                       /*if improper fraction, then append it.*/
              $='['_"]"                /*append the whole # part of fraction. */
              zn=zn-_*zd               /*now, just use the proper fraction.   */
              if zn==0  then return $  /*Is there no fraction? Then we're done*/
              end
if zd//zn==0  then do;  zd=zd%zn;  zn=1;  end
  do  forever
  if zn==1 & datatype(zd,'W')  then return $ "1/"zd   /*append Egyptian fract.*/
  nd=zd%zn+1;      $=$ '1/'nd          /*add unity to integer fraction, append*/
  z=$fractSub(zn'/'zd,  "-",  1'/'nd)  /*go and subtract the two fractions.   */
  parse var z zn '/' zd                /*extract the numerator and denominator*/
  L=2*max(length(zn),length(zd))       /*calculate if need more decimal digits*/
  if L>=digits()  then numeric digits L+L  /*yes, then bump the decimal digits*/
  end   /*forever*/                    /* [↑]  the DO forever ends when zn==1.*/
/*────────────────────────────────$FRACTSUB subroutine────────────────────────*/
$fractSub: procedure;  parse arg z.1,,z.2 1 zz.2;  arg ,op
                             do j=1  for 2;    z.j=translate(z.j,'/',"_");   end
if z.1==''  then z.1=(op\=="+" & op\=='-')     /*unary +,-     first fraction.*/
if z.2==''  then z.2=(op\=="+" & op\=='-')     /*unary +.-    second fraction.*/
  do j=1  for 2                                /*process both of the fractions*/
  if pos('/',z.j)==0     then z.j=z.j"/1";     parse var  z.j  n.j  '/'  d.j
  if \datatype(n.j,'N')  then call erx  "numerator isn't an integer:"    n.j
  if \datatype(d.j,'N')  then call erx  "denominator isn't an integer:"  d.j
  n.j=n.j/1;   d.j=d.j/1                    /*normalize numerator/denominator.*/

      do  while \datatype(n.j,'W');  n.j=n.j*10/1;  d.j=d.j*10/1;  end /*while*/
                                            /* [↑]  normalize both numbers.   */
  if d.j=0  then call erx  "denominator can't be zero:"   z.j
  g=gcd(n.j,d.j);   if g=0  then iterate;     n.j=n.j/g;         d.j=d.j/g
  end    /*j*/
l=lcm(d.1 d.2);             do j=1  for 2;  n.j=l*n.j/d.j;  d.j=l;  end  /*j*/
if op=='-'  then n.2=-n.2
t=n.1+n.2;       u=l;                  if t==0  then return 0
g=gcd(t,u);      t=t/g;     u=u/g;     if u==1  then return t
                                                     return t'/'u
/*─────────────────────────────general 1─line subs────────────────────────────*/
erx:  say;  say '***error!***' arg(1);       say;          exit 13
gcd:procedure;$=;do i=1 for arg();$=$ arg(i);end;parse var $ x z .;if x=0 then x=z;x=abs(x);do j=2 to words($);y=abs(word($,j));if y=0 then iterate;do until _==0;_=x//y;x=y;y=_;end;end;return x
lcm:procedure;y=;do j=1 for arg();y=y arg(j);end;x=word(y,1);do k=2 to words(y);!=abs(word(y,k));if !=0 then return 0;x=x*!/gcd(x,!);end;return x
p:  return word(arg(1),1)


defmodule Emirp do
  defp prime?(2), do: true
  defp prime?(n) when n<2 or rem(n,2)==0, do: false
  defp prime?(n), do: prime?(n,3)

  defp prime?(n,k) when n<k*k, do: true
  defp prime?(n,k) when rem(n,k)==0, do: false
  defp prime?(n,k), do: prime?(n,k+2)

  def emirp?(n) do
    if prime?(n) do
      reverse = to_string(n) |> String.reverse |> String.to_integer
      n != reverse and prime?(reverse)
    end
  end

  def task do
    emirps = Stream.iterate(1, &(&1+1)) |> Stream.filter(&emirp?/1)
    first = Enum.take(emirps,20) |> Enum.join(" ")
    IO.puts "First 20 emirps: #{first}"
    between = Enum.reduce_while(emirps, [], fn x,acc ->
      cond do
        x < 7700        -> {:cont, acc}
        x in 7700..8000 -> {:cont, [x | acc]}
        true            -> {:halt, Enum.reverse(acc)}
      end
    end) |> Enum.join(" ")
    IO.puts "Emirps between 7,700 and 8,000: #{between}"
    IO.puts "10,000th emirp: #{Enum.at(emirps, 9999)}"
  end
end

Emirp.task


// Generate emirps. Nigel Galloway: November 19th., 2017
let emirp =
  let rec fN n g = match n with |0->g |_->fN (n/10) (g*10+n%10)
  let     fG n g = n<>g && isPrime g
  primes32() |> Seq.filter (fun n -> fG n (fN n 0))


def ef(fr)
  ans = []
  if fr >= 1
    return [[fr.to_i], Rational(0, 1)]  if fr.denominator == 1
    intfr = fr.to_i
    ans, fr = [intfr], fr - intfr
  end
  x, y = fr.numerator, fr.denominator
  while x != 1
    ans << Rational(1, (1/fr).ceil)
    fr = Rational(-y % x, y * (1/fr).ceil)
    x, y = fr.numerator, fr.denominator
  end
  ans << fr
end

for fr in [Rational(43, 48), Rational(5, 121), Rational(2014, 59)]
  puts '%s => %s' % [fr, ef(fr).join(' + ')]
end

lenmax = denommax = [0]
for b in 2..99
  for a in 1...b
    fr = Rational(a,b)
    e = ef(fr)
    elen, edenom = e.length, e[-1].denominator
    lenmax = [elen, fr] if elen > lenmax[0]
    denommax = [edenom, fr] if edenom > denommax[0]
  end
end
puts 'Term max is %s with %i terms' % [lenmax[1], lenmax[0]]
dstr = denommax[0].to_s
puts 'Denominator max is %s with %i digits' % [denommax[1], dstr.size], dstr


USING: io kernel lists lists.lazy math.extras math.parser
    math.primes sequences ;
FROM: prettyprint => . pprint ;
IN: rosetta-code.emirp

: rev ( n -- n' )
    number>string reverse string>number ;

: emirp? ( n -- ? )
    dup rev [ = not ] [ [ prime? ] [email protected] ] 2bi and and ;

: nemirps ( n -- seq )
    0 lfrom [ emirp? ] lfilter ltake list>array ;

: print-seq ( seq -- )
    [ pprint bl ] each nl ;

: part1 ( -- )
    "First 20 emirps:" print 20 nemirps print-seq ;

: part2 ( -- )
    "Emirps between 7700 and 8000:" print
    7700 ... 8000 [ emirp? ] filter print-seq ;

: part3 ( -- )
    "10,000th emirp:" print 10,000 nemirps last . ;

: main ( -- )
    part1 nl part2 nl part3 ;

MAIN: main


#! /usr/bin/gforth-fast

: reverse  ( n -- n )
    0 swap
    begin
        10 /mod >r  swap 10 * +
    r> dup 0= until drop ;

: 2^  1 swap lshift ;

create 235-wheel 6 c, 4 c, 2 c, 4 c, 2 c, 4 c, 6 c, 2 c,
    does> swap 7 and + [email protected] ;

0  1 2constant init-235    \ roll 235 wheel at position 1
2 11 2constant emirp-start \ starting position to roll wheel for emirp search.

: next-235   over 235-wheel + swap 1+ swap ;

\ check that n is prime excepting multiples of 2, 3, 5.
: sq  dup * ;
: wheel-prime? ( n -- f )
    >r init-235 begin
        next-235
        dup sq [email protected] >    if  rdrop 2drop true  exit  then
        [email protected] over mod 0= if  rdrop 2drop false exit  then
    again ;

: prime? ( n -- f )
    dup 2 <
    if drop false
    else
        dup 1 and 0=
        if 2 =
        else dup 3 mod 0=
            if 3 =
            else dup 5 mod 0=
                if 5 =
                else wheel-prime?
                then
            then
        then
    then ;

: emirp? ( n -- f )
    dup reverse 2dup <>
    swap prime? and
    swap wheel-prime? and ;

: next-emirp ( m n -- m' n' )
    begin
        next-235
    dup emirp? until ;

: task1
    cr ." The first 20 emirps are: " 0 { count }
    emirp-start begin
        next-emirp dup .
        count 1+ dup to count
    20 = until 2drop ;

: task2
    cr ." emirps between 7700 and 8000: "
    emirp-start begin
        next-emirp dup 7700 8000 within if dup . then
    dup 8000 > until 2drop ;

: task3
    cr ." The 10,000th emirp is " 0 { count }
    emirp-start begin
        next-emirp
        count 1+ dup to count
    10000 = until nip . ;

task1 task2 task3
cr bye


      MODULE BAG	!A mixed assortment.
       INTEGER MSG	!I/O unit number to share about.
       INTEGER PF16LIMIT,PF32LIMIT,NP			!Know that P(3512) = 32749, the last within two's complement 16-bit integers.
       PARAMETER (PF16LIMIT = 3512, PF32LIMIT = 4793)	!32749² = 1,072,497,001; the integer limit is 2,147,483,647 in 32-bit integers.
       INTEGER*2 PRIME16(PF16LIMIT)			!P(4792) =  46337, next is 46349 and 46337² = 2,147,117,569.
       INTEGER*4 PRIME32(PF16LIMIT + 1:PF32LIMIT)	!Let the compiler track the offsets.
       DATA NP,PRIME16(1),PRIME16(2)/2,2,3/	!But, start off with this. Note that Prime(NP) is odd...
       INTEGER NGP,NNP,NIP	!Invocation counts.
       DATA NGP,NNP,NIP/3*0/	!Starting at zero.
       CONTAINS		!Some co-operating routines.
        RECURSIVE INTEGER FUNCTION GETPRIME(I)	!They are numbered. As if in an array Prime(i).
Chooses from amongst two arrays, of sizes known from previous work.
         INTEGER I		!The desired index.
         INTEGER P		!A potential prime.
         INTEGER MP		!Counts beyond NP.
          NGP = NGP + 1		!Another try.
          IF (I.LE.0) THEN	!A silly question?
            GETPRIME = -666		!This should cause trouble!
          ELSE IF (I.LE.NP) THEN	!I have a little list.
            IF (I.LE.PF16LIMIT) THEN		!Well actually, two little lists.
              GETPRIME = PRIME16(I)		!So, direct access from this.
             ELSE				!Or, for the larger numbers,
              GETPRIME = PRIME32(I)		!This.
            END IF			!So much for previous effort.
          ELSE IF (I.LE.PF32LIMIT) THEN	!My list may not yet be completely filled.
            MP = NP			!This is the last stashed so far.
            P = GETPRIME(NP)		!I'll ask me to figure out where this is stashed.
   10       P = NEXTPRIME(P)		!Go for the next one along.
            MP = MP + 1			!Advance my count.
            IF (MP.LT.I) GO TO 10	!Are we there yet?
            GETPRIME = P		!Yep.
           ELSE			!But, my list may be too short.
            WRITE (MSG,*) "Hic!",I	!So, give an indication.
            STOP "Too far..."		!And quit.
          END IF		!For factoring 32-bit, need only 4792 elements.
        END FUNCTION GETPRIME	!This is probably faster than reading from a monster disc file.

        SUBROUTINE STASHPRIME(P)	!Saves a value in the stash.
         INTEGER P	!The prime to be stashed.
          NP = NP + 1		!Count another in.
          IF (NP.LE.PF16LIMIT) THEN	!But, where to?
            PRIME16(NP) = P			!The short list.
          ELSE IF (NP.LE.PF32LIMIT) THEN!Or,
            PRIME32(NP) = P			!The long list (which is shorter)
          ELSE				!Or,
            STOP "Stash overflow!"		!Oh dear.
          END IF			!It is stashed.
        END SUBROUTINE STASHPRIME	!The checking should be redundant.

        INTEGER FUNCTION FINDPRIME(IT)	!Via binary search.
         INTEGER IT	!The value to be found.
         INTEGER L,R,P	!Assistants.
          L = 0		!This is the *exclusive bounds* version.
          R = NP + 1	!Thus, L = first - 1; R = Last + 1.
    1     P = (R - L)/2		!Probe offset.
          IF (P.LE.0) THEN	!No span?
            FINDPRIME = -L		!Not found. IT follows Prime(L).
            RETURN			!Escape.
          END IF		!But otherwise,
          P = P + L		!Convert to an index into array PRIME, manifested via GETPRIME.
          IF (IT - GETPRIME(P)) 2,4,3	!Compare... Three way result.
    2     R = P; GO TO 1	!IT < PRIME(P): move R back.
    3     L = P; GO TO 1	!PRIME(P) < IT: move L forward.
    4     FINDPRIME = P		!PRIME(P) = IT: Found here!
        END FUNCTION FINDPRIME	!Simple and fast.

        RECURSIVE INTEGER FUNCTION NEXTPRIME(P)	!Some effort may ensue.
Checks the stash in PRIME in the hope of finding the next prime directly, otherwise advances from P.
Collates a stash of primes in PRIME16 and PRIME32, advancing NP from 2 to PF32LIMIT as it goes.
         INTEGER P	!Not necessarily itself a prime number.
         INTEGER PI	!A possibly prime increment.
         INTEGER IT	!A finger.
          NNP = NNP + 1	!Another try
          IF (P.LE.1) THEN	!Dodge annoying effects.	Otherwise, FINDPRIME(P) would be zero.
            PI = 2		!The first prime is known.	Because P precedes Prime(1).
           ELSE			!The first stashed value is two.
            IT = (ABS(FINDPRIME(P)))	!The stash is ordered, and P = 2 will be found at 1.
            IF (IT.LT.NP) THEN		!Before my last-known prime? FINDPRIME(4) = -2 as it follows Prime(NP=2).
              PI = GETPRIME(IT + 1)	!Yes, so I know the next along already.
             ELSE	!Otherwise, it is past Prime(NP). and IT = NP thanks to the ABS.
              IF (NP.LT.PF32LIMIT) THEN	!If my stash is not yet filled,
                PI = GETPRIME(IT)	!I want to start with its last entry, known to be an odd number.
               ELSE			!So that I can stash each next prime along the way.
                PI = P			!Otherwise, start with P.
                IF (MOD(PI,2).EQ.0) PI = PI - 1	!And some suspicion.
              END IF			!So  much for a starting position.
              DO WHILE (PI.LE.P)	!Perhaps I must go further.
   11           PI = PI + 2			!Advance to a possibility.
                IF (.NOT.ISPRIME(PI)) GO TO 11	!Discard it?
                IF (IT.EQ.NP .AND. IT.LT.PF32LIMIT) THEN	!Am I one further on from NP?
                  CALL STASHPRIME(PI)		!Yes, and there is space to stash it.
                  IT = IT + 1			!Ready for the next one along, if it comes.
                END IF			!All are candidates for my stash.
              END DO		!Perhaps this prime will be big enough.
            END IF		!It may be a long way past PRIME(NP).
          END IF		!And I may have filled my stash along the way.
          NEXTPRIME = PI	!Take that.
        END FUNCTION NEXTPRIME	!Messy.

        RECURSIVE LOGICAL FUNCTION ISPRIME(N)	!Checks an arbitrary number, though limited by INTEGER size.
Crunches up to SQRT(N), and at worst needs to be able to reach Prime(4793) = 46349; greater than SQRT(2147483647) = 46340·95...
         INTEGER N	!The number.
         INTEGER I,F,Q	!Assistants.
          NIP = NIP + 1	!Another try.
          IF (N.LT.2) THEN	!Dodge annoyances.
            ISPRIME = .FALSE.	!Such as N = 1, and the first F being 2.
          ELSE			!Otherwise, some effort.
            ISPRIME = .FALSE.	!The usual result.
            I = 1		!Start at the start with PRIME(1).
   10       F = GETPRIME(I)	!Thus, no special case with F = 2.
            Q = N/F		!So, how many times? (Truncation, remember)
            IF (Q .GE. F) THEN	!Q < F means F² > N.
              IF (Q*F .EQ. N) RETURN	!A factor is found!
              I = I + 1		!Very well.
              GO TO 10		!Try the next possible factor.
            END IF		!And if we get through all that,
            ISPRIME = .TRUE.	!It is a prime number.
          END IF		!And we're done.
        END FUNCTION ISPRIME	!After a lot of divisions.

        INTEGER FUNCTION ESREVER(IT,BASE)	!Reversed digits.
         INTEGER IT	!The number to be reversed. Presumably positive.
         INTEGER BASE	!For the numerology.
         INTEGER N,R	!Assistants.
          IF (BASE.LE.1) STOP "Base 2 at least!"	!Ah, distrust.
          N = IT	!A copy I can damage.
          R = 0		!Here we go.
          DO WHILE(N.GT.0)	!A digit remains?
            R = R*BASE + MOD(N,BASE)	!Yes. Grab the low-order digit of N.
            N = N/BASE			!And reduce N by another power of BASE.
          END DO		!Test afresh.
          ESREVER = R		!That's it.
        END FUNCTION ESREVER	!Easy enough.

        SUBROUTINE EMIRP(BASE,N1,N2,I1,I2)	!Two-part interface.
         INTEGER BASE	!Avoid decimalist chauvinism.
         INTEGER N1,N2	!Count span to show those found.
         INTEGER I1,I2	!Search span.
         INTEGER N	!Counter.
         INTEGER P,R	!Assistants.
          WRITE (MSG,1) N1,N2,BASE,I1,I2	!Declare the purpose.
    1     FORMAT ("Show the first ",I0," to ",I0,	!So as to encompass
     &     " emirP numbers (base ",I0,") between ",I0," and ",I0)	!The specified options.
          N = 0		!None found so far.
          P = I1 - 1	!Syncopation. The starting position might itself be a prime number.
Chase another emirP.
   10     P = NEXTPRIME(P)		!I want the next prime.
          IF (P.LT.I1) GO TO 10		!Up to the starting mark yet?
          IF (P.GT.I2) GO TO 900	!Past the finishing mark?
          R = ESREVER(P,BASE)		!Righto, a candidate.
          IF (P .EQ. R) GO TO 10	!Palindromes are rejected.
          IF (.NOT.ISPRIME(R)) GO TO 10	!As are non-primes.
          N = N + 1			!Aha, a success!
c          if (mod(n,100) .eq. 0) then
c            write (6,66) N,P,R,NP,NGP,NNP,NIP
c   66       format ("N=",I5,",p=",I6,",R=",I6,",NP=",I6,3I12)
c          end if
          IF (N.GE.N1) WRITE (6,*) P,R	!Are we within the count span?
          IF (N.LT.N2) GO TO 10		!Past the end?
Closedown.
  900     WRITE (MSG,901) NP,GETPRIME(NP)	!Might be of interest.
  901     FORMAT ("Stashed up to Prime(",I0,") = ",I0,/)
        END SUBROUTINE EMIRP	!Well, that was odd.
      END MODULE BAG	!Mixed.

      PROGRAM POKE	!Now put it all to the test.
      USE BAG		!With ease.
      MSG = 6		!Standard output.

      CALL EMIRP(10,    1,   20,   1,   1000)	!These parameters
      CALL EMIRP(10,    1,   28,7700,   8000)	!Meet the specifiction
      CALL EMIRP(10,10000,10000,   1,1000000)	!Of three separate invocations.

      END	!Whee!


use num_bigint::BigInt;
use num_integer::Integer;
use num_traits::{One, Zero};
use std::fmt;

#[derive(Debug, Clone, PartialEq, PartialOrd)]
struct Rational {
    nominator: BigInt,
    denominator: BigInt,
}

impl Rational {
    fn new(n: &BigInt, d: &BigInt) -> Rational {
        assert!(!d.is_zero(), "denominator cannot be 0");
        // simplify if possible
        let c = n.gcd(d);
        Rational {
            nominator: n / &c,
            denominator: d / &c,
        }
    }

    fn is_proper(&self) -> bool {
        self.nominator < self.denominator
    }
    fn to_egyptian(&self) -> Vec<Rational> {
        let mut frac: Vec<Rational> = Vec::new();

        let mut current: Rational;
        if !self.is_proper() {
            // input is grater than 1
            // store the integer part
            frac.push(Rational::new(
                &self.nominator.div_floor(&self.denominator),
                &One::one(),
            ));

            // calculate the remainder
            current = Rational::new(
                &self.nominator.mod_floor(&self.denominator),
                &self.denominator,
            );
        } else {
            current = self.clone();
        }

        while !current.nominator.is_one() {
            let div = current.denominator.div_ceil(&current.nominator);

            // store the term
            frac.push(Rational::new(&One::one(), &div));

            current = Rational::new(
                &(-&current.denominator).mod_floor(&current.nominator),
                match current.denominator.checked_mul(&div).as_ref() {
                    Some(r) => r,
                    _ => break,
                },
            );
        }

        frac.push(current);
        frac
    }
}

impl fmt::Display for Rational {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.denominator.is_one() {
            // for integers only display the integer part
            write!(f, "{}", self.nominator)
        } else {
            write!(f, "{}/{}", self.nominator, self.denominator)
        }
    }
}

fn rational_vec_to_string(vec: Vec<Rational>) -> String {
    let mut p = vec
        .iter()
        .fold(String::new(), |acc, num| (acc + &num.to_string() + ", "));

    if p.len() > 1 {
        p.truncate(p.len() - 2);
    }
    format!("[{}]", p)
}

fn run_max_searches(x: usize) {
    // generate all proper fractions with 2 digits
    let pairs = (1..x).flat_map(move |i| (i + 1..x).map(move |j| (i, j)));

    let mut max_length = (0, Rational::new(&BigInt::from(1), &BigInt::from(1)));
    let mut max_denom = (
        Zero::zero(),
        Rational::new(&BigInt::from(1), &BigInt::from(1)),
    );

    for (i, j) in pairs {
        let e = Rational::new(&BigInt::from(i), &BigInt::from(j)).to_egyptian();
        if e.len() > max_length.0 {
            max_length = (e.len(), Rational::new(&BigInt::from(i), &BigInt::from(j)));
        }

        if e.last().unwrap().denominator > max_denom.0 {
            max_denom = (
                e.last().unwrap().denominator.clone(),
                Rational::new(&BigInt::from(i), &BigInt::from(j)),
            );
        }
    }

    println!(
        "Maximum length of terms is for {} with {} terms",
        max_length.1, max_length.0
    );
    println!("{}", rational_vec_to_string(max_length.1.to_egyptian()));

    println!(
        "Maximum denominator is for {} with {} terms",
        max_denom.1, max_denom.0
    );
    println!("{}", rational_vec_to_string(max_denom.1.to_egyptian()));
}
fn main() {
    let tests = [
        Rational::new(&BigInt::from(43), &BigInt::from(48)),
        Rational::new(&BigInt::from(5), &BigInt::from(121)),
        Rational::new(&BigInt::from(2014), &BigInt::from(59)),
    ];

    for test in tests.iter() {
        println!("{} -> {}", test, rational_vec_to_string(test.to_egyptian()));
    }

    run_max_searches(100);
    run_max_searches(1000);
}


import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}

abstract class Frac extends Comparable[Frac] {
  val num: BigInt
  val denom: BigInt

  def toEgyptian: List[Frac] = {
    if (num == 0) {
      return List(this)
    }

    val fracs = new ArrayBuffer[Frac]
    if (num.abs >= denom.abs) {
      val div = Frac(num / denom, 1)
      val rem = this - div
      fracs += div
      egyptian(rem.num, rem.denom, fracs)
    } else {
      egyptian(num, denom, fracs)
    }
    fracs.toList
  }

  @tailrec
  private def egyptian(n: BigInt, d: BigInt, fracs: mutable.Buffer[Frac]): Unit = {
    if (n == 0) {
      return
    }
    val n2 = BigDecimal.apply(n)
    val d2 = BigDecimal.apply(d)
    val (divbd, rembd) = d2./%(n2)
    var div = divbd.toBigInt()
    if (rembd > 0) {
      div = div + 1
    }
    fracs += Frac(1, div)
    var n3 = -d % n
    if (n3 < 0) {
      n3 = n3 + n
    }
    val d3 = d * div
    val f = Frac(n3, d3)
    if (f.num == 1) {
      fracs += f
      return
    }
    egyptian(f.num, f.denom, fracs)
  }

  def unary_-(): Frac = {
    Frac(-num, denom)
  }

  def +(rhs: Frac): Frac = {
    Frac(
      num * rhs.denom + rhs.num * denom,
      denom * rhs.denom
    )
  }

  def -(rhs: Frac): Frac = {
    Frac(
      num * rhs.denom - rhs.num * denom,
      denom * rhs.denom
    )
  }

  override def compareTo(rhs: Frac): Int = {
    val ln = num * rhs.denom
    val rn = rhs.num * denom
    ln.compare(rn)
  }

  def canEqual(other: Any): Boolean = other.isInstanceOf[Frac]

  override def equals(other: Any): Boolean = other match {
    case that: Frac =>
      (that canEqual this) &&
        num == that.num &&
        denom == that.denom
    case _ => false
  }

  override def hashCode(): Int = {
    val state = Seq(num, denom)
    state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
  }

  override def toString: String = {
    if (denom == 1) {
      return s"$num"
    }
    s"$num/$denom"
  }
}

object Frac {
  def apply(n: BigInt, d: BigInt): Frac = {
    if (d == 0) {
      throw new IllegalArgumentException("Parameter d may not be zero.")
    }

    var nn = n
    var dd = d

    if (nn == 0) {
      dd = 1
    } else if (dd < 0) {
      nn = -nn
      dd = -dd
    }

    val g = nn.gcd(dd)
    if (g > 0) {
      nn /= g
      dd /= g
    }

    new Frac {
      val num: BigInt = nn
      val denom: BigInt = dd
    }
  }
}

object EgyptianFractions {
  def main(args: Array[String]): Unit = {
    val fracs = List.apply(
      Frac(43, 48),
      Frac(5, 121),
      Frac(2014, 59)
    )
    for (frac <- fracs) {
      val list = frac.toEgyptian
      val it = list.iterator

      print(s"$frac -> ")
      if (it.hasNext) {
        val value = it.next()
        if (value.denom == 1) {
          print(s"[$value]")
        } else {
          print(value)
        }
      }
      while (it.hasNext) {
        val value = it.next()
        print(s" + $value")
      }
      println()
    }

    for (r <- List(98, 998)) {
      println()
      if (r == 98) {
        println("For proper fractions with 1 or 2 digits:")
      } else {
        println("For proper fractions with 1, 2 or 3 digits:")
      }

      var maxSize = 0
      var maxSizeFracs = new ListBuffer[Frac]
      var maxDen = BigInt(0)
      var maxDenFracs = new ListBuffer[Frac]
      val sieve = Array.ofDim[Boolean](r + 1, r + 2)
      for (i <- 0 until r + 1) {
        for (j <- i + 1 until r + 1) {
          if (!sieve(i)(j)) {
            val f = Frac(i, j)
            val list = f.toEgyptian
            val listSize = list.size
            if (listSize > maxSize) {
              maxSize = listSize
              maxSizeFracs.clear()
              maxSizeFracs += f
            } else if (listSize == maxSize) {
              maxSizeFracs += f
            }
            val listDen = list.last.denom
            if (listDen > maxDen) {
              maxDen = listDen
              maxDenFracs.clear()
              maxDenFracs += f
            } else if (listDen == maxDen) {
              maxDenFracs += f
            }
            if (i < r / 2) {
              var k = 2
              while (j * k <= r + 1) {
                sieve(i * k)(j * k) = true
                k = k + 1
              }
            }
          }
        }
      }
      println(s"  largest number of items = $maxSize")
      println(s"fraction(s) with this number : ${maxSizeFracs.toList}")
      val md = maxDen.toString()
      print(s"  largest denominator = ${md.length} digits, ")
      println(s"${md.substring(0, 20)}...${md.substring(md.length - 20)}")
      println(s"fraction(s) with this denominator : ${maxDenFracs.toList}")
    }
  }
}