#include <bits/stdc++.h>
using namespace std;
char nc() {
  static char buf[1 << 25], *p = buf, *q = buf;
  if (p == q && (q = (p = buf) + fread(buf, 1, 1 << 25, stdin), p == q))
    return EOF;
  return *p++;
}
template <class T>
void rd(T& x) {
  short f = 1;
  x = 0;
  char ch = nc();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = nc();
  }
  while (isdigit(ch)) {
    x = (x << 1) + (x << 3) + (ch ^ 48);
    ch = nc();
  }
  x *= f;
}
template <class T>
void wr(T x) {
  if (x < 0) putchar('-'), x = -x;
  if (x >= 10) wr(x / 10);
  putchar(x % 10 + 48);
}
int n, m, shit;
int x, y, z;
struct Cp {
  double a, b;
  Cp(double aa = 0, double bb = 0) : a(aa), b(bb) {}
  Cp operator+(Cp x) const { return Cp(a + x.a, b + x.b); }
  Cp operator-(Cp x) const { return Cp(a - x.a, b - x.b); }
  Cp operator*(Cp x) const { return Cp(a * x.a - b * x.b, a * x.b + x.a * b); }
  Cp operator*(int x) const { return Cp(a * x, b * x); }
  double len() { return sqrt(a * a + b * b); }
  void print() { printf("%.12lf %.12lf\n", a, b); }
};
Cp e(int a) {
  double r = a * 3.14159265358979323846 / 180;
  return Cp(cos(r), -sin(r));
}
struct {
  int l, r;
  Cp sum, mul, add;
} tree[300010 << 2];
void pushup(int x) { tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum; }
void pushdown(int x) {
  if (tree[x].mul.a != 1 || tree[x].mul.b) {
    tree[x << 1].add = tree[x << 1].add * tree[x].mul;
    tree[x << 1 | 1].add = tree[x << 1 | 1].add * tree[x].mul;
    tree[x << 1].sum = tree[x << 1].sum * tree[x].mul;
    tree[x << 1 | 1].sum = tree[x << 1 | 1].sum * tree[x].mul;
    tree[x << 1].mul = tree[x << 1].mul * tree[x].mul;
    tree[x << 1 | 1].mul = tree[x << 1 | 1].mul * tree[x].mul;
    tree[x].mul = Cp(1, 0);
  }
  if (tree[x].add.a || tree[x].add.b) {
    tree[x << 1].add = tree[x << 1].add + tree[x].add;
    tree[x << 1 | 1].add = tree[x << 1 | 1].add + tree[x].add;
    tree[x << 1].sum =
        tree[x << 1].sum + tree[x].add * (tree[x << 1].r - tree[x << 1].l + 1);
    tree[x << 1 | 1].sum =
        tree[x << 1 | 1].sum +
        tree[x].add * (tree[x << 1 | 1].r - tree[x << 1 | 1].l + 1);
    tree[x].add = Cp(0, 0);
  }
}
void build(int x, int l, int r) {
  tree[x].l = l, tree[x].r = r;
  tree[x].mul = Cp(1, 0);
  if (l == r) {
    tree[x].sum = Cp(l - 1, 0);
    return;
  }
  int mid = (l + r) >> 1;
  build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
  pushup(x);
}
void add(int x, int l, int r, Cp k) {
  if (tree[x].l >= l && tree[x].r <= r) {
    tree[x].add = tree[x].add + k;
    tree[x].sum = tree[x].sum + Cp(tree[x].r - tree[x].l + 1) * k;
    return;
  }
  pushdown(x);
  int mid = (tree[x].l + tree[x].r) >> 1;
  if (l <= mid) add(x << 1, l, r, k);
  if (r > mid) add(x << 1 | 1, l, r, k);
  pushup(x);
}
void mul(int x, int l, int r, Cp k) {
  if (tree[x].l >= l && tree[x].r <= r) {
    tree[x].add = tree[x].add * k;
    tree[x].mul = tree[x].mul * k;
    tree[x].sum = tree[x].sum * k;
    return;
  }
  pushdown(x);
  int mid = (tree[x].l + tree[x].r) >> 1;
  if (l <= mid) mul(x << 1, l, r, k);
  if (r > mid) mul(x << 1 | 1, l, r, k);
  pushup(x);
}
Cp get(int x, int pos) {
  if (tree[x].l == tree[x].r) return tree[x].sum;
  pushdown(x);
  int mid = (tree[x].l + tree[x].r) >> 1;
  if (pos <= mid)
    return get(x << 1, pos);
  else
    return get(x << 1 | 1, pos);
}
signed main() {
  rd(n), rd(m);
  build(1, 1, n + 1);
  while (m--) {
    rd(z), rd(x), rd(y);
    Cp A = get(1, x), B = get(1, x + 1);
    if (z == 1) {
      Cp t = B - A;
      double ll = t.len();
      t = Cp(y * t.a / ll, y * t.b / ll);
      add(1, x + 1, n + 1, t);
    } else {
      Cp E = e(y);
      mul(1, x + 1, n + 1, E);
      add(1, x + 1, n + 1, (Cp(1, 0) - E) * A);
    }
    Cp g = get(1, n + 1);
    g.print();
  }
}
