#include <iostream>
#include <stdexcept>
#include <sstream>

using namespace std;

class Rational {
  private:
    long p, q;

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

      if (teiler > 1) {
        p /= teiler;
        q /= teiler;
      }
      if (q < 0) {
        p = -p;
        q = -q;
      }
      if (p == 0)
        q = 1;
    }

    static long ggt(long a, long b) {
      if (a == 0 && b == 0)
        throw domain_error("ggt(0, 0)");

      long r;
      do {
        r = a % b;
        a = b;
        b = r;
      } while (r != 0);
      return r;
    }

  public:
    Rational(long p_ = 0, long q_ = 1): p(p_), q(q_) {
      if (q == 0) {
        ostringstream os;
        os << "Unerlaubter Aufruf Rational(" << p << ", " << q << ")";
        throw domain_error(os.str());
      }
      normalisieren();
    }

    friend ostream& operator<<(ostream& stream, const Rational& r) {
      if (r.q == 1)
        return stream << r.p;

      return stream << r.p << '/' << r.q;
    }
    friend istream& operator>>(istream& stream, Rational& r) {
      char c;
      stream >> r.p >> c >> r.q;
      if (c != '/' || r.q == 0) {
        stream.setstate(ios::failbit);
        return stream;
      }
      r.normalisieren();
      return stream;
    }

    friend Rational operator/(const Rational& s, const Rational& t) {
      if (t.p == 0) {
        ostringstream os;
        os << "Unerlaubte Operation: " << s << " / " << t;
        throw domain_error(os.str());
      }
      return Rational(s.p*t.q, s.q*t.p);
    }
};

int main() try {
  cin.exceptions(ios::failbit|ios::badbit);

  Rational r, s;
  cout << "p1/q1 p2/q2: ";
  cin >> r >> s;
  cout << "r/s = " << r/s << endl;
  return 0;
} catch (const domain_error& e) {
  cerr << "Bereichsfehler: " << e.what() << endl;
} catch (const ios::failure& e) {
  cerr << "I/O-Fehler: " << e.what() << endl;
} catch (...) {
  cerr << "Sonstige exception" << endl;
}
