// Original C++ solution (slower):
#include<stdio.h>

#include<iostream>

#include<algorithm>

#include<vector>

#include<queue>

#include<functional>

 

 

#define rep(i,n) for(int i=0;i<(n);i++)

 

using namespace std;

const int INF = 100000000;

const double EPS = 0.0000001;

typedef pair<int,int> P;



int n,m;



struct edge

{

	//どこから来た,コスト,速度制限

	int to,cost,ub;

	edge(int to,int cost,int ub) {

		this->to = to;

		this->cost = cost;

		this->ub = ub;

	}

};



vector<edge> G[103];

int s,g;

double dist[103][103][33];



typedef pair<double,int> PD;

typedef pair<PD,P> PP;



double dijkstra() {

	rep(i,103) rep(j,103) rep(k,33) dist[i][j][k]=INF;

	dist[s][0][0]=0;



	//最短距離 頂点 前の頂点 今の速さ

	priority_queue<PP,vector<PP>,greater<PP> > que;

	que.push(PP(PD(0,s),P(0,0)));



	while (!que.empty())

	{

		PP pp = que.top(); que.pop();

		int v = pp.first.second;



		int prev = pp.second.first;

		//今の速度

		int u = pp.second.second;



		//printf("[debug] %f,%d,%d,%d\n",pp.first.first,v,prev,u);



		if(dist[v][prev][u] < pp.first.first) continue;



		rep(i,G[v].size()) {

			edge e = G[v][i];

			if(e.to == prev) continue;

			for(int j=-1;j<=1;j++) {

				if(j+u<=0 || u+j > e.ub) continue;





				if(dist[e.to][v][u+j] > dist[v][prev][u] + (1.0*e.cost/(u+j))) {

					dist[e.to][v][u+j] = dist[v][prev][u] + (1.0*e.cost/(u+j));



					que.push(PP(PD(dist[e.to][v][u+j],e.to),P(v,u+j)));

				}

			}

		}



	}

	double ans=INF;

	rep(i,103) ans=min(ans,dist[g][i][1]);



	return ans;

	

}



void solve() {

	rep(i,103) G[i].clear();

	cin>>s>>g;

	rep(i,m) {

		int x,y,d,c;

		cin>>x>>y>>d>>c;

		G[x].push_back(edge(y,d,c));

		G[y].push_back(edge(x,d,c));

	}



	double ans;

	ans = dijkstra();

	if(ans==INF) {

		cout<<"unreachable"<<endl;

	}

	else

	{

		cout<<ans<<endl;

	}





}



int main() {

	while (cin>>n>>m)

	{

		if(n+m==0) return 0;

		solve();



	}







}

// Optimized solution to the same problem (faster):
#include <algorithm>

#include <functional>

#include <cmath>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <sstream>

#include <iostream>

#include <iomanip>

#include <vector>

#include <list>

#include <stack>

#include <queue>

#include <map>

#include <set>

#include <bitset>

#include <climits>



#define all(c) (c).begin(), (c).end()

#define rep(i,n) for(int i=0;i<(n);i++)

#define pb(e) push_back(e)

#define mp(a, b) make_pair(a, b)

#define fr first

#define sc second



const int INF=100000000;

int dx[4]={1,0,-1,0};

int dy[4]={0,1,0,-1};

using namespace std;

typedef pair<int ,int > P;

typedef long long ll;



template<class T>

bool chmin(T &a, const T &b) {

    if(a>b) {

        a=b;

        return true;

    }

    return false;

}

struct Edge {

    int to,d,c;

    Edge(int to=0,int d=0,int c=0) :

        to(to),d(d),c(c) {}

};



struct State {

    int v,u;

    int spd;

    double t;

    State(int v=0,int u=0,int spd=0,double t=0) :

        v(v),u(u),spd(spd),t(t){}



    bool operator<(const State &rhs) const {

        return t>rhs.t;

    }

};

int s,g;

int n,m;

vector<Edge> G[40];



double dijk() {

    // v,u,spd;

    double d[40][40][40];

    rep(i,40) rep(j,40) rep(k,40) d[i][j][k]=INF;

    //rep(i,40) d[s][i][1]=1;

    d[s][s][0]=0;



    priority_queue<State> que;

    que.push(State(s,s,0));

    while(que.size()) {

        State s=que.top(); que.pop();



        rep(i,G[s.v].size()) {

            Edge e=G[s.v][i];

            if(e.to==s.u) continue;

            for(int k=-1;k<=1;k++) {

                if(!(0<=s.spd+k&&s.spd+k<=e.c)) continue;

                if(s.spd+k<=0) continue;

                if(chmin(d[e.to][s.v][s.spd+k],d[s.v][s.u][s.spd]+1.0*e.d/(s.spd+k))) {

                    que.push(State(e.to,s.v,s.spd+k,d[e.to][s.v][s.spd+k]));

                }

            }

        }

    }

    double ret=INF;

    rep(i,40) chmin(ret,d[g][i][1]);



    return ret;



}



void solve() {

    rep(i,40) G[i].clear();

    cin>>s>>g;

    s--,g--;

    rep(i,m) {

        int x,y,d,c;

        cin>>x>>y>>d>>c;

        x--,y--;

        G[x].push_back(Edge(y,d,c));

        G[y].push_back(Edge(x,d,c));

    }

    double ans=dijk();

    if(ans==INF) cout<<"unreachable"<<endl;

    else printf("%.10f\n",ans);

}



int main() {

    while(cin>>n>>m) {

        if(n==0) break;

        solve();

    }

    return 0;

}

// Fastest known solution for this problem: