#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstdio>

using namespace std;

const int MAX = 35;
const int INF = (1<<25);
int n,m;

struct Edge{
  int to;
  double dis,lim;
  Edge(int a, double b, double c):to(a),dis(b),lim(c){}
};

struct State{
  int pos,from;
  double speed,t;
  State(int a, double b, double c, int f):pos(a),speed(b),t(c),from(f){}
  bool operator < (const State& s) const{ return t > s.t;}
};

vector<Edge> E[MAX];
double T[MAX][MAX][MAX];
//T[i][j][k] := shortest time from i to j with speed k.


void init(){
  for(int i = 0; i < MAX; i++){
    for(int j = 0; j < MAX; j++)
      for(int k = 0; k < MAX; k++) T[i][j][k] = INF;
    E[i].clear();
  }
}

void input(){
  for(int i = 0; i < m; i++){
    int x,y;
    double d,c;
    cin >> x >> y >> d >> c;
    //   cout << x << " " << y << " " << d << " " << c << endl;
    E[x].push_back(Edge(y,d,c));
    E[y].push_back(Edge(x,d,c));
  }
}

void solve(int s, int g){

  priority_queue<State> Q;
  T[0][s][0] = 0;
  Q.push(State(s,0,0,0));

  while(!Q.empty()){
    State sta = Q.top();
    Q.pop();

    if(sta.t > T[sta.from][sta.pos][(int)sta.speed]) continue;

    for(int i = 0; i < E[sta.pos].size(); i++){
      int np = E[sta.pos][i].to;

      if(np == sta.from) continue;

      double sp[] = {-1,0,1};
      
      for(int j = 0; j < 3; j++){
	double ns = sta.speed+sp[j];
	if(ns <= 0 || ns > E[sta.pos][i].lim) continue;
	double nt = sta.t+E[sta.pos][i].dis/ns;
	if(T[sta.pos][np][(int)ns] > nt){
	  T[sta.pos][np][(int)ns] = nt;
	  Q.push(State(np,ns,nt,sta.pos));
	}
      }
    }
  }

  double ans = INF;

  for(int i = 0; i < MAX; i++)
    ans = min(ans,T[i][g][1]);
  

  if(ans == INF) cout << "unreachable" << endl;
  else printf("%.5f\n",ans);
}

int main(){

  while(cin >> n >> m && n+m){
    init();
    int s,g;
    cin >> s >> g;
    input();
    solve(s,g);
  }
  return 0;
}