#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

template<typename T1,typename T2> inline void chmin(T1 &a, T2 b){ if(a > b) a = b; }
template<typename T1,typename T2> inline void chmax(T1 &a, T2 b){ if(a < b) a = b; }

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
const int MAX_N = 100010;

const double EPS = 1e-8;        // 非常に小さな値
const double PI = acos(-1);     // 円周率

// a == b なら true (誤差に寛容)
inline bool Eq(double a, double b) { return fabs(b - a) < EPS; }

// ユークリッド平面上の点を表す構造体
class Point
{
    public:
        double x, y;
    public:
        Point() {}
        Point(double x, double y) : x(x), y(y) {}
        Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }
        Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
        Point operator*(const double b) const { return Point(x * b, y * b); }
        Point operator*(const Point &b) const { return Point(x * b.x - y * b.y, x * b.y + y * b.x); }

        Point operator/(const double b) const { return Point(x / b, y / b); }
        bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }
        bool operator==(const Point &b) const { return Eq(x, b.x) && Eq(y, b.y); }

        // 大きさの二乗を返します
        double Norm() { return x * x + y * y; }
        // 逆正接(y = 0 からの rad を [-π, π] の範囲で表したもの)を返します
        double Atan2() { return atan2(y, x); }
        // 大きさを返します
        double Abs() { return sqrt(Norm()); }
        // 原点を中心として反時計周りに theta (rad)度回転した座標を返します
        // ※インスタンスの値が更新されるわけではないことに注意
        Point Rotate(double theta) { return Point(cos(theta) * x - sin(theta) * y, sin(theta) * x + cos(theta) * y); }
        // 原点を反時計周りに π/2 回転した座標を返します
        // ※インスタンスの値が更新されるわけではないことに注意
        Point Rotate90() { return Point(-y, x); }
};

// 2 点の外積
double Cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; }
// 2 点の内積
double Dot(const Point &a, const Point &b) { return a.x * b.x + a.y * b.y; }
// ラジアンを角度に
double RadianToDegree(double r) { return (r * 180.0 / acos(-1)); }
// 角度をラジアンに
double DegreeToRadian(double d) { return (d * acos(-1) / 180.0); }
// a->b->c とたどったときの b の角度(ラジアン [0, π])
double GetAngle(const Point &a, const Point &b, const Point &c)
{
  const Point v = a - b, w = c - b;
  double alpha = atan2(v.y, v.x), beta = atan2(w.y, w.x);
  if(alpha > beta) { swap(alpha, beta); }
  double theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

// 直線を表すクラス
class Line
{
    public:
        Point a, b;
    public:
        Line() {};
        Line(Point a, Point b) : a(a), b(b) {};
        // Ax + By = C という式が与えられたときの直線上の任意の 2 点を保存
        Line(double A, double B, double C)
        {
            if(Eq(A, 0)) { a = Point(0, C / B); b = Point(1, C / B); }
            else if(Eq(B, 0)) { a = Point(C / A, 0); b = Point(C / A, 1); }
            else { a = Point(0, C / B); b = Point(C / A, 0); }
        }
        // 傾きとの取得
        enum LineResult {
            INF_SLOPE,  // 傾き無限のグラフ (x = n のグラフ)
            NO_SLOPE,   // 切片のみのグラフ (y = b のグラフ)
            VALID_SLOPE // 傾きと切片のあるグラフ
        };
        // out_a に傾きが、 out_b に切片が、返り値として LineResult が返る
        // INF_SLOPE の時は out_b に x = n の n が入る
        int GetAB(double& out_a, double& out_b) {
            if(abs(a.x - b.x) < EPS) { return INF_SLOPE; }
            if(abs(a.y - b.y) < EPS) {
                out_b = a.y;
                return NO_SLOPE;
            }
            out_a = (a.y - b.y) / (a.x - b.x);
            out_b = a.y - out_a * a.x;
            return VALID_SLOPE;
        }
        // x 座標を渡した時に対応する y 座標を返します
        double GetY(double x) {
            double slope, intercept;
            // x = a の場合は適当な点を返す
            if(GetAB(slope, intercept) == INF_SLOPE) { return a.y; }
            return slope * x + intercept;
        }
        // y 座標を渡した時に対応する x 座標を返します
        double GetX(double y) {
            double slope, intercept;
            // y = b の場合は適当な点を返す
            if(GetAB(slope, intercept) == INF_SLOPE) { return a.x; }
            return (y - intercept) / slope;
        }
};

// 線分を表すクラス
// 直線と違い端点が定義できる場合はこちら
class Segment
{
    public:
        Point a, b;
        Segment() {};
        Segment(Point a, Point b) : a(a), b(b) {};
        // 中点を求める
        Point Center() { return Point((a.x + b.x) / 2, (a.y + b.y) / 2); }
        // 垂直二等分線を求める
        Line PerpBisector() {
            Point center = this->Center();
            return Line((a - center).Rotate90() + center, center);
        }
        // a を起点として反時計回りに theta (rad)度回転した座標を返します
        // ※インスタンスの値が更新されるわけではないことに注意
        Segment Rotate(double theta) {
            Point tmp(b.x - a.x, b.y - a.y);
            tmp = tmp.Rotate(theta);
            return Segment(a, Point(tmp.x + a.x, tmp.y + a.y));
        }
};

// 円を表すクラス
class Circle
{
    public:
        Point p;  // 中心
        double r; // 半径

        Circle() {};
        Circle(Point p, double r) : p(p), r(r) {};
};

// その他図形を表す型定義
typedef vector< Point > Polygon;            // 多角形
typedef vector< Segment > Segments;         // 線分集合
typedef vector< Line > Lines;               // 直線集合
typedef vector< Circle > Circles;           // 円集合
typedef pair< Point, Point > PointPoint;    // 2 点

// 点の進行方向を調べる
enum DotDir {
    Counterclockwise = 1,   // a -> b 反時計周りの方向に c
    Clockwise = -1,         // a -> b 時計周りの方向に c
    CAB = 2,                // c -> a -> b の順に並ぶ
    ABC = -2,               // a -> b -> c の順に並ぶ
    ACB = 0                 // a -> c -> b の順に並ぶ
};
// a -> b -> c の順に点をたどったときの進行方向 DotDir を返す
int Ccw(const Point &a, Point b, Point c)
{
  b = b - a, c = c - a;
  if(Cross(b, c) > EPS) { return Counterclockwise; }
  if(Cross(b, c) < -EPS) { return Clockwise; }
  if(Dot(b, c) < 0) { return CAB; }
  if(b.Norm() < c.Norm()) { return ABC; }
  return ACB;
}

// --- 直線の平行・交差判定 --- //

// 直線の平行判定 a, b が平行なら true
bool Parallel(const Line& a,const Line& b){
  return abs(Cross(a.b - a.a, b.b - b.a)) < EPS;
}
// 直線の直交判定 a, b が直交していれば true
bool Orthogonal(const Line& a,const Line& b){
  return abs(Dot(a.a - a.b, b.a - b.b)) < EPS;
}

// --- 点から直線・線分への射影・反射 --- //
// ※射影と反射の定義、少し違う気がするが気にしないことにする

// 射影
// 点 p から直線 l に対して垂線をおろしたときの交点 x を射影と呼ぶことにする
// その x を返す
Point Projection(const Line& l, const Point& p) {
  double t = Dot(p - l.a, l.a - l.b) / (l.a - l.b).Norm();
  return l.a + (l.a - l.b) * t;
}
// 線分に対しても直線と同じ式()
Point Projection(const Segment& l, const Point& p) {
  double t = Dot(p - l.a, l.a - l.b) / (l.a - l.b).Norm();
  return l.a + (l.a - l.b) * t;
}

// 反射
// 直線 l を対象軸として点 p と線対称の位置にある点 x を p の反射と呼ぶ
Point Reflection(const Line& l, const Point& p) {
  return p + (Projection(l, p) - p) * 2.0;
}

// --- 点・直線・線分の交差判定 --- //
double Distance(const Point& a,const Point& b); // プロトタイプ
double Distance(const Line& l,const Point& p);  // 同上

// 直線 l 上に点 p があるなら true
bool Intersect(const Line &l, const Point &p) { return abs(Ccw(l.a, l.b, p)) != 1; }
// 直線同士が交わっているなら true
bool Intersect(const Line &l, const Line &m) {
  return abs(Cross(l.b - l.a, m.b - m.a)) > EPS || abs(Cross(l.b - l.a, m.b - l.a)) < EPS;
}
// 線分 s 上に点 p があるなら true
bool Intersect(const Segment &s, const Point &p) { return Ccw(s.a, s.b, p) == ACB; }
// 直線と線分が交わっているなら true
bool Intersect(const Line &l, const Segment &s) {
    return Cross(l.b - l.a, s.a - l.a) * Cross(l.b - l.a, s.b - l.a) < EPS;
}
// 線分同士が交わっているなら true
bool Intersect(const Segment &s, const Segment &t) {
  return Ccw(s.a, s.b, t.a) * Ccw(s.a, s.b, t.b) <= 0 && Ccw(t.a, t.b, s.a) * Ccw(t.a, t.b, s.b) <= 0;
}
// 直線と円が接しているなら true
bool Intersect(const Circle &c, const Line &l) { return Distance(l, c.p) <= c.r + EPS; }
// 点が円周上にあるなら true
bool Intersect(const Circle &c, const Point &p) { return abs((p - c.p).Abs() - c.r) < EPS; }
// 線分が円周と交差する数を返す
// ただし円の接線の場合も 2 を返す
int Intersect(const Circle &c, const Segment &l)
{
    // 円の中心から線分に向かっての射影までの距離が
    // 円の半径より大きいなら円と線分は交わっていない
    if((Projection(l, c.p) - c.p).Norm() - c.r * c.r > EPS) { return 0; }
    // 線分の端点から円の中心までの距離
    const double d1 = (c.p - l.a).Abs(), d2 = (c.p - l.b).Abs();
    // 両方の端点が円の内部にある場合は円に内包されているため交わっていない
    if(d1 < c.r + EPS && d2 < c.r + EPS) { return 0; }
    // 端点のどちらか片方だけ円に入っている
    if(d1 < c.r - EPS && d2 > c.r + EPS || d1 > c.r + EPS && d2 < c.r - EPS) { return 1; }
    // 円の中心から線分への射影
    const Point h = Projection(l, c.p);
    // 射影から各端点への内積が負 = 射影は線分の中にある
    // -> 線分は円を通過する
    if(Dot(l.a - h, l.b - h) < 0) { return 2; }
    return 0;
}

// 円周どうしの交差判定
bool Intersect(const Circle &c1, const Circle &c2) {
    double d = Distance(c1.p, c2.p);
    if(d > c1.r + c2.r) { return false; }
    if(d + min(c1.r, c2.r) < max(c1.r, c2.r)) { return false; }
    return true;
}

// --- 点・直線・線分・円の距離 --- //

// 2 点 a, b 間の距離
double Distance(const Point& a,const Point& b) { return (a - b).Abs(); }

// 点 p から直線 l に対して下した垂線の距離
// = 点 p と点 p の直線 l に対する射影の距離
double Distance(const Line& l,const Point& p) { return (p - Projection(l, p)).Abs(); }

// 直線同士の距離
// 平行である -> 直線 m 上の任意点からの l に対する射影への距離
// 平行でない -> 0
double Distance(const Line& l,const Line& m) {
  return Intersect(l, m) ? 0 : Distance(l, m.a);
}

// 線分と点の距離
// 点 p の線分 l に対する射影 r を求め、それが l 上にあるならそれと点 p の距離
// ないなら線分 l の両端のどっちか短い方が距離
double Distance(const Segment& s,const Point& p){
  Point r = Projection(s, p);
  if (Intersect(s, r)) { return (r - p).Abs(); }
  return min((s.a - p).Abs(), (s.b - p).Abs());
}

// 線分同士の距離
// 線分が交差している -> 0
// 交差していない -> 線分の端点の組み合わせパターンの最小が距離
double Distance(const Segment& a,const Segment& b){
  if(Intersect(a, b)) { return 0; }
  return min({ Distance(a, b.a), Distance(a, b.b), Distance(b, a.a), Distance(b, a.b) });
}

// 直線と線分の距離
// 交差している -> 0
// 交差していない -> 線分の端点 2 つと直線の距離の最小
double Distance(const Line& l,const Segment& s) {
  if (Intersect(l, s)) { return 0; }
  return min(Distance(l, s.a), Distance(l, s.b));
}

// 点 p から円 c の円周の一番近いところまでの距離
double Distance(const Point& p, const Circle& c) {
    if(Distance(p, c.p) <= c.r) { return 0; }
    double ret = Distance(p, c.p) - c.r;
    return (ret < 0) ? 0 : ret;
}

// 円 c1 と円 c2 の円周の一番近いところどうしの距離
double Distance(const Circle& c1, const Circle& c2) {
    if(Intersect(c1, c2)) { return 0; }
    double ret = Distance(c1.p, c2.p) - c1.r - c2.r;
    return (ret < 0) ? 0 : ret;
}

signed main() {
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);

    double A, B, H, M;
    cin >> A >> B >> H >> M;

    Point a(0, A), b(0, B);
    double diff_a = 360.0 / 12.0;
    double diff_b = 360.0 / 60.0;
    double a_deg = diff_a * H;
    a_deg += (diff_a / 60.0) * M;
    double b_deg = diff_b * M;
    double a_rad = DegreeToRadian(a_deg);
    double b_rad = DegreeToRadian(b_deg);
    a = a.Rotate(a_rad);
    b = b.Rotate(b_rad);

    double ans = Distance(a, b);
    printf("%.10f\n", ans);

    return 0;
}


Measured memory_bytes: 4128