#define _USE_MATH_DEFINES
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <numeric>
#include <functional>
#include <cctype>
#include <list>
#include <limits>
#include <cassert>
//#include <boost/multiprecision/cpp_int.hpp>



using namespace std;
using Int = long long;
//using namespace boost::multiprecision;

const double EPS = 1e-10;
long long const MOD = 1000000007;

long long mod_pow(long long x, long long n) {
    long long res = 1;
    for(int i = 0;i < 60; i++){
        if(n >> i & 1) res = res * x % MOD;
        x = x * x % MOD;
    }
    return res;
}

template<typename T>
T gcd(T a, T b) {
    return b != 0 ? gcd(b, a % b) : a;
}

template<typename T>
T lcm(T a, T b) {
    return a * b / gcd(a, b);
}

void fastInput() {
    cin.tie(0);
    ios::sync_with_stdio(false);
}

struct Edge {
    int from, to, dist, limit;
};


double INF = 1e10;

// 距離、頂点番号、前の頂点、その頂点に入る時のスピード
vector<vector<vector<double>>> dijkstra(vector<vector<Edge>> &G, int s, int t) {
    vector<vector<vector<double>>> d(G.size(), vector<vector<double>> (G.size() + 1, vector<double> (31, INF)));
    priority_queue<pair<double, pair<int, pair<int, int>>> , vector<pair<double, pair<int, pair<int, int>>>>, greater<pair<double, pair<int, pair<int, int>>>>> que;
    d[s][G.size()][0] = 0;
    que.push({d[s][G.size()][0], {s, {G.size(), 0}}});
    while (!que.empty()) {
        pair<double, pair<int, pair<int, int>>> p = que.top(); que.pop();
        int v = p.second.first;
        int preV = p.second.second.first;
        int speed = p.second.second.second;
        if (d[v][preV][speed] < p.first) continue;
        for (int i=0; i<G[v].size(); i++) {
            Edge e = G[v][i];
            for (int j = -1; j <= 1; j++) {
                int nextSpeed = speed + j;
                if (e.limit < nextSpeed) continue;
                if (nextSpeed <= 0) continue;
                if (e.to == preV) continue;
                if (d[e.to][e.from][nextSpeed] > d[v][preV][speed] + 1.0 * e.dist / nextSpeed) {
                    d[e.to][e.from][nextSpeed] = d[v][preV][speed] + 1.0 * e.dist / nextSpeed;
                    double dist = d[e.to][e.from][nextSpeed];
                    que.push({dist, {e.to, {e.from, nextSpeed}}});
                }
            }
        }
    }
    return d;
}

double solve(int N, int M) {
    int s, t; cin >> s >> t;
    s--, t--;
    vector<vector<Edge>> G(N);
    for (int i = 0; i < M; i++) {
        int u, v; cin >> u >> v;
        u--, v--;
        int d; cin >> d;
        int c; cin >> c;
        Edge e1 = {u, v, d, c};
        Edge e2 = {v, u, d, c};
        G[u].push_back(e1);
        G[v].push_back(e2);
    }

    vector<vector<vector<double>>> D = dijkstra(G, s, t);
    double ret = INF;
    for (int i = 0; i < N; i++) {
        ret = min(ret, D[t][i][1]);
    }
    if (ret == INF) ret = -1;
    return ret;
}

int main(void) {
    int N, M;
    vector<double> ans;
    while (1) {
        cin >> N >> M;
        if (!N && !M) break;
        ans.push_back(solve(N, M));
    }
    for (auto &i : ans) {
        if (i == -1) cout << "unreachable" << endl;
        else printf("%.12f\n", i);
    }
}


Measured memory_bytes: 3784