Это является расточительных счетные факториалов непрерывно, как, что, так как вы дублируя работу в x!
, когда вы делаете (x+1)!
, (x+2)!
и так далее.
Один из подходов заключается в поддержании список факториалов в пределах заданного диапазона (например, все 64-битных беззнаковых факториалов) и просто сравнить его с этим. Учитывая, насколько быстрые факториалы увеличивают стоимость, этот список не будет очень большим. На самом деле, вот C мета-программа, которая на самом деле генерирует функцию для вас:
#include <stdio.h>
int main (void) {
unsigned long long last = 1ULL, current = 2ULL, mult = 2ULL;
size_t szOut;
puts ("int isFactorial (unsigned long long num) {");
puts (" static const unsigned long long arr[] = {");
szOut = printf (" %lluULL,", last);
while (current/mult == last) {
if (szOut > 50)
szOut = printf ("\n ") - 1;
szOut += printf (" %lluULL,", current);
last = current;
current *= ++mult;
}
puts ("\n };");
puts (" static const size_t len = sizeof (arr)/sizeof (*arr);");
puts (" for (size_t idx = 0; idx < len; idx++)");
puts (" if (arr[idx] == num)");
puts (" return 1;");
puts (" return 0;");
puts ("}");
return 0;
}
При запуске, что вы получаете функцию:
int isFactorial (unsigned long long num) {
static const unsigned long long arr[] = {
1ULL, 2ULL, 6ULL, 24ULL, 120ULL, 720ULL, 5040ULL,
40320ULL, 362880ULL, 3628800ULL, 39916800ULL,
479001600ULL, 6227020800ULL, 87178291200ULL,
1307674368000ULL, 20922789888000ULL, 355687428096000ULL,
6402373705728000ULL, 121645100408832000ULL,
2432902008176640000ULL,
};
static const size_t len = sizeof (arr)/sizeof (*arr);
for (size_t idx = 0; idx < len; idx++)
if (arr[idx] == num)
return 1;
return 0;
}
, который является довольно коротким и эффективным, даже для 64-битные факториалы.
Если вы после чисто программным способом (без таблиц поиска), вы можете использовать свойство, что факторный число является:
1 x 2 x 3 x 4 x ... x (n-1) x n
для некоторого значения n
.
Следовательно, вы можете просто начать делиться своим тестовым номером на 2
, затем 3
затем 4
и так далее. Будет одна из двух вещей.
Во-первых, вы можете получить нецелый результат, в этом случае это не было факториал.
Во-вторых, вы можете в конечном итоге с 1
из раздела, и в этом случае это был факториал.
Предполагая, что ваши подразделения являются неотъемлемой частью, следующий код будет хорошей отправной точкой:
int isFactorial (unsigned long long num) {
unsigned long long currDiv = 2ULL;
while (num != 1ULL) {
if ((num % currDiv) != 0)
return 0;
num /= currDiv;
currDiv++;
}
return 1;
}
Однако для эффективности, лучший вариант, вероятно, первый один. Переместите стоимость расчета на фазу сборки, а не во время выполнения. Это стандартный трюк в случаях, когда стоимость вычисления значительна по сравнению с поиском таблицы.
Вы можете даже сделать его эффективным даже с использованием бинарного поиска таблицы поиска, но это, возможно, не обязательно, поскольку в нем всего двадцать элементов.
есть массив известных факториалов .... –
Я попробовал его. Извините, я забыл упомянуть об этом в вопросе. –
«Я попробовал». - и это значит? –