#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp> // Common file
#include <ext/pb_ds/tree_policy.hpp> // Including tree_order_statistics_node_update
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace std;
//using namespace _gnu_pbds;
#define pb push_back
// #define INT_MAX 1000000000 this is wrong as INT_MAX is already included in header<climits> and  2147483647  
// #define INT_MIN -1000000000
#define INF 1000000000
#define LL_MAX 1000000000000000000
#define LL_MIN -1000000000000000000
#define mod1 1000000007
#define ll long long 
#define ld long double
#define vi vector <int>
#define vvi vector <vector<int>>
#define vll vector<long long>
#define vvl vector <vector<long long>>
#define pii pair<int,int>
#define pll pair<long,long>
#define vpii vector<pair<int,int>>
#define pld pair<ld,ld>
#define vpll vector<pair<ll,ll>>
#define vpld vector<pair<ld,ld>>
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define ff first
#define ss second
#define lb lower_bound
#define ub upper_bound
#define sz(a) (int)a.size()

template<class T> bool ckmin(T& a, const T& b) { 
	return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { 
	return a < b ? a = b, 1 : 0; } 
constexpr int pct(int x) { return __builtin_popcount(x); } 
constexpr int bits(int x) { return 31-__builtin_clz(x); } // floor(log2(x))

template<class T>
T binpow(T a, T b, T m) {
    a %= m;
    long long res = 1;
    while (b > 0) {
        if (b & 1)
            res = res * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return res;
}
/*struct item{
    int m,c;
};					// change item according to the question;
struct segtree{
	int size;
	//vector<ll>opeations
	vector<item>values;
	void intit(int n){
		size=1;
		while(size<n)size*=2;
		//operations.assign(2*size,0);
		values.resize(2*size);
	}
    item merge(item a,item b){
        if(a.m<b.m)return a;
        if(b.m<a.m)return b;
        if(a.m==b.m)return {a.m,a.c+b.c}; 
    }
    item single(int v){
        return {v,1};
    }
    item NEUTRAL_ELEMENT={INF,1};
    void build(vi &a,int x,int lx,int rx){
        if(rx-lx==1){
            if(lx<sz(a)){
                values[x]=single(a[lx]);
            }
            return;
        }
        int m=(lx+rx)/2;
        build(a,2*x+1,lx,m);
        build(a,2*x+2,m,rx);
        values[x]=merge(values[2*x+1],values[2*x+2]);
    }
    void build(vi &a){
        build(a,0,0,size);
    }
        ll NO_OPERATION=0;			//change these according to the mass change operation
    ll NEUTRAL_ELEMENT=LL_MIN;

    ll modify_op(ll a,ll b,ll len){
        if(b==NO_OPERATION)return a;
        return len-a;
    }
    ll calc_op(ll a,ll b){
        return (a+b);
    }
    void apply_mod_op(ll &a,ll b,ll len){
        a=modify_op(a,b,len);
    }
    void propagate(int x,int lx,int rx){//,int l,int r){
        if(rx-lx==1)return;
        
        int m=(lx+rx)/2;
        
        apply_mod_op(values[2*x+1],operations[x],m-lx);
        apply_mod_op(operations[2*x+1],operations[x],1);
        apply_mod_op(operations[2*x+2],operations[x],1);     
        apply_mod_op(values[2*x+2],operations[x],rx-m);

        operations[x]=NO_OPERATION;
    }
    
    void modify(int l,int r,int x,int lx,int rx){
        propagate(x,lx,rx);
        if(lx>=r||rx<=l)return;
        if(l<=lx && rx<=r){
            apply_mod_op(operations[x],1,1);
            apply_mod_op(values[x],1,rx-lx);
            return;
        }
        int m=(lx+rx)/2;
        modify(l,r,2*x+1,lx,m);
        modify(l,r,2*x+2,m,rx);
        values[x]=calc_op(values[2*x+1],values[2*x+2]);
    }
    void modify(int l,int r){
        modify(l,r,0,0,size);
    }
    int find(int k,int x,int lx,int rx){
        propagate(x,lx,rx);
        if(rx-lx==1){
            return lx;
        }
        int m=(lx+rx)/2;
        int sl=values[2*x+1];
        if(k<sl){
            return find(k,2*x+1,lx,m);
        }else{
            return find(k-sl,2*x+2,m,rx);
        }
    }
    int find(int k){
        return find(k,0,0,size);
    }

    ll calc(int l,int r,int x,int lx,int rx){
        propagate(x,lx,rx);
        if(lx>=r||rx<=l)return NEUTRAL_ELEMENT;
        if(lx>=l && rx<=r)return values[x];
        int m=(lx+rx)/2;
        auto m1=calc(l,r,2*x+1,lx,m);
        auto m2=calc(l,r,2*x+2,m,rx);
        auto res=calc_op(m1,m2);
        return res;
    }
    ll calc(int l,int r){
        return calc(l,r,0,0,size);
    }
    void set(int i,int v,int x,int lx,int rx){
        if(rx-lx==1){
            values[x]=single(v);
            return;
        }
        int m=(lx+rx)/2;
        if(i<m){
            set(i,v,2*x+1,lx,m);
        }else{
            set(i,v,2*x+2,m,rx);
        }
        values[x]=merge(values[2*x+1],values[2*x+2]);
    }
    void set(int i,int v){
        set(i,v,0,0,size);
    }
    item calc(int l,int r,int x,int lx,int rx){
        if(lx>=r||rx<=l)return NEUTRAL_ELEMENT;
        if(l<=lx && rx<=r)return values[x];
        int m=(lx+rx)/2;
        item s1=calc(l,r,2*x+1,lx,m);
        item s2=calc(l,r,2*x+2,m,rx);
        return merge(s1,s2);
    }
    item calc(int l,int r){
        return calc(l,r,0,0,size);
    }
};*/
/*int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
string ds="RLDU";
 
int n,m; 												//for solving grrid problems;
bool possible(int x,int y){
 	//cout<<n<<" "<<m<<" "<<x<<" "<<y<<" possible"<<endl;
 
    return (x<n&&x>=0&&y<m&&y>=0);
}*/
/*here we cand do just x+dx[i],y+dx[i] to move the four 
directions and ds helps if we want to record path.
we can easily extend it to include four diagonals*/
int main(){
	string s;
    cin>>s;
    int n=s.length();
    ll sum=0;
    for(int i=0;i<n;i++){
        sum+=(s[i]-'0');
    }
    if(sum%9==0)cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}
/* stuff you should look for
    * int overflow, array bounds
    * special cases (n=1?), set tle
    * do smth instead of nothing and stay organized
*/



Measured memory_bytes: 3720