#include<iostream>
#include<stdlib.h>
#include<vector>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<map>
#include<math.h>
#include<iomanip>
#include<set>

#define rep(i,n) for(ll i = 0; i < (ll)n; i++)
#define swap(a,b) a^=b;b^=a;a^=b;
//#define for(i,a,b) for (ll i=(a);i<(ll)b; i++)
#define print(x) std::cout << x << std::endl;

using namespace std;

typedef long long ll;

template<class T, class U> std::string replace(std::string s, const T& target, const U& replacement, bool replace_first = 0, bool replace_empty = 0);
bool isContain(int value, int under, int top);
vector<int> range(int x);

int get_ab(string str) {
	bool isA = false;
	int res = 0;
	if (str[0] == 'A') isA = true;
	for (int i = 1; i < str.length(); i++) {
		if (isA && str[i] == 'B') { res++; isA = false; }
		else if (str[i] == 'A') isA = true;
		else isA = false;
	}
	return res;
}

vector<bool> isVisited;
vector<int> Accu;
vector<vector<int>> Datas;
int N;

void DEF(int pos,int sum) {
	bool all_visited = true;
	rep(i,N) 
		if (isVisited[i] == false) {
			all_visited = false;
			break;
		}

	Accu[pos] = sum;

	rep(i, N) {
		if (isVisited[i] == true) continue; //すでに訪れている
		if (Datas[pos][i] == -1)  continue; //繋がっていない
		isVisited[i] = true;
		DEF(i, sum + Datas[pos][i]);
	}
}


int main(void) {
	//Program Start	

	int N, K;
	cin >> N >> K;

	double ans = 0;

	for (int i = 1; i <= N; i++) {
		int j = 0;
		for (j = 0;; j++) {
			if (i * pow(2, j) >= K) break;
		}
		ans += 1.0 / (double)pow(2,j);
	}

	ans /= (double)N;

	printf("%.12f", ans);

	/*
	cin >> N;

	Datas.resize(N);
	rep(i, N) Datas[i].resize(N);

	rep(i, N) 
		rep(j, N)
			Datas[i][j] = -1;

	int u, v, w;
	rep(i, N - 1) {
		cin >> u >> v >> w;
		Datas[u - 1][v - 1] = w;
		Datas[v - 1][u - 1] = w;
	}

	isVisited.resize(N);
	
	Accu.resize(N);

	isVisited[0] = true;
	DEF(0, 0);

	rep(i, N) {
		if (Accu[i] % 2 == 0) printf("1\n");
		else printf("0\n");
	}
	*/

ProgramEndPointLabel:;


	//Program End
	system("pause");

	return 0;
}


vector<int> range(int y) {
	vector<int> result(y);
	for (int i = 0; i < y; i++)
		result[i] = i;
	return result;
}

bool isContain(int value, int under, int top) {
	if (under <= value && value <= top) return true;
	return false;
}

template<class T, class U> std::string replace(std::string s, const T& target, const U& replacement, bool replace_first, bool replace_empty) {
	using S = std::string;
	using C = std::string::value_type;
	using N = std::string::size_type;
	struct {
		auto len(const S& s) { return s.size(); }
		auto len(const C* p) { return std::char_traits<C>::length(p); }
		auto len(const C  c) { return 1; }
		auto sub(S* s, const S& t, N pos, N len) { s->replace(pos, len, t); }
		auto sub(S* s, const C* t, N pos, N len) { s->replace(pos, len, t); }
		auto sub(S* s, const C  t, N pos, N len) { s->replace(pos, len, 1, t); }
		auto ins(S* s, const S& t, N pos) { s->insert(pos, t); }
		auto ins(S* s, const C* t, N pos) { s->insert(pos, t); }
		auto ins(S* s, const C  t, N pos) { s->insert(pos, 1, t); }
	} util;

	N target_length = util.len(target);
	N replacement_length = util.len(replacement);
	if (target_length == 0) {
		if (!replace_empty || replacement_length == 0) return s;
		N n = s.size() + replacement_length * (1 + s.size());
		s.reserve(!replace_first ? n : s.size() + replacement_length);
		for (N i = 0; i < n; i += 1 + replacement_length) {
			util.ins(&s, replacement, i);
			if (replace_first) break;
		}
		return s;
	}

	N pos = 0;
	while ((pos = s.find(target, pos)) != std::string::npos) {
		util.sub(&s, replacement, pos, target_length);
		if (replace_first) return s;
		pos += replacement_length;
	}
	return s;
}


Measured memory_bytes: 504