Reputation: 1148
I am writing a program that cyphers plaintext using a substitution cypher. I am trying to calcuate the total number of, for lack of a better term "cypher" permutations. What I mean is, I want to calculate all the possible permutations that do not substitute the plaintext as itself. Meaning 00000000(NULL) cannot be substituted as 00000000(NULL). I know I can generate all the possible permutations of a block of n size in the following way.
n(size) = 3 (1, 2, 3 are the unique values being permutated)
The problem is, only 231 and 312 do not substitute plaintext as itself. I could use conditional statments to determine if a permutation is valid but I would prefer a way that calculates only the valid permutations. I am hoping that there is already a simple way to do this but I do not know how to word the question in order to google it. So to sum up my question, I need an efficient way to calculate all the possible cypher permutations that do not leave plaintext unsubstituted.
The following code will generate all possible permutations for n number of unique values. But it will only work when n! is representable using a normal integer data type.
#include <stdlib.h>
#include <stdio.h>
int main()
{
int current_perm = 0;
int num_perms = 1;
int cypher_size = 0;
int buffer = 0;
int *cypher = NULL;
printf("Input the number of unique values in the cypher(The cypher's size) : ");
scanf("%i", &cypher_size);
if((cypher = malloc(sizeof(int)*(cypher_size+1))) == NULL)
{
perror("ERROR: Failed to allocate memory for the cypher ");
return 1;
}
int i = cypher_size;
int j = 0;
while(i > 0)
{
cypher[i-1] = i;
num_perms *= i;
i--;
}
for(j = 0; j < cypher_size; j++) {printf("%i ", cypher[j]);}
printf("\n");
for(current_perm = 1; current_perm < num_perms;)
{
for(i = 0; i < cypher_size-1; i++, current_perm++)
{
buffer = cypher[i+1];
cypher[i+1] = cypher[i];
cypher[i] = buffer;
for(j = 0; j < cypher_size; j++) {printf("%i ", cypher[j]);}
printf("\n");
}
}
}
Upvotes: 0
Views: 102
Reputation: 65498
Permutations with no fixed points are called derangements. The following C code uses the alternating sum formula from the Wikipedia link.
static int nder(int n) {
int m = 1;
int f = 1;
for (int k = n; k > 0; k--) {
f *= k;
m = f - m;
}
return m;
}
You can swap out ints for bignums or doubles. In the latter case, you should get an answer that's within a couple ulp of being accurate. If the answer won't fit in a double even, ln(n!/e) = ln(1) + ln(2) + ... + ln(n) - 1 = lgamma(n + 1.0) - 1.0
if you have lgamma
available in <math.h>
is an excellent approximation of the natural log of the number of derangements.
Upvotes: 2