#pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#if defined (__GNUC__)
#include<bits/stdc++.h>
#elif defined (_MSC_VER)
# include <__msvc_all_public_headers.hpp>
#endif

using namespace std;
//#define int long long
//using f80 = __float80;
using ll = long long;
using ull = unsigned long long;
const int INF = 1001001001;
const int MOD = 1000000007;
const long double PI = 3.141592653589793238462643383279;
#define endl '\n'
#define rep(i,n) repi(i,0,n)
#define repi(i,a,b) for(int i=int(a);i<int(b);++i)
#define rrep(i,n) rrepi(i,n-1,0-1)
#define rrepi(i,a,b) for(int i=int(a);i>int(b);--i)
#define SORT(obj) sort((obj).begin(), (obj).end())
#define RSORT(obj) sort((obj).begin(), (obj).end(), greater<>())
#define ALL(obj) (obj).begin(),(obj).end()
#define UNIQUE(v) SORT(v); v.erase( unique(v.begin(), v.end()), v.end() )
#define show(v) rep(i,v.size()){cout<<v[i]<<" ";}cout<<endl
#define MAX(x) *max_element(ALL(x))
#define MIN(x) *min_element(ALL(x))
#define EPS (1e-7)
#define INF (1e9)
//#define PI (acos(-1))
#define SZ(x) ((int)(x).size())
#define SUM(v,i) accumulate(ALL(v),i)
#define nSUM(n) ((n)+1)*(n)/2　//1〜nまでの総和を求める式
#define debugl(a) cout<<a<<endl
#define debug(a) cout<<a<<" "
#define deg_to_rad(deg) (((deg)/360)*2*PI)
#define push_buck emplace_back
#define PB push_back
#define MP make_pair
#define rad_to_deg(rad) (((rad)/2/PI)*360)
using vi = vector<int>;
int dx[ 4 ] = { 1,0,-1,0 };
int dy[ 4 ] = { 0,1,0,-1 };
template<class T>bool chmax( T &a , const T &b ) { if ( a < b ) { a = b; return 1; } return 0; }
template<class T>bool chmin( T &a , const T &b ) { if ( b < a ) { a = b; return 1; } return 0; }
template<class T> inline void Yes( T condition ) { if ( condition ) cout << "Yes" << endl; else cout << "No" << endl; }
template<class T> void print( const T &value ) { cout << value << '\n'; }
struct aaa { aaa( ) { cin.tie( nullptr ); ios::sync_with_stdio( false ); cout << fixed << setprecision( 20 ); }; }aaa;
//template <typename... Args>void IN(Args& ... args) {cin >>args;IN(args...);return;} //まとめて入力　IN(a,b,c,d...)

ull gcd( ull a , ull b ) { return b ? gcd( b , a % b ) : a; }//最大公約数
ull lcm( ull a , ull b ) { return a * b / gcd( a , b ); }	//最小公倍数

bool IsPrime( int num ) {
	if ( num < 2 ) return false;
	else if ( num == 2 ) return true;
	else if ( num % 2 == 0 ) return false; // 偶数はあらかじめ除く

	double sqrtNum = sqrt( num );
	for ( int i = 3; i <= sqrtNum; i += 2 ) {
		if ( num % i == 0 ) {
			// 素数ではない
			return false;
		}
	}

	// 素数である
	return true;
}

// n個の数字の最小公倍数
int nlcm( vector<int> numbers ) {
	int res;
	res = numbers[ 0 ];
	for ( int i = 1; i < numbers.size( ); i++ ) {
		res = lcm( res , numbers[ i ] );
	}
	return res;
}

 // n個の数字の最大公約数
int ngcd( vector<int> a ) {
	int res;
	res = a[ 0 ];
	for ( int i = 1; i < a.size( ) && res != 1; i++ ) {
		res = gcd( a[ i ] , res );
	}
	return res;
}

int digsum( int n ) {
	int res = 0;
	while ( n > 0 ) {
		res += n % 10; //桁和
		// res++;       桁数
		n /= 10;
	}
	return res;
}

struct mint {
	ll x;
	mint( ll x = 0 ) :x( x %MOD ) {}
	mint &operator+=( const mint a ) {
		if ( ( x += a.x ) >= MOD ) x -= MOD;
		return *this;
	}
	mint &operator-=( const mint a ) {
		if ( ( x += MOD - a.x ) >= MOD ) x -= MOD;
		return *this;
	}
	mint &operator*=( const mint a ) {
		( x *= a.x ) %= MOD;
		return *this;
	}
	mint operator+( const mint a ) const {
		mint res( *this );
		return res += a;
	}
	mint operator-( const mint a ) const {
		mint res( *this );
		return res -= a;
	}
	mint operator*( const mint a ) const {
		mint res( *this );
		return res *= a;
	}
	mint pow( ll t ) const {
		if ( !t ) return 1;
		mint a = pow( t >> 1 );
		//debug(a.x);

		a *= a;
		if ( t & 1 ) a *= *this;
		return a;
	}

	// for prime MOD
	mint inv( ) const {
		return pow( MOD - 2 );
	}
	mint &operator/=( const mint a ) {
		return ( *this ) *= a.inv( );
	}
	mint operator/( const mint a ) const {
		mint res( *this );
		return res /= a;
	}
};

mint ncr( ll n , ll a ) {
	mint x = 1 , y = 1;
	//rep(i, a) {
	for ( int i = 0; i < a; ++i ) {
		x *= n - i;
		y *= i + 1;
	}
	return x / y;
}

// a^n MOD を計算する
long long modpow( long long a , long long n , long long mod ) {
	long long res = 1;
	while ( n > 0 ) {
		if ( n & 1 ) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res;
}

//素因数分解
map<ll , ll> GetPrimeFactors( ll n ) {
	map<ll , ll> mp;
  // dived by 2, 3, 5, ...
	while ( n % 2 == 0 ) {
		++mp[ 2 ];
		n /= 2;
	}
	for ( int i = 3; i * i <= n; i += 2 ) {
		while ( n % i == 0 ) {
			++mp[ i ];
			n /= i;
		}
	}
	if ( n != 1 ) ++mp[ n ];
	return mp;
}

//約数全列挙
vector<int> enum_div( int n ) {
	vector<int> ret;
	for ( int i = 1; i * i <= n; ++i ) {
		if ( n % i == 0 ) {
			ret.push_back( i );
			if ( i != 1 && i * i != n ) {
				ret.push_back( n / i );
			}
		}
	}
	return ret;
}

//約数全列挙 set ver
set<ll> listDivisors( ll n ) {   // set版
	set<ll> divs;
	repi( i , 1 , ( ll )( sqrt( n ) + 1 ) ) {
	//FOR( i , 1 , ( ll )( sqrt( n ) + 1 ) ) {   // {1, n} を除く場合は2番目の引数を 2 にする
		if ( n % i == 0 ) {
			divs.insert( i );
			divs.insert( n / i );
		}
	}
	return divs;
}

//文字列中に存在する特定の文字の個数カウント
int stringcount( string s , char c ) { return count( s.cbegin( ) , s.cend( ) , c ); }

//int Factorial( int n ) {
//	int ans = 1;
//	while ( n > 1 ) {
//		ans *= n;
//		--n;
//	}
//	return ans;
//}
//
//int npr( int n , int r ) {
//	return Factorial( n ) / Factorial( n - r );
//}
//
//int ncr( int n , int r ) {
//	return npr( n , r ) / Factorial( r );
//}



void solve( ) {
	ll n , m , x , y , z , h , w , a , b , c , d;
	//string s , t , line;
	cin >> a >> b >> c >> d;
	a--;
	w = lcm( c , d );
	//debugl( w );
	cout << ( b - a ) - b / d + a / d - b / c + a / c + b / w - a / w;
	//debugl( ( b - a ) - b / d + a / d - b / c + a / c );
}


signed main( ) {
	solve( );
	return 0;
}

Measured memory_bytes: 256