#include <vector>
#include <iostream>
#include <utility>
#include <algorithm>
#include <string>
#include <deque>
#include <tuple>
#include <queue>
#include <functional>
#include <cmath>
#include <iomanip>
using namespace std;
typedef long long ll;
double cut[32][32][32];
pair<int,int> way[32][32];
int main() {
	int n, m, s, g;
	while(cin >> n >> m, n) {
		cin >> s >> g;
		fill((double*)cut, (double*)cut + 32 * 1024, 1e100);
		fill((pair<int,int>*)way, (pair<int,int>*)way + 1024,make_pair(0,0));
		for (int i = 0; i < m; i++) {
			int x, y, d, c;
			cin >> x >> y >> d >> c;
			way[x][y] = way[y][x] = make_pair(d,c);
		}
		priority_queue<tuple<double, int, int, int>, vector<tuple<double, int, int, int>>, greater<tuple<double, int, int, int>>> que;
		que.push(make_tuple(0., s, 1,0));
		while (!que.empty()&&(get<1>(que.top())!=g||get<2>(que.top())!=0)){
			auto a = que.top();
			que.pop();
			for (int i = 1; i <= n; i++) {
				if (way[get<1>(a)][i].second == 0)continue;
				if (i == get<1>(a)||i==get<3>(a))continue;
				if (get<2>(a)>way[get<1>(a)][i].second)continue;
				if (get<2>(a) == 0)continue;
				for (int j = max(0, get<2>(a)-1); j <= get<2>(a)+1; j++) {
					if (cut[i][j][get<1>(a)]>get<0>(a) + (double)way[get<1>(a)][i].first / get<2>(a)) {
						que.push(make_tuple(get<0>(a) + (double)way[get<1>(a)][i].first / get<2>(a), i, j,get<1>(a)));
						cut[i][j][get<1>(a)] = get<0>(a) + (double)way[get<1>(a)][i].first / get<2>(a);
					}
				}
			}
		}
		if (que.empty())cout << "unreachable" << endl;
		else cout << fixed << setprecision(10) << get<0>(que.top()) << endl;
	}
	return 0;
}