#include <bits/stdc++.h>   using namespace std;   const int INF = 1000000000;   template <typename T>   using V = std::vector<T>;   struct debugger {     template <typename T>     debugger &operator,(const T &v) {       cerr << v <<    ;       return *this;     }   } dbg;   using namespace std;   const double pi = acos(-1);   struct SegmentTree {     int n;     int size;     vector<pair<double, double> > dat;     vector<double> lazy;     int real_size;     SegmentTree(int n_) {       real_size = n_;       n = 1;       size = n_;       while (n < n_) n *= 2;       dat = vector<pair<double, double> >(2 * n - 1);       lazy = vector<double>(2 * n - 1);       init(0, 0, n);     }     void init(int k, int l, int r) {       if (r - l == 1) {         if (l < real_size) {           dat[k] = make_pair(1.0, 0.0);         }       } else {         int m = (l + r) / 2;         init((k * 2 + 1), l, m);         init((k * 2 + 2), m, r);         dat[k] = combine(dat[(k * 2 + 1)], dat[(k * 2 + 2)]);       }     }     void update(int a, int b, const double &d) { update(a, b + 1, 0, 0, n, d); }     void propagate(int k, int l, int r) {       double t = lazy[k];       double x = dat[k].first * cos(t) + dat[k].second * sin(t);       double y = -dat[k].first * sin(t) + dat[k].second * cos(t);       dat[k] = make_pair(x, y);       if ((k * 2 + 2) < lazy.size()) {         lazy[(k * 2 + 1)] += lazy[k];         lazy[(k * 2 + 2)] += lazy[k];       }       lazy[k] = 0.0;     }     void update(int a, int b, int k, int l, int r, const double &d) {       propagate(k, l, r);       if (r <= a || b <= l) return;       if (a <= l && r <= b) {         lazy[k] = d;         propagate(k, l, r);       } else {         int m = (l + r) / 2;         update(a, b, (k * 2 + 1), l, m, d);         update(a, b, (k * 2 + 2), m, r, d);         dat[k] = combine(dat[(k * 2 + 1)], dat[(k * 2 + 2)]);       }     }     void update(int a, int b, int k, int l, int r, int z) {       propagate(k, l, r);       if (r <= a || b <= l) return;       if (a <= l && r <= b) {         double len =             sqrt(dat[k].first * dat[k].first + dat[k].second * dat[k].second);         dat[k].first *= (len + z) / len;         dat[k].second *= (len + z) / len;       } else {         int m = (l + r) / 2;         update(a, b, (k * 2 + 1), l, m, z);         update(a, b, (k * 2 + 2), m, r, z);         dat[k] = combine(dat[(k * 2 + 1)], dat[(k * 2 + 2)]);       }     }     void update(int a, int z) { update(a, a + 1, 0, 0, n, z); }     pair<double, double> query(int a, int b) { return query(a, b + 1, 0, 0, n); }     pair<double, double> query(int a, int b, int k, int l, int r) {       if (r <= a || b <= l) return make_pair(0.0, 0.0);       propagate(k, l, r);       if (a <= l && r <= b) {         return dat[k];       } else {         pair<double, double> vl = query(a, b, (k * 2 + 1), l, (l + r) / 2);         pair<double, double> vr = query(a, b, (k * 2 + 2), (l + r) / 2, r);         return combine(vl, vr);       }     }     pair<double, double> combine(pair<double, double> vl,                                  pair<double, double> vr) {       return make_pair(vl.first + vr.first, vl.second + vr.second);     }   };   int main() {     int N, M;     scanf( %d , &N), scanf( %d , &M);     SegmentTree st(N + 1);     for (int i = 0; i < (M); i++) {       int x;       scanf( %d , &x);       if (x == 2) {         int y, z;         scanf( %d , &y), scanf( %d , &z);         st.update(y, N, z * 1.0 / 360 * 2 * pi);       } else {         int y, z;         scanf( %d , &y), scanf( %d , &z);         st.update(y, z);       }       auto ans = st.query(1, N);       printf( %.10f %.10f n , ans.first, ans.second);     }   }