Effective random permutation of n-sets-bits

In order to create a bit pattern with precisely set bits n, I know two practical methods, but they both have limitations that I don’t like.

First, you can list all possible dictionary values ​​that have many bits specified in a pre-computed table, and then generate a random index into this table to select a possible result. This is due to the fact that as the output size increases, the list of candidates' output data becomes almost inexpedient.

Alternatively, you can select ndisjoint bit positions in random order (for example, using partial Shuffle Fisher-Yates) and set only these bits. However, this approach calculates a random state in a much larger space than the number of possible results. For example, he may select the first and second bits from three, or he may separately select the second and first bits.

This second approach should consume more bits from a random number source than is strictly required. Since he selects the bits nin a certain order when their order is not important, this means that he makes an arbitrary difference between n!different ways of getting the same result and consumes no less than floor(log_2(n!))more bits than necessary.

Can this be avoided?

, , , , , n.


<code> w!  / (n! * (wn)!) </code> ( w - ), .

n w-1, w-2 .., <code> w!  / (wn)! </code>, <code> n! </code> , .

, n! , . , , . , , , n- .

+2
5

, :

?

, - . k RNG. , randint(limit), 0 limit-1 , k 32- int:

mask = 0;
for (j = 32 - k; j < 32; ++j) {
    r = randint(j+1);
    b = 1 << r;
    if (mask & b) mask |= (1 << j);
    else mask |= b;
}

, , , randint(). k > 16, 32 - k .

, ( ), , , . , :

for (i = k; i >= 1; --i) {
    while ((b = binomial(n, i)) > r) --n;
    buf[i-1] = n;
    r -= b;
}

buf [] 0 n-1 k- colex r. buf[i-1] = n mask |= (1 << n). binomial() - , (. this). , , .

+2

?

, . log (k!) .

(n k) = (n-1 k-1) + (n-1 k) . 0 (n k) -1. r. n- . j i, i-, r < (i-1 j-1) , (i-1 j-1), .

, ; 32- 16 , - 64 80 . , - .

n , 1 k/n. ( ), . k. . , , .

+1

[ :] , PRNG, . , PRNG. PRNG, , . PRNG . .

, PRNG, LCG PRNG, , , .

ETA: ++ next_permutation(). . . std:: next_permutation Explaination.

+1

3, i- .
i-1?

, : i- , , ,

0

, - w!/((w-n)! * n!) , , , , .

:

", , , , , n .

...

, , n! , . , , . , , , n- .

, n- k-. - . , , n k 4 3. , 4 , (0, 1, 2, 3), n, 3, k. n!/((k! * (nk)!). k- (2, 1, 0). 1 k- (3, 1, 0), ..

, k-index . , k- .

. Tablizing the Binomial Coeffieicent.

#, , , . . :

  • k- N, K . K- .

  • k- . , , . , , Pascal Triangle, .

  • k-. , .

  • Mark Dominus , . . , int. , , .

  • .NET # , ( ), . bool, InitTable, , true, , . , . , 4 . .

  • , , . , , 2 , .

, :

public void Test10Choose5()
{
   String S;
   int Loop;
   int N = 10;  // Total number of elements in the set.
   int K = 5;  // Total number of elements in each group.
   // Create the bin coeff object required to get all
   // the combos for this N choose K combination.
   BinCoeff<int> BC = new BinCoeff<int>(N, K, false);
   int NumCombos = BinCoeff<int>.GetBinCoeff(N, K);
   // The Kindexes array specifies the indexes for a lexigraphic element.
   int[] KIndexes = new int[K];
   StringBuilder SB = new StringBuilder();
   // Loop thru all the combinations for this N choose K case.
   for (int Combo = 0; Combo < NumCombos; Combo++)
   {
      // Get the k-indexes for this combination.  
      BC.GetKIndexes(Combo, KIndexes);
      // Verify that the Kindexes returned can be used to retrive the
      // rank or lexigraphic order of the KIndexes in the table.
      int Val = BC.GetIndex(true, KIndexes);
      if (Val != Combo)
      {
         S = "Val of " + Val.ToString() + " != Combo Value of " + Combo.ToString();
         Console.WriteLine(S);
      }
      SB.Remove(0, SB.Length);
      for (Loop = 0; Loop < K; Loop++)
      {
         SB.Append(KIndexes[Loop].ToString());
         if (Loop < K - 1)
            SB.Append(" ");
      }
      S = "KIndexes = " + SB.ToString();
      Console.WriteLine(S);
   }
}

, . n n!/((K! (N - k)!). k , , 1. k, 32. , N, N, N 0 N 1, 1 32 0, 32 32 . 32 1, 32.

, 32, 16 ( 32 - 601 080 390 ), 32- , . 64- , 64- . , long, 18 446 744 073 709 551 616, 2 ^ 64. n k, n 64, 64 32. 64 32 - 1,832,624,140,942,590,534 - 64 k , , , , , - . # .NET BigInteger. , .

PRNG, , Mersenne Twister TinyMT . ++ #. , C.

, Fisher-Yates, , - :

// Get 7 random cards.
ulong Card;
ulong SevenCardHand = 0;
for (int CardLoop = 0; CardLoop < 7; CardLoop++)
{
  do
  {
    // The card has a value of between 0 and 51.  So, get a random value and
    // left shift it into the proper bit position.  
    Card = (1UL << RandObj.Next(CardsInDeck));
  } while ((SevenCardHand & Card) != 0);
  SevenCardHand |= Card;
}

, ( , ), 7 52. 64- . .

As a side note, the best binomial coefficient calculator I found that works with very large numbers (he accurately calculated the case, which gave more than 15,000 digits as a result) can be found.

0
source

Source: https://habr.com/ru/post/1679363/


All Articles