Видя, что вы говорите о числах, таких как 2 ^ 128 / (N!), Кажется, что в вашей задаче N будет довольно маленьким (N <35 согласно моим расчетам).Я предлагаю взять оригинальный алгоритм в качестве отправной точки;Сначала переключите направление цикла: </p>
i = 2;
while (i < N) {
swap A[N - 1 - i] and A[N - i + k % i]
k = k / i
i = i + 1
}
Теперь измените цикл, чтобы сделать несколько перестановок за одну итерацию.Я предполагаю, что скорость деления одинакова независимо от числа i, при условии, что i <2 ^ 32. <br>Разделить диапазон 2 ... N-1 на поддиапазоны так, чтобы произведение чисел в каждомподдиапазон меньше 2 ^ 32:
2, 3, 4, ..., 12: product is 479001600
13, 14, ..., 19: product is 253955520
20, 21, ..., 26: product is 3315312000
27, 28, ..., 32: product is 652458240
33, 34, 35: product is 39270
Затем разделите длинное число k на произведения вместо деления на i.Каждая итерация даст остаток (менее 2 ^ 32) и меньшее число k.Когда у вас есть остаток, вы можете работать с ним во внутреннем цикле, используя оригинальный алгоритм;который теперь будет быстрее, потому что он не требует длинного деления.
Вот некоторый код:
static const int rangeCount = 5;
static const int rangeLimit[rangeCount] = {13, 20, 27, 33, 36};
static uint32_t rangeProduct[rangeCount] = {
479001600,
253955520,
3315312000,
652458240,
39270
};
for (int rangeIndex = 0; rangeIndex < rangeCount; ++rangeIndex)
{
// The following two lines involve long division;
// math libraries probably calculate both quotient and remainder
// in one function call
uint32_t rangeRemainder = k % rangeProduct[rangeIndex];
k /= rangeProduct[rangeIndex];
// A range starts where the previous range ended
int rangeStart = (rangeIndex == 0) ? 2 : rangeLimit[rangeIndex - 1];
// Iterate over range
for (int i = rangeStart; i < rangeLimit[rangeIndex] && i < n; ++i)
{
// The following two lines involve a 32-bit division;
// it produces both quotient and remainder in one Pentium instruction
int remainder = rangeRemainder % i;
rangeRemainder /= i;
std::swap(permutation[n - 1 - i], permutation[n - i + remainder]);
}
}
Конечно, этот код можно расширить до более чем 128 бит.
Другая оптимизацияможет включать извлечение степеней 2 из произведений диапазонов;это может добавить небольшое ускорение, увеличив дальность.Не уверен, стоит ли это (возможно, для больших значений N, например, N = 1000).