#include <bits/stdc++.h>
using namespace std;

const double INF = 1e4;

template <typename T>
struct Dijkstra {
  struct Edge {
    int to;
    int cost;
    int cap;
  };
  vector<vector<Edge>> g;
  Dijkstra(int n) : g(n) {}

  void addEdge(int u, int v, int d, int c) {
    g[u].push_back({v, d, c});
    g[v].push_back({u, d, c});
  }
  T build(int s, int t) {
    vector<vector<vector<T>>> dp(
        g.size(), vector<vector<T>>(g.size(), vector<T>(31, INF)));
    struct Node {
      T time;
      int speed;
      int to;
      int rev;
      bool operator>(const Node& other) const { return speed > other.speed; }
    };
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    pq.push({0.0, 0, s, s});

    while (!pq.empty()) {
      auto now = pq.top();
      pq.pop();
      if (dp[now.to][now.rev][now.speed] < now.time) continue;
      for (auto&& nxt : g[now.to]) {
        if (nxt.to == now.rev) continue;
        for (int ds = -1; ds <= 1; ds++) {
          int speed = now.speed + ds;
          if (speed < 1 || nxt.cap < speed) continue;
          double time = now.time + 1.0 * nxt.cost / speed;
          if (dp[nxt.to][now.to][speed] > time) {
            dp[nxt.to][now.to][speed] = time;
            pq.push({time, speed, nxt.to, now.to});
          }
        }
      }
    }
    T res = INF;
    for (int i = 0; i < g.size(); i++) {
      res = min(res, dp[t][i][1]);
    }
    return res;
  }
};

int main() {
  int n, m;
  while (cin >> n >> m, n) {
    int s, g;
    cin >> s >> g;
    s--, g--;
    Dijkstra<double> graph(n);
    for (int i = 0; i < m; i++) {
      int x, y, d, c;
      cin >> x >> y >> d >> c;
      x--, y--;
      graph.addEdge(x, y, d, c);
    }
    auto ans = graph.build(s, g);
    if (ans < INF) {
      cout << ans << endl;
    } else {
      cout << "unreachable" << endl;
    }
  }
}

