Problem: You are given two rectangles on a plane. The centers of both rectangles are located in the origin of coordinates (meaning the center of the rectangle's symmetry). The first rectangle's sides are parallel to the coordinate axes: the length of the side that is parallel to the Ox axis, equals w, the length of the side that is parallel to the Oy axis, equals h. The second rectangle can be obtained by rotating the first rectangle relative to the origin of coordinates by angle α.

<image>

Your task is to find the area of the region which belongs to both given rectangles. This region is shaded in the picture.

Input

The first line contains three integers w, h, α (1 ≤ w, h ≤ 106; 0 ≤ α ≤ 180). Angle α is given in degrees.

Output

In a single line print a real number — the area of the region which belongs to both given rectangles.

The answer will be considered correct if its relative or absolute error doesn't exceed 10 - 6.

Examples

Input

1 1 45


Output

0.828427125


Input

6 4 30


Output

19.668384925

Note

The second sample has been drawn on the picture above.

Solution (in JAVA):

Solution:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.StringTokenizer;

public class cf280a {
  static FastIO in = new FastIO(), out = in;

  public static void main(String[] args) {
    double w = in.nextInt();
    double h = in.nextInt();
    double alpha = in.nextInt();
    if (alpha == 0 || alpha == 180 || (alpha == 90 && w == h)) {
      out.printf("%.10f%n", w * h);
      out.close();
      return;
    }
    alpha = Math.toRadians(alpha);
    vec2[] corners = new vec2[4];
    corners[0] = new vec2(w / 2, h / 2);
    corners[1] = new vec2(-w / 2, h / 2);
    corners[2] = new vec2(-w / 2, -h / 2);
    corners[3] = new vec2(w / 2, -h / 2);
    line2[] r1 = new line2[4];
    line2[] r2 = new line2[4];
    for (int i = 0; i < 4; i++)
      r1[i] = new line2(corners[i], corners[(i + 1) % 4]);
    for (int i = 0; i < 4; i++)
      r2[i] = new line2(corners[i].rotate(alpha),
          corners[(i + 1) % 4].rotate(alpha));

    ArrayList<vec2> pts = new ArrayList<vec2>();
    for (int i = 0; i < 4; i++)
      for (int j = 0; j < 4; j++) {
        vec2 v = r1[i].intersect(r2[j]);
        if (v != null)
          pts.add(v);
      }
    // System.out.println(pts);
    poly2 poly = new poly2(ConvexHull.convexHull(pts));
    out.printf("%.10f%n", poly.getArea());
    out.close();
  }

  static class poly2 {
    int N;
    vec2[] vs;

    poly2(ArrayList<vec2> v) {
      vs = v.toArray(new vec2[0]);
      N = v.size();
    }

    public String toString() {
      return Arrays.toString(vs);
    }

    double getArea() {
      double sum = 0;
      for (int i = 0; i < N; i++)
        sum += vs[i].cross(vs[(i + 1) % N]);
      return Math.abs(0.5 * sum);
    }

    // Centroid of a solid cone.myramid is 1/4 height
    // for a hollow, it is 1/3 height
    vec2 getCentroid() {
      double A = 0, cx = 0, cy = 0;
      for (int i = 0, j = 1; i < N; i++, j = (j + 1) % N) {
        double a1 = vs[i].cross(vs[j]);
        cx += a1 * (vs[i].x + vs[j].x);
        cy += a1 * (vs[i].y + vs[j].y);
        A += a1;
      }
      return new vec2(cx / (3 * A), cy / (3 * A));
    }

    boolean contains(vec2 p) {
      double sum = 0;
      for (int i = 0, j = 1; i < N; i++, j = (j + 1) % N) {
        if (vs[i].eq(p))
          return true;
        sum += vs[i].angleBtwn(vs[j]);
      }
      // If sum == 2*PI, inside
      // == PI , on edge
      // == 0 , outside
      return Math.abs(sum) > 2 * 0.5 * Math.PI;
    }
  }

  static class GEOM {
    static double EPS = 1e-9;

    static boolean eq(double a, double b) {
      double d = Math.abs(a - b);
      if (d < EPS)
        return true;
      return d < EPS * Math.max(Math.abs(a), Math.abs(b));
    }
  }

  static class line2 {
    vec2 e1, e2;

    line2(vec2 a, vec2 b) {
      e1 = a;
      e2 = b;
    }

    public String toString() {
      return e1 + " :: " + e2;
    }

    vec2 getVec2() {
      return e2.sub(e1);
    }

    vec2 intersect(line2 rhs) {
      vec2 v1 = getVec2(), v2 = rhs.getVec2(), v3 = rhs.e1.sub(e1);
      double div = v1.cross(v2), sn = v3.cross(v2);
      double s = sn / div;
      if (Math.abs(div) < 1e-9)
        return null; // parallel lines
      vec2 p = v1.scale(s).add(e1);
      // segment intersection
      double r = rhs.scaleProj(p);
      if (s < 0 || r < 0 || s > 1 || r > 1)
        return null;
      return p;
    }

    double scaleProj(vec2 p) {// 0.0 -> 1.0
      vec2 v1 = getVec2();
      return v1.dot(p.sub(e1)) / v1.mag2();
    }

    vec2 proj(vec2 p) {
      vec2 v1 = getVec2();
      double k = v1.dot(p.sub(e1)) / v1.mag2();
      return v1.scale(k).add(e1);
    }

    boolean isLower(vec2 a, vec2 b, vec2 p) {
      return b.sub(a).dot(p.sub(a)) < 0;
    }

    boolean checkSides(vec2 a, vec2 b, vec2 c, vec2 d) {
      vec2 v1 = b.sub(a);
      return v1.cross(c.sub(a)) * v1.cross(d.sub(a)) <= 0;
    }

    boolean intersects(line2 rhs) { // checks for segment intersection
      vec2[][] v = { { e1, e2 }, { rhs.e1, rhs.e2 } };
      for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++)
          if (isLower(v[i][j], v[i][1 - j], v[1 - i][0])
              && isLower(v[i][j], v[i][1 - j], v[1 - i][1]))
            return false;
      return checkSides(e1, e2, rhs.e1, rhs.e2)
          && checkSides(rhs.e1, rhs.e2, e1, e2);
    }

    double dist(vec2 p) {
      vec2 A = getVec2();
      double t = A.dot(p.sub(e1)) / A.mag2();
      if (t >= 1)
        return e2.dist(p);
      if (t <= 0)
        return e1.dist(p);
      return p.dist(A.scale(t).add(e1));
    }

    double dist(line2 rhs) {
      if (intersects(rhs))
        return 0.;
      return Collections.min(Arrays.asList(dist(rhs.e1), dist(rhs.e2),
          rhs.dist(e1), rhs.dist(e2)));
    }
  }

  static class vec2 implements Comparable<vec2> {
    double x, y;

    public String toString() {
      return String.format("(%.2f %.2f)", x, y);
    }

    vec2(double a, double b) {
      x = a;
      y = b;
    }

    boolean eq(vec2 rhs) {
      return GEOM.eq(x, rhs.x) && GEOM.eq(y, rhs.y);
    }

    vec2 add(vec2 rhs) {
      return new vec2(x + rhs.x, y + rhs.y);
    }

    vec2 sub(vec2 rhs) {
      return new vec2(x - rhs.x, y - rhs.y);
    }

    vec2 scale(double s) {
      return new vec2(x * s, y * s);
    }

    vec2 midpoint(vec2 rhs) {
      return new vec2(.5 * (x + rhs.x), .5 * (y + rhs.y));
    }

    double dot(vec2 rhs) {
      return x * rhs.x + y * rhs.y;
    }

    double cross(vec2 rhs) {
      return x * rhs.y - y * rhs.x;
    }// pos->left,neg->right

    double mag() {
      return Math.sqrt(x * x + y * y);
    }

    double mag2() {
      return x * x + y * y;
    }

    double dist(vec2 rhs) {
      return sub(rhs).mag();
    }

    double dist2(vec2 rhs) {
      return sub(rhs).mag2();
    }

    vec2 normalize() {
      return scale(1. / mag());
    } // assumes mag()!=0

    double angleBtwn(vec2 rhs) {
      return Math.atan2(cross(rhs), dot(rhs));
    }

    double angle() {
      return Math.atan2(y, x);
    }

    vec2 orthoCW() {
      return new vec2(y, -x);
    }

    vec2 orthoCCW() {
      return new vec2(-y, x);
    }

    vec2 reflect(vec2 n) {
      return sub(scale(-2 * dot(n)));
    }// n==surface normal

    // [cos(t) -sin(t)][x] = [x*cos(t)-y*sin(t) x*sin(t)+y*cos(t)]
    // [sin(t) cos(t)][y]
    vec2 rotate(double ang) {
      double nx = x * Math.cos(ang) - y * Math.sin(ang);
      double ny = x * Math.sin(ang) + y * Math.cos(ang);
      return new vec2(nx, ny);
    }

    public int compareTo(vec2 rhs) {
      if (GEOM.eq(x, rhs.x))
        return Double.compare(y, rhs.y);
      return Double.compare(x, rhs.x);
    }
  }

  static class ConvexHull {
    static double cross(vec2 p, vec2 a, vec2 b) {
      return a.sub(p).cross(b.sub(p));
    }

    static ArrayList<vec2> convexHull2(ArrayList<vec2> pts) {
      int k = 0, lim = 2, start = 0, end = pts.size();
      vec2[] H = new vec2[end + 10];
      Collections.sort(pts);
      for (int dir = 1; dir >= -1; dir -= 2, start = end + (end = -1), lim = k + 1)
        for (int i = start; i != end; i += dir) {
          while (k >= lim && cross(H[k - 2], H[k - 1], pts.get(i)) <= 0)
            k--;
          H[k++] = pts.get(i);
        }
      ArrayList<vec2> res = new ArrayList<vec2>();
      for (int i = 0; i < k - 1; i++)
        res.add(H[i]);
      return res;
    }

    static ArrayList<vec2> convexHull3(ArrayList<vec2> p) {
      int n = p.size();
      Collections.sort(p);
      Deque<vec2> b = new ArrayDeque<vec2>(), u = new ArrayDeque<vec2>();
      for (int i = 0; i < n; b.add(p.get(i++)))
        while (b.size() > 1 && ccw(p.get(i), b))
          ;
      for (int i = n - 1; i >= 0; u.add(p.get(i--)))
        while (u.size() > 1 && ccw(p.get(i), u))
          ;
      u.removeFirst();
      u.removeLast();
      b.addAll(u);
      return new ArrayList<vec2>(b);
    }

    static ArrayList<vec2> convexHull(ArrayList<vec2> pp) {
      vec2[] p = pp.toArray(new vec2[0]); Arrays.sort(p);
      Deque<vec2>[] q = new Deque[]{new ArrayDeque<vec2>(),new ArrayDeque<vec2>()};
      for (int s=0, e=p.length, z=0, d=1; d>=-1; d-=2, s=e+(e=-1), q[z++].removeFirst())
        for (; s != e; q[z].add(p[s]), s += d)
          while (q[z].size() > 1 && ccw(p[s], q[z]));
      q[0].addAll(q[1]);
      return new ArrayList<vec2>(q[0]);
    }
    static boolean ccw(vec2 v, Deque<vec2> h) {
      vec2 r = h.removeLast();
      return (v.sub(r).cross(r.sub(h.getLast())) >= 0) ? true : !h.add(r);
    }
  }

  static class FastIO extends PrintWriter {
    BufferedReader br;
    StringTokenizer st;

    public FastIO() {
      this(System.in, System.out);
    }

    public FastIO(InputStream in, OutputStream out) {
      super(new BufferedWriter(new OutputStreamWriter(out)));
      br = new BufferedReader(new InputStreamReader(in));
      scanLine();
    }

    public void scanLine() {
      try {
        st = new StringTokenizer(br.readLine().trim());
      } catch (Exception e) {
        throw new RuntimeException(e.getMessage());
      }
    }

    public int numTokens() {
      if (!st.hasMoreTokens()) {
        scanLine();
        return numTokens();
      }
      return st.countTokens();
    }

    public String next() {
      if (!st.hasMoreTokens()) {
        scanLine();
        return next();
      }
      return st.nextToken();
    }

    public double nextDouble() {
      return Double.parseDouble(next());
    }

    public long nextLong() {
      return Long.parseLong(next());
    }

    public int nextInt() {
      return Integer.parseInt(next());
    }
  }
}