#include <bits/stdc++.h>

using namespace std;

#define SZ(x) (int)(x.size())
#define REP(i, n) for(int i=0;i<(n);++i)
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RREP(i, n) for(int i=(int)(n);i>=0;--i)
#define RFOR(i, a, b) for(int i=(int)(a);i>=(int)(b);--i)
#define ALL(a) (a).begin(),(a).end()
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<< endl;

using ll = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using P = pair<int, int>;

const double eps = 1e-8;
const ll MOD = 1000000007;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;

template<typename T1, typename T2>
bool chmax(T1 &a, const T2 &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template<typename T1, typename T2>
bool chmin(T1 &a, const T2 &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template<typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> p) {
  os << p.first << ":" << p.second;
  return os;
}

template<class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  REP(i, SZ(v)) {
    if (i) os << " ";
    os << v[i];
  }
  return os;
}

struct Edge {
  int u, v, c;
  double d;

  Edge(int u, int v, double d, int c) : u(u), v(v), d(d), c(c) {}
};

struct Elm {
  int now, prev, v;
  double d;
};

bool operator<(Elm e1, Elm e2) { return e1.d > e2.d; }

int cnt = 0;

bool solve() {
  cnt++;
  int n, m;
  cin >> n >> m;
  if (n == 0) return false;
  int start, goal;
  cin >> start >> goal;
  start--;
  goal--;

  vector<vector<Edge>> g(n);
  int ma = 1;
  REP(i, m) {
    int u, v, c;
    double d;
    cin >> u >> v >> d >> c;
    ma = max(ma, c);
    u--;
    v--;
    g[u].push_back(Edge(u, v, d, c));
    g[v].push_back(Edge(v, u, d, c));
  }
/*
  if(cnt == 17) {
    REP(i, n) {
      cerr << i << ":";
      for (auto &e: g[i]) {
        cerr << "{" << e.v << "," << e.c << "," << e.d << "}" << " ";
      }
      cerr << endl;
    }
  }
  */


  vector<vector<vector<double>>> dp(n, vector<vector<double>>(n, vector<double>(ma+1, INF)));

  priority_queue<Elm> pq;
  pq.push({start, start, 0, 0});
  dp[start][start][0] = 0;
  while (!pq.empty()) {
    auto tmp = pq.top();
    pq.pop();
    int now = tmp.now, prev = tmp.prev, v = tmp.v;

    double d = tmp.d;
    if (dp[now][prev][v] < d - eps) continue;
    REP(i, SZ(g[now])) {
      int nxt = g[now][i].v;
      if (nxt == prev) continue;
      for (int j = -1; j <= 1; ++j) {
        int nv = v + j;
        if (nv <= 0 || g[now][i].c < nv) continue;
        double diff = g[now][i].d / nv;
        if (dp[nxt][now][nv] - eps > d + diff) {
          dp[nxt][now][nv] = d + diff;
          pq.push({nxt, now, nv, dp[nxt][now][nv]});
        }
      }
    }
  }


  double ans = INF;
  REP(i, n) {
    chmin(ans, dp[goal][i][1]);
  }

  if (abs(ans - INF) < eps) {
    cout << "unreachable" << endl;
  } else {
    cout << ans << endl;
  }

  return true;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  while (1) {
    if (!solve()) break;
  }


}

























Measured memory_bytes: 3956