protected void CreateShortcut()
{
/*
* If there are k nodes out of a total possible
* number of N ( =2^(160) ), the average distance
* between them is d_ave = N/k. So we want to select a distance
* that is at least N/k from us. We want to do this
* with prob(dist = d) ~ 1/d. We can do this by selecting
* a uniformly distributed p, and sample:
*
* d = d_ave(d_max/d_ave)^p
* = d_ave( 2^(p log d_max - p log d_ave) )
* = 2^( p log d_max + (1 - p) log d_ave )
*
* since we can go all the way around the ring d_max = N
* and: log d_ave = log N - log k, but k is the size of the network:
*
* d = 2^( p log N + (1 - p) log N - (1-p) log k)
* = 2^( log N - (1-p)log k)
*
*/
double logN = (double)(Address.MemSize * 8);
double logk = Math.Log( (double)_node.NetworkSize, 2.0 );
double p = _rand.NextDouble();
double ex = logN - (1.0 - p)*logk;
int ex_i = (int)Math.Floor(ex);
double ex_f = ex - Math.Floor(ex);
//Make sure 2^(ex_long+1) will fit in a long:
int ex_long = ex_i % 63;
int ex_big = ex_i - ex_long;
ulong dist_long = (ulong)Math.Pow(2.0, ex_long + ex_f);
//This is 2^(ex_big):
BigInteger big_one = 1;
BigInteger dist_big = big_one << ex_big;
BigInteger rand_dist = dist_big * dist_long;
// Add or subtract random distance to the current address
BigInteger t_add = _node.Address.ToBigInteger();
// Random number that is 0 or 1
if( _rand.Next(2) == 0 ) {
t_add += rand_dist;
}
else {
t_add -= rand_dist;
}
byte[] target_int = Address.ConvertToAddressBuffer(new BigInteger(t_add % Address.Full));
Address.SetClass(target_int, _node.Address.Class);
Address start = new AHAddress(target_int);
#if TRACE
if (ProtocolLog.SCO.Enabled) {
ProtocolLog.Write(ProtocolLog.SCO,
String.Format("SCO local: {0}, Selecting shortcut to create close to start: {1}.",
_node.Address, start));
}
#endif
//make a call to the target selector to find the optimal
_target_selector.ComputeCandidates(start, (int) Math.Ceiling(logk), CreateShortcutCallback, null);
}