//ライブラリ
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>
#include <numeric>
#include <cmath>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <complex>
#include <string.h>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <iomanip>
#include <sys/time.h>
#include <tuple>
#include <random>
#include <functional>
using namespace std;

//ユーティリティ
#define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define reps(i,n) for(int i=1, i##_len=(n); i<=i##_len; ++i)
#define rrep(i,n) for(int i=n-1; i>=0; --i)
#define rreps(i,n) for(int i=n; i>0; --i)
#define vmax(v) *max_element(all(v))
#define vmin(v) *min_element(all(v))
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define uniq(v) (v).erase(unique((v).begin(), (v).end()), (v).end())

template<class T>bool chmax(T &former, const T &b) {if (former<b) {former=b;return true;} return false;}
template<class T>bool chmin(T &former, const T &b) {if (former>b) {former=b;return true;} return false;}

//型
typedef long long unsigned int ll;

//定数
const ll inf = (1e9+9);
const double pi = (acos(-1));
const ll mod = 1e9 + 7;
const double eps = 1e-8;

//セグメント木
//データ構造
template< typename Monoid >
struct SegmentTree {
  using F = function< Monoid(Monoid, Monoid) >;
 
  int sz;
  vector< Monoid > seg;
 
  const F f;
  const Monoid M1;
 
  SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
    sz = 1;
    while(sz < n) sz <<= 1;
    seg.assign(2 * sz, M1);
  }
 
  void set(int k, const Monoid &x) {
    seg[k + sz] = x;
  }
 
  void build() {
    for(int k = sz - 1; k > 0; k--) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }
 
  void update(int k, const Monoid &x) {
    k += sz;
    seg[k] = x;
    while(k >>= 1) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }
 
  Monoid query(int a, int b) {
    Monoid L = M1, R = M1;
    for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if(a & 1) L = f(L, seg[a++]);
      if(b & 1) R = f(seg[--b], R);
    }
    return f(L, R);
  }
 
  Monoid operator[](const int &k) const {
    return seg[k + sz];
  }
};

// 法の元の演算
// modを維持しながらべき乗。
ll mod_pow(ll x, ll n) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

// 逆元。オイラーの定理から？
// 有限体上での割り算に利用
// 3/4 = 3*(1/4) = 3x(4の逆数) = 3x3 mod 11
// 4の逆数はかけると1になるので、この場合は3
ll mod_inverse(ll x) {
    return mod_pow(x, mod-2);
}

const int fact_max_n = 1000000;
ll fact[fact_max_n];
ll fact_inv[fact_max_n];

void calc_fact() {
    fact[0] = 1;
    //階乗の算出。かける度にmodを取る。
    for (ll i = 1; i < fact_max_n; i++)
        fact[i] = (fact[i-1] * i) % mod;
    //階乗の逆元の算出。
    //1*2*3 => 1/(1*2*3)
    //1*2 => 1/(1*2*3)*3
    fact_inv[fact_max_n-1] = mod_inverse(fact[fact_max_n-1]);
    for (ll i = fact_max_n-2; i >= 0; i--) 
        fact_inv[i] = (fact_inv[i+1] * (i+1)) % mod;
}

//mod付き組み合わせ
// nCk= n!/(n-k)!k! を、modをかませながら演算
ll mod_comb(ll n, ll k) {
    if (n < 0 || k < 0 || n < k) return 0;
    return (fact[n] * fact_inv[k] % mod) * fact_inv[n-k] % mod;
}


//GCD
int gcd(int a, int b) {
	while(1) {
		if (a<b) swap(a, b);
		if(!b) break;
		a %= b;
	}
	return a;
}

int gcd(const vector<int> &list) {
	int a = list[0];
	for(auto i=1; i<list.size(); i++) {
		a = gcd(a, list[i]);	
	}
	return a;
}

int a, p;

void input() {
	cin >> a >> p;
	cin.ignore();
}

int solve() {
	return (a*3+p)/2;
}

int main() {
	input();
	cout << solve() << endl;
}	

Measured memory_bytes: 888