#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <stack>
#include <list>
#include <utility>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
#include <climits>
#include <map>
#include <unordered_map>
#include <string.h>
#include<iomanip>
#include <iterator>
#include <locale>

#define all(a) a.begin(),a.end()
#define VV(T) vector<vector< T > >
#define rep(i,N) for(int i = 0; i <N; i++)
#define repsg(i,s,g) for(int i = s; i <g; i++)
#define name(x) #x


using namespace std;

const int INF = INT_MAX;
const long long INFL = 1LL<<40;
const double PI = atan(1)*4;
const long long MOD = pow(10,9)+7;
int dy[]={0, 0, 1, -1, 0};
int dx[]={1, -1, 0, 0, 0};

typedef long long ll,LL;
typedef vector<int> vint;
typedef vector<vector<int> > vvint;
typedef vector<long long> vll, vLL;
typedef vector<vector<long long> > vvll, vvLL;
typedef pair<int,int> pii;
typedef pair<LL, LL> pLL;


// vector入力
template<typename T>
istream& operator >> (istream& is, vector<T>& vec){
    for(T& x: vec) is >> x;
    return is;
}
// vector出力
template<typename T>
ostream& operator << (ostream& os, vector<T>& vec){
    for(int i=0; i<vec.size(); i++){
        os << vec[i] << ( i+1 == vec.size() ? "" : " " );
    }
    return os;
}

template< typename T >
struct edge{
    int src, to;T cost;
    edge(int to,T cost) :src(-1),to(to),cost(cost){}
    edge(int src, int to, T cost) :src(src),to(to),cost(cost){}edge
    &operator=(const int &x){
        to =x;
        return *this;
    }
    operator int() const{ return to;}
};

template< typename T >
using Edges =vector< edge<T> >;
template< typename T >
using WeightedGraph =vector< Edges<T> >;
using UnWeightedGraph =vector< vector<int> >;
template< typename T >
using Matrix =vector< vector<T> >;

struct UnionFind {
    // UnionFind u(n) 宣言
    // u.unionSet(x,y) 併合
    // u.findSet(x,y) -> {true, false}
    // u.root(x) xのroot. data[x]を参照。併合前はxそのもの、併合後は同一union
    vector<int> data;
    UnionFind(int size) : data(size, -1) { }
    bool unionSet(int x, int y) {
        x = root(x); y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        return x != y;
    }
    bool findSet(int x, int y) {
        return root(x) == root(y);
    }
    int root(int x) {
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    int size(int x) {
        return -data[root(x)];
    }
};

int main() {
    ll a,b;cin>>a>>b;
    
    if(a%2==0 && b%2==1){
        ll one_num = (b-a+1)/2;
        
        if(one_num%2==0) cout<<0<<endl;
        else cout<<1<<endl;
        return 0;
    }
    
    if(a%2==0 && b%2==0){
        
        ll one_num = (b-1 -a+1)/2;
        
        if(one_num%2 == 0){
            cout<<(b^0)<<endl;
        }else{
            cout<<(b^1)<<endl;
        }
        return 0;
    }
    
    if(a%2==1 && b%2==0){
        
        ll one_num = (b-1 -a-1+1)/2;
        
        if(one_num%2 == 0){
            cout<<(a^0^b)<<endl;
        }else{
            cout<<(a^1^b)<<endl;
        }
        return 0;
    }
    
    
    if(a%2==1 && b%2==1){
        
        ll one_num = (b -a-1+1)/2;
        
        if(one_num%2 == 0){
            cout<<(a^0)<<endl;
        }else{
            cout<<(a^1)<<endl;
        }
        return 0;
    }
    
    
    
    
    return 0;
}


/*
 1 ^ 2 = 0b11 = 3
 3 ^ 3 = 0;
 
 
 2^3^4 = 1^4 = 0b101 = 5

 nが偶数のとき、n^(n+1)は1になる。
 nが奇数のとき、n^(n+1)は繰り上がりに依存する。
 
 
(2n)^(2n+1) = 1
 
a,bの偶奇で分ける
偶,偶なら、1^1^1^1....1^b
偶、奇なら1^1^1^^1.....
奇、偶なら a^1^1....1^b
奇、奇なら a^1^1^...^1
 
 
 */


Measured memory_bytes: 256