#include <bits/stdc++.h>
using namespace std;
struct point {
  long double x, y, ang;
  point() {}
  point(long double x_, long double y_, long double ang_) {
    x = x_;
    y = y_;
    ang = ang_;
  }
};
point operator+(const point& a, const point& b) {
  return point(a.x + b.x * cos(a.ang) - b.y * sin(a.ang),
               a.y + b.x * sin(a.ang) + b.y * cos(a.ang), a.ang + b.ang);
}
const int MAXSEG = 1 << 20;
const long double PI = 3.1415926535897932384626433832795;
int N, M;
point seg[MAXSEG];
void build_tree(int node, int left, int right) {
  if (left == right) {
    seg[node] = point(1.0, 0.0, 0.0);
    return;
  }
  int mid = (left + right) / 2;
  build_tree(2 * node, left, mid);
  build_tree(2 * node + 1, mid + 1, right);
  seg[node] = seg[2 * node] + seg[2 * node + 1];
}
void update(int node, int left, int right, int type, int idx, long double d) {
  if (idx == left && right == idx) {
    long double len =
        sqrt(seg[node].x * seg[node].x + seg[node].y * seg[node].y);
    if (type == 1) {
      seg[node].x *= (len + d) / len;
      seg[node].y *= (len + d) / len;
    } else {
      seg[node].ang -= d * PI / 180;
      seg[node].x = len * cos(seg[node].ang);
      seg[node].y = len * sin(seg[node].ang);
    }
    return;
  }
  int mid = (left + right) / 2;
  if (idx <= mid)
    update(2 * node, left, mid, type, idx, d);
  else
    update(2 * node + 1, mid + 1, right, type, idx, d);
  seg[node] = seg[2 * node] + seg[2 * node + 1];
}
int main() {
  ios::sync_with_stdio(0);
  cin >> N >> M;
  build_tree(1, 1, N);
  for (int i = 0, x, y, z; i < M; i++) {
    cin >> x >> y >> z;
    update(1, 1, N, x, y, z);
    cout << setprecision(10) << seg[1].x << " " << seg[1].y << "\n";
  }
  return 0;
}
