0

I am new to Assembly Inline in C. I have to solve the following problem with the inline assembler of Visual Studio:

Input: a DWORD (the number N, N≤ 6)

Output: a vector of DWORD (all permutations, see description in the code), a DWORD (the number of permutations)


/*Description: Generate all permutations of the first N natural numbers.
              The permutations generated must be inserted within a single
              array of integers. For example, if N = 3, the array must contain:
              {1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1}.*/

#include <stdio.h>


void main()
{
// Variables
int N=4;    // number of integers (try with values ​​<= 6)
int Perm[4326]; // array permutations: size is sufficient for N <= 6
int Num;    // At the end it must contain the number of permutations generated

// asm block
    __asm
    {
        XOR EAX, EAX    //N
        MOV ECX, 1      //Counter
        MOV EDX, 1      //Value of integers <= N

        MOV EAX, N
L1:
        MOV Perm[ECX*4-4], EDX
        INC EDX
        INC ECX
        CMP EDX, EAX
        JLE L1
    }

// Print on video
    {
        int i,j,k;
        printf("Permutations of the first %d natural numbers\n",N);
        for (i=k=0;i<Num;i++)
        {
            for (j=0;j<N;j++)
            {
                printf("%3d",Perm[k++]);
            }
            printf("\n");
        }
    }
}

I tried to solve this problem but I can't find a solution.

Can anyone help me?

ilMichigan
  • 49
  • 5

1 Answers1

2

Let's start with the basic, how to do the maths.

We'll go with very simple maths.

When you have to list all possible combinations of n distinct objects, we should first define a path to do so. At first, we could consider the combinations with one, two and three objects (n ∈ {1,2,3}), let's go with the objects A, B and C :

  1. For only one object, A, we have only one possible combination, A

  2. For two objects, A and B, we have two possible combinations, [ A, B ] and [ B, A ]

  3. With three objects, we have then six possible combinations,

    [ A, B, C ] [ A, C, B ]

    [ B, A, C ] [ B, C, A ]

    [ C, A, B ] [ C, B, A ]

What do we see here ?

  1. That the number of possible combinations depends directly from the number of objects
  2. From one object to two objects, we double the number of combinations (1 x 2)
  3. From two objects to three objects, we triple the number of combinations (2 x 3)

If we take the combinations for three objects, we can clearly see that it is a combinations between object C and the combinations of two objects :

  [ A, B, C ] [ A, C, B ]

  [ B, A, C ] [ B, C, A ]

  [ C, A, B ] [ C, B, A ]

So we can see than incrementing n gives us n x ( n - 1 number of possible combinations). Consequently, the number of possible combinations for any n is factorial(n). If we look closely to the combinations of three objects, we can guess a path for an adequate algorithm to produce all n combinations :

  [ A, B, C ]

  [ B, A, C ]

  [ A, C, B ]

  [ B, C, A ]

  [ C, A, B ]

  [ C, B, A ]

We can see a pattern here, we have the two initial combinations [ A, B ] and [ B, A ] to which C is added, then we have at the same two preceding combinations but this time the second and the third elements are switched ( C is in the "middle" ), and , at new the same two preceding combinations but this time the first and the second elements are switched ( C is at the "start" ). We can then repeat the same pattern with four objects:

  1. Simply add D to the six initial combinations.
  2. Then take this six resulting combinations and add them at new with a switch of their third and fourth element.
  3. Then take this six resulting combinations and add them at new with a switch of their second and third element.
  4. Then take this six resulting combinations and add them at new with a switch of their first and second element.

The pseudo code we can asses from that, with all of our objects in an "objects" collection :

Set n to 0
Create empty collection "combinations"
For each object in "objects"
  If n > 0 Then
     Include current object in all combinations of "combinations"
     Set indice to n
     Copy "combinations" to new collection "local combinations"
     While indice > 0
        Create empty collection "new combinations"
        For each combination in "local combinations"
          Create combination witch switch of indice + 1 and indice element of current combination in "new combinations"
        decrement indice 
        Add all combinations of "new combinations" to "combinations"
        If Indice > 0 Then Replace the content of "local combinations" with all combinations of "new combinations" 
  Else
     Create combination with the current object in "combinations"
  Increment n

We have here an estime complexity of O(Factorial(n)) as we iterate n times and with each iteration we iterates n - 1 times, with n as the number of objects.

Before implementing that in assembly, let's go with C for clarity :

#include <stdio.h>
// There is no standard factorial function in C, lets write a basic one. 
// Considering its limited range, note that a table of known factorials would 
// be far better for perfomance 
unsigned int factorial(unsigned int pNumber) {
   unsigned int lResult = pNumber;
   if (pNumber > 7) {
      // We should not compute that above int32 capacity (max fact 12) and sould not take more than a few kilobytes on the stack, so 7 at max.
      return 0; // If output < pNumber that's mean the function failed 
   }
   while(--pNumber > 0) lResult *= pNumber;
   return lResult;
}
int main(int nbargs, char *args[]) {
  // First, define our number objects, we're going with 4 as an example
  unsigned int number_of_objects = 4;
  // Set n to 0 : Our expected number of objects at the end
  unsigned int n = 0;
  // Create empty collection "combinations" : we need to store "factorial(number_of_objects) * number_of_objects" unsigned int in the end, we take that on the stack
  unsigned int combinations_number = 0;
#ifdef _MSC_VER
  unsigned int all_combinations[32000][6];
#else
  unsigned int all_combinations[factorial(number_of_objects)][number_of_objects];
#endif
  // For each object in "objects" : We have to loop on our objects, as it is simply successive integers, we go for a simple loop 
  for (unsigned int object = 1; object <= number_of_objects; object++) {
    // If n > 0 Then : 
    if (n > 0) {
      // Include current object in all combinations of "combinations" : 
      unsigned int indice;
      for (indice = 0; indice < combinations_number; indice++) {
        all_combinations[indice][n] = object;
      }
      // Set indice to n :
      indice = n;
      // Copy "combinations" to new collection "local combinations" :
      unsigned int start = 0;
      unsigned int combinations_number_to_add = combinations_number;
      // While indice > 0
      while(indice > 0) {
        // Create empty collection "new combinations" :
        // For each combination in "local combinations" :
        for (unsigned int local_indice = start; local_indice < start + combinations_number_to_add; local_indice++) {
           // Create combination witch switch of indice + 1 and indice element of current combination in "new combinations" :
           for (unsigned int copy_indice = 0; copy_indice <= n ; copy_indice++) {
             all_combinations[combinations_number][copy_indice] = all_combinations[local_indice][copy_indice];
           }
           all_combinations[combinations_number][indice - 1] = all_combinations[local_indice][indice];
           all_combinations[combinations_number][indice] = all_combinations[local_indice][indice - 1];
           combinations_number++;
        }
        // decrement indice  :
        indice--;
        // Add all combinations of "new combinations" to "combinations" :
        start+=combinations_number_to_add;
        // If Indice > 0 Then Replace the content of "local combinations" with all combinations of "new combinations"  :
      };
    // Else :
    } else {
      // Create combination with the current object in "combinations" : Simply store the "object" in all_combinations 
      all_combinations[combinations_number++][0] = object;
    }
    // Increment n:
    n++;
  }
  // Simple display
  printf("%d \n", combinations_number);
  for (n = 0; n < combinations_number; n++) {
    for (unsigned int nb = 0; nb < number_of_objects; nb++) {
      printf("%d ", all_combinations[n][nb]);
    }
    printf("\n");
  }
}

As you can see, we have eliminate here the need of a "local/new" collections with simple array maths, as we simply have integers as "objects".

As i shouldn't do all your homework, i let you how to adapt this C code in MSVC ASM. At least try.

Zilog80
  • 2,534
  • 2
  • 15
  • 20