#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

class rational {
  private:
    long int p, q;

    void normalisieren() {
      long int teiler = ggt(p, q);
      p /= teiler;
      q /= teiler;

      if (q < 0) {
        p = -p;
        q = -q;
      }
      if (p == 0)
        q = 1;
    }
    static long int ggt(long int a, long int b) {
      if (a == 0) return abs(b);
      if (b == 0) return abs(a);

      long int h;
      do {
        h = a % b;
        a = b;
        b = h;
      } while (h != 0);

      return abs(a);
    }

  public:
    rational(long int p_ = 0, long int q_ = 1): p(p_), q(q_) {
      normalisieren();
    }

    operator long double() {
      return static_cast<long double>(p) / static_cast<long double>(q);
    }

    rational& operator+=(const rational& r) {
      p *= r.q;
      p += r.p * q;
      q *= r.q;
      normalisieren();
      return *this;
    }
    friend rational operator-(const rational& r) {
      return rational{-r.p, r.q};
    }
    rational& operator-=(const rational& r) {
      return *this += -r;
    }
    rational& operator*=(const rational& r) {
      p *= r.p;
      q *= r.q;
      normalisieren();
      return *this;
    }
    rational& operator/=(const rational& r) {
      return *this *= rational{r.q, r.p};
    }
    
    friend rational operator+(rational r, const rational& s) {
      return r += s;
    }
    friend rational operator-(rational r, const rational& s) {
      return r -= s;
    }
    friend rational operator*(rational r, const rational& s) {
      return r *= s;
    }
    friend rational operator/(rational r, const rational& s) {
      return r /= s;
    }

    friend ostream& operator<<(ostream& stream, const rational& r) {
      return stream << r.p << "/" << r.q;
    }
    friend istream& operator>>(istream& stream, rational& r) {
      long int p_, q_;
      char c;
      stream >> p_ >> c >> q_;
      if (c != '/' || q_ == 0)
        stream.setstate(ios::failbit);
      else
        r = rational{p_, q_};
      return stream;
    }
};

rational pow(const rational& r, long int z) {
  rational res{1};

  for (long int i = 0; i < abs(z); i++) {
    if (z < 0)
      res /= r;
    else
      res *= r;
  }

  return res;
}

rational pot_reihe(const rational& r, long int n) {
  rational res{0};
  for (long int k = 1; k <= n; k++) {
    res += static_cast<rational>(k) * pow(r, k);
  }
  return res;
}

rational kettenbruch(const vector<long int>& a, const vector<long int>& b) {
  vector<long int>::size_type n = a.size();
  rational res{b[n]};
  for (vector<long int>::size_type i = n; i > 0; i--)
    res = rational(b[i - 1]) + rational(a[i - 1]) / res;
  return res;
}

int main() {
  cout << setprecision(18);

  long int n = 8;
  vector<rational> rs{rational{2, 3}, -rational{10, 7}};

  // a)
  for (rational r: rs)
    cout << "pot_reihe(" << r << ", " << n << ") = "
         << pot_reihe(r, n) << " =~ "
         << static_cast<long double>(pot_reihe(r, n)) << endl;
  cout << endl;

  // b)
  for (rational r: rs) {
    rational p = (rational{n} * pow(r, n + 2) - rational{n + 1} * pow(r, n + 1) + r) / pow(r - rational{1}, 2);
    cout << "p = " << p << " =~ " << static_cast<long double>(p) << endl;
  }
  cout << endl;

  // c)
  rational r = kettenbruch({1, 1, 1, 1}, {3,7, 15, 1, 292});
  cout << "kettenbruch(...) = "
       << r << " =~ "
       << static_cast<long double>(r) << endl;
  cout << endl;

  // d)
  for (long int n = 1; n <= 10; n++) {
   vector<long int> a(n), b(n + 1);
   a[0] = 4;
   b[0] = 0;
   for (long int i = 1; i <= n; i++) {
     if (i < n)
       a[i] = i * i;
     b[i] = 2 * i - 1;
   }

   rational k = kettenbruch(a, b);
   cout << "k[" << setw(2) << n << "] = "
        << k << " =~ "
        << static_cast<long double>(k) << endl;
  }
}
