import java.util.*;import java.io.*;import java.math.*;
public class Main{
	//Don't have to see. start------------------------------------------
	static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	}
	static final int OBJECT_MEMORY = 1024;
	static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem.
	static PrintWriter out = new PrintWriter(System.out);
	static void flush(){out.flush();}
	static void myout(Object t){out.println(t);}
	static void myerr(Object t){System.err.print("debug:");System.err.println(t);}
	static String next(){return ii.next();}
	static int nextInt(){return Integer.parseInt(next());}
	static long nextLong(){return Long.parseLong(next());}
	static ArrayList<String> nextStrArray(){return myconv(next(), HAN);}
	static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);}
	static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	}
	static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	}
	static final int HAN = 8;
	static final int NL = 9;
	static final int NOCHAR = 0;
	static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	}
	static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	}
	public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	}
	//Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	}
	//Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);}
public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;}
	//Method addition frame end
} import java.util.*; util.* java import java.io.*; io.* java import java.math.*; math.* java public class Main{
	//Don't have to see. start------------------------------------------
	static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	}
	static final int OBJECT_MEMORY = 1024;
	static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem.
	static PrintWriter out = new PrintWriter(System.out);
	static void flush(){out.flush();}
	static void myout(Object t){out.println(t);}
	static void myerr(Object t){System.err.print("debug:");System.err.println(t);}
	static String next(){return ii.next();}
	static int nextInt(){return Integer.parseInt(next());}
	static long nextLong(){return Long.parseLong(next());}
	static ArrayList<String> nextStrArray(){return myconv(next(), HAN);}
	static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);}
	static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	}
	static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	}
	static final int HAN = 8;
	static final int NL = 9;
	static final int NOCHAR = 0;
	static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	}
	static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	}
	public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	}
	//Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	}
	//Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);}
public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;}
	//Method addition frame end
} Main static final int OBJECT_MEMORY = 1024; OBJECT_MEMORY 1024 static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem. ii new InputIterator() static PrintWriter out = new PrintWriter(System.out); out new PrintWriter(System.out) static final int HAN = 8; HAN 8 static final int NL = 9; NL 9 static final int NOCHAR = 0; NOCHAR 0 static void flush(){out.flush();} flush {out.flush();} out.flush() out.flush out static void myout(Object t){out.println(t);} myout {out.println(t);} out.println(t) out.println out t Object t t static void myerr(Object t){System.err.print("debug:");System.err.println(t);} myerr {System.err.print("debug:");System.err.println(t);} System.err.print("debug:") System.err.print System.err System System.err "debug:" System.err.println(t) System.err.println System.err System System.err t Object t t static String next(){return ii.next();} next {return ii.next();} return ii.next(); ii.next() ii.next ii static int nextInt(){return Integer.parseInt(next());} nextInt {return Integer.parseInt(next());} return Integer.parseInt(next()); Integer.parseInt(next()) Integer.parseInt Integer next() next static long nextLong(){return Long.parseLong(next());} nextLong {return Long.parseLong(next());} return Long.parseLong(next()); Long.parseLong(next()) Long.parseLong Long next() next static ArrayList<String> nextStrArray(){return myconv(next(), HAN);} nextStrArray {return myconv(next(), HAN);} return myconv(next(), HAN); myconv(next(), HAN) myconv next() next HAN static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);} nextCharArray {return myconv(next(), NOCHAR);} return myconv(next(), NOCHAR); myconv(next(), NOCHAR) myconv next() next NOCHAR static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	} nextIntArray {
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	} ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY); ret new ArrayList<Integer>(OBJECT_MEMORY) ArrayList<String> input = nextStrArray(); input nextStrArray() nextStrArray for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		} int i = 0; int i = 0; i 0 i < input.size() i input.size() input.size input i++ i++ i {
			ret.add(Integer.parseInt(input.get(i)));
		} {
			ret.add(Integer.parseInt(input.get(i)));
		} ret.add(Integer.parseInt(input.get(i))) ret.add ret Integer.parseInt(input.get(i)) Integer.parseInt Integer input.get(i) input.get input i return ret; ret static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	} nextLongArray {
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	} ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY); ret new ArrayList<Long>(OBJECT_MEMORY) ArrayList<String> input = nextStrArray(); input nextStrArray() nextStrArray for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		} int i = 0; int i = 0; i 0 i < input.size() i input.size() input.size input i++ i++ i {
			ret.add(Long.parseLong(input.get(i)));
		} {
			ret.add(Long.parseLong(input.get(i)));
		} ret.add(Long.parseLong(input.get(i))) ret.add ret Long.parseLong(input.get(i)) Long.parseLong Long input.get(i) input.get input i return ret; ret static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	} myconv {//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	} String joinString = ""; joinString "" if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		} no == HAN no HAN {
			joinString = " ";
		} joinString = " " joinString " " if(no == NL){
			joinString = "\n";
		} no == NL no NL {
			joinString = "\n";
		} joinString = "\n" joinString "\n" if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		} list instanceof String[] list String[] {
			return String.join(joinString,(String[])list);
		} return String.join(joinString,(String[])list); String.join(joinString,(String[])list) String.join String joinString (String[])list if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		} list instanceof ArrayList list ArrayList {
			return String.join(joinString,(ArrayList)list);
		} return String.join(joinString,(ArrayList)list); String.join(joinString,(ArrayList)list) String.join String joinString (ArrayList)list {
			throw new ClassCastException("Don't join");
		} throw new ClassCastException("Don't join"); new ClassCastException("Don't join") Object list list int no no static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	} myconv {//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	} String splitString = (no == NOCHAR) ? "" : " "; splitString (no == NOCHAR) ? "" : " " (no == NOCHAR) no NOCHAR "" " " return new ArrayList<String>(Arrays.asList(str.split(splitString))); new ArrayList<String>(Arrays.asList(str.split(splitString))) String str str int no no public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	} main {
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	} Runtime rt = Runtime.getRuntime(); rt Runtime.getRuntime() Runtime.getRuntime Runtime long mae = System.currentTimeMillis(); mae System.currentTimeMillis() System.currentTimeMillis System solve() solve flush() flush long ato = System.currentTimeMillis(); ato System.currentTimeMillis() System.currentTimeMillis System myerr("time : " + (ato - mae) + "ms") myerr "time : " + (ato - mae) + "ms" "time : " + (ato - mae) + "ms" "time : " (ato - mae) ato mae "ms" myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB") myerr "memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB" "memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB" "memory : " ((rt.totalMemory() - rt.freeMemory()) / 1024) (rt.totalMemory() - rt.freeMemory()) rt.totalMemory() rt.totalMemory rt rt.freeMemory() rt.freeMemory rt 1024 "KB" String[] args args //Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	} solve {//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	} ArrayList<Long> one = nextLongArray(); one nextLongArray() nextLongArray long A = one.get(0) - 1; A one.get(0) - 1 one.get(0) one.get one 0 1 long B = one.get(1); B one.get(1) one.get one 1 long C = one.get(2); C one.get(2) one.get one 2 long D = one.get(3); D one.get(3) one.get one 3 long BC = (B / C); BC (B / C) B C long BD = (B / D); BD (B / D) B D long BCD = (B / lcm(C, D)); BCD (B / lcm(C, D)) B lcm(C, D) lcm C D long Ball = B - (BC + BD) + BCD; Ball B - (BC + BD) + BCD B - (BC + BD) B (BC + BD) BC BD BCD long AC = (A / C); AC (A / C) A C long AD = (A / D); AD (A / D) A D long ACD = (A / lcm(C, D)); ACD (A / lcm(C, D)) A lcm(C, D) lcm C D long Aall = A - (AC + AD) + ACD; Aall A - (AC + AD) + ACD A - (AC + AD) A (AC + AD) AC AD ACD myout(Ball - Aall) myout Ball - Aall Ball Aall //Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);} lcm {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);} return Math.max(m,n) / gcd(m, n) * Math.min(m,n); Math.max(m,n) / gcd(m, n) * Math.min(m,n) Math.max(m,n) / gcd(m, n) Math.max(m,n) Math.max Math m n gcd(m, n) gcd m n Math.min(m,n) Math.min Math m n long m m long n n public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;} gcd {return n != 0 ? gcd(n, m % n) : m;} return n != 0 ? gcd(n, m % n) : m; n != 0 ? gcd(n, m % n) : m n != 0 n 0 gcd(n, m % n) gcd n m % n m n m long m m long n n static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	} InputIterator ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY); inputLine new ArrayList<String>(OBJECT_MEMORY) int index = 0; index 0 int max; max InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		} InputIterator {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		} BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br new BufferedReader(new InputStreamReader(System.in)) while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			} true {
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			} String read; read try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				} catch(IOException e){
					read = null;
				} IOException e {
					read = null;
				} read = null read null {
					read = br.readLine();
				} read = br.readLine() read br.readLine() br.readLine br if(read != null){
					inputLine.add(read);
				}else{
					break;
				} read != null read null {
					inputLine.add(read);
				} inputLine.add(read) inputLine.add inputLine read {
					break;
				} break; max = inputLine.size() max inputLine.size() inputLine.size inputLine boolean hasNext(){return (index < max);} hasNext {return (index < max);} return (index < max); (index < max) index max String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		} next {
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		} if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			} hasNext() hasNext {
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			} String returnStr = inputLine.get(index); returnStr inputLine.get(index) inputLine.get inputLine index index++ index return returnStr; returnStr {
				throw new IndexOutOfBoundsException("There is no more input");
			} throw new IndexOutOfBoundsException("There is no more input"); new IndexOutOfBoundsException("There is no more input") public class Main{
	//Don't have to see. start------------------------------------------
	static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	}
	static final int OBJECT_MEMORY = 1024;
	static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem.
	static PrintWriter out = new PrintWriter(System.out);
	static void flush(){out.flush();}
	static void myout(Object t){out.println(t);}
	static void myerr(Object t){System.err.print("debug:");System.err.println(t);}
	static String next(){return ii.next();}
	static int nextInt(){return Integer.parseInt(next());}
	static long nextLong(){return Long.parseLong(next());}
	static ArrayList<String> nextStrArray(){return myconv(next(), HAN);}
	static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);}
	static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	}
	static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	}
	static final int HAN = 8;
	static final int NL = 9;
	static final int NOCHAR = 0;
	static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	}
	static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	}
	public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	}
	//Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	}
	//Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);}
public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;}
	//Method addition frame end
} public class Main{
	//Don't have to see. start------------------------------------------
	static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	}
	static final int OBJECT_MEMORY = 1024;
	static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem.
	static PrintWriter out = new PrintWriter(System.out);
	static void flush(){out.flush();}
	static void myout(Object t){out.println(t);}
	static void myerr(Object t){System.err.print("debug:");System.err.println(t);}
	static String next(){return ii.next();}
	static int nextInt(){return Integer.parseInt(next());}
	static long nextLong(){return Long.parseLong(next());}
	static ArrayList<String> nextStrArray(){return myconv(next(), HAN);}
	static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);}
	static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	}
	static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	}
	static final int HAN = 8;
	static final int NL = 9;
	static final int NOCHAR = 0;
	static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	}
	static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	}
	public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	}
	//Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	}
	//Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);}
public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;}
	//Method addition frame end
} Main
import java.util.*;import java.io.*;import java.math.*;
public class Main{
	//Don't have to see. start------------------------------------------
	static class InputIterator{
		ArrayList<String> inputLine = new ArrayList<String>(OBJECT_MEMORY);
		int index = 0; int max;
		InputIterator(){
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String read;
				try{
					read = br.readLine();
				}catch(IOException e){
					read = null;
				}
				if(read != null){
					inputLine.add(read);
				}else{
					break;
				}
			}
			max = inputLine.size();
		}
		boolean hasNext(){return (index < max);}
		String next(){
			if(hasNext()){
				String returnStr = inputLine.get(index);
				index++;
				return returnStr;
			}else{
				throw new IndexOutOfBoundsException("There is no more input");
			}
		}
	}
	static final int OBJECT_MEMORY = 1024;
	static InputIterator ii = new InputIterator();//This class cannot be used in reactive problem.
	static PrintWriter out = new PrintWriter(System.out);
	static void flush(){out.flush();}
	static void myout(Object t){out.println(t);}
	static void myerr(Object t){System.err.print("debug:");System.err.println(t);}
	static String next(){return ii.next();}
	static int nextInt(){return Integer.parseInt(next());}
	static long nextLong(){return Long.parseLong(next());}
	static ArrayList<String> nextStrArray(){return myconv(next(), HAN);}
	static ArrayList<String> nextCharArray(){return myconv(next(), NOCHAR);}
	static ArrayList<Integer> nextIntArray(){
		ArrayList<Integer> ret = new ArrayList<Integer>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Integer.parseInt(input.get(i)));
		}
		return ret;
	}
	static ArrayList<Long> nextLongArray(){
		ArrayList<Long> ret = new ArrayList<Long>(OBJECT_MEMORY);
		ArrayList<String> input = nextStrArray();
		for(int i = 0; i < input.size(); i++){
			ret.add(Long.parseLong(input.get(i)));
		}
		return ret;
	}
	static final int HAN = 8;
	static final int NL = 9;
	static final int NOCHAR = 0;
	static String myconv(Object list, int no){//only join
		String joinString = "";
		if(no == HAN){
			joinString = " ";
		}else if(no == NL){
			joinString = "\n";
		}
		if(list instanceof String[]){
			return String.join(joinString,(String[])list);
		}else if(list instanceof ArrayList){
			return String.join(joinString,(ArrayList)list);
		}else{
			throw new ClassCastException("Don't join");
		}
	}
	static ArrayList<String> myconv(String str, int no){//only split
		String splitString = (no == NOCHAR) ? "" : " ";
		return new ArrayList<String>(Arrays.asList(str.split(splitString)));
	}
	public static void main(String[] args){
		Runtime rt = Runtime.getRuntime();
		long mae = System.currentTimeMillis();
		solve();flush();
		long ato = System.currentTimeMillis();
		myerr("time : " + (ato - mae) + "ms");
		myerr("memory : " + ((rt.totalMemory() - rt.freeMemory()) / 1024) + "KB");
	}
	//Don't have to see. end------------------------------------------
	static void solve(){//Here is the main function
		ArrayList<Long> one = nextLongArray();
		long A = one.get(0) - 1;
		long B = one.get(1);
		long C = one.get(2);
		long D = one.get(3);
		long BC = (B / C);
		long BD = (B / D);
		long BCD = (B / lcm(C, D));
		long Ball = B - (BC + BD) + BCD;

		long AC = (A / C);
		long AD = (A / D);
		long ACD = (A / lcm(C, D));
		long Aall = A - (AC + AD) + ACD;
		myout(Ball - Aall);

	}
	//Method addition frame start
public static long lcm(long m, long n) {return Math.max(m,n) / gcd(m, n) * Math.min(m,n);}
public static long gcd(long m, long n) {return n != 0 ? gcd(n, m % n) : m;}
	//Method addition frame end
}