#c #time-limiting
#c #ограничение по времени
Вопрос:
Программа должна найти количество цифр в факториале числа
#include <stdio.h>
#include <math.h>
int main()
{
int n = 0 , i , count = 0 , dig ;
double sum = 0, fact;
scanf("%d" , amp;n );
for(i=1;i<=n;i )
{
sum = sum log(i);
}
fact = (exp(sum));
while(fact!=0)
{
dig = ((int)fact%10);
count ;
fact = floor(fact/10);
}
printf("%dn",count);
return 0;
}
Не стесняйтесь комментировать внесение улучшений в этот код, поскольку у меня пока нет большого опыта в программировании.
Комментарии:
1. Может быть, использовать
log10()
для прямого вычисления количества цифр? (log10(1 * 2 * 3 *...* n) = log10(1) log10(2) log10(3) ... log10(N) = <[approximate] number of digits>
)2. не могли бы вы внести изменения в мой код и опубликовать его здесь?
Ответ №1:
Причина, по которой ваш код занимает так много времени, заключается в том, что после n
достижения значения около 180 значение fact
становится слишком большим для хранения в переменной с плавающей запятой двойной точности. Когда вы выполняете эту строку:
fact = (exp(sum));
вы в основном устанавливаете fact
значение infinity. В результате следующий while()
цикл никогда не завершается.
Также нет особого смысла вычислять логарифмы в вашем коде. Это только замедлит работу. Просто вычислите факториал в double
переменной и сбрасывайте его, когда он становится слишком большим. Например, так:
int factorial_digit_count(int n) {
int i, nd=1;
double f = 1.0;
for (i=2; i<=n; i ) {
f *= i;
if (f > 1.0E 100) {
f /= 1.0E 100;
nd = 100;
}
}
while (f > 1.0E 10) {
f /= 1.0E 10;
nd = 10;
}
while (f >= 10.0) {
f /= 10.0;
nd ;
}
return nd;
}
Ответ №2:
Предполагая, что вы не хотите использовать какие-либо математические вычисления, но хотите «перебирать» свой путь — так я бы сократил ваше время выполнения (и в основном очистил ваш код).
#include <stdio.h>
#include <math.h>
int main()
{
int n, fact = 1;
scanf("%d" , amp;n );
for (int i = 1; i < n; i )
fact *= i;
int sum = 0;
while (fact != 0)
{
fact /= 10;
sum
}
printf("%dn",count);
return 0;
}
Надеюсь, это ответ на ваш вопрос, удачи!
Ответ №3:
Существует простая взаимосвязь между базовым b
логарифмом числа и базовым b
представлением этого числа:
len(repr(x, b)) = 1 floor(log(x, b))
В частности, в базе 10 количество цифр в x равно 1 floor(log10(x))
. (Чтобы понять, почему это так, посмотрите на результат этой формулы для степеней 10.)
Теперь логарифм of a×b
— это сумма логарифмов a
и b
. Таким образом, логарифм of n!
— это просто сумма логарифмов целых чисел от 1 до n
. Если мы выполним это вычисление в базе 10, то мы можем легко извлечь длину десятичного разложения n!
.
Другими словами, если вы суммируете log10
каждое значение вместо log
, то вы можете избавиться от:
fact = (exp(sum));
и
while(fact!=0)
{
dig = ((int)fact%10);
count ;
fact = floor(fact/10);
}
и просто выводите 1 floor(sum)
.
Теоретически это может привести к ошибке округления. Однако вам нужно будет выполнить очень много логарифмов, чтобы значение ошибки распространилось достаточно, чтобы создать ошибку в вычислении. (Не сказать, что это не может произойти. Но если это произойдет, n
это действительно очень большое число.)
Комментарии:
1. Извините, но я не понимаю, что нужно удалить из моего кода…… Не могли бы вы, пожалуйста, внести изменения в мой код и вставить его сюда?
2. @aryan: вы удаляете код, который я процитировал, меняете log на log10 и печатаете то, что я сказал вам печатать. Вы должны быть в состоянии сделать это, если хотите ответить на вызов программирования. Но для вас важнее понять, что такое логарифм и как его можно использовать, потому что это позволит вам получить ответ самостоятельно. Программирование — это не копирование решений.
3. Большое вам спасибо…. За помощь, а также за то, что вы не кормили меня с ложечки готовым кодом, хотя мне и не нужно было много, но ваши слова тронули меня. Я впервые здесь, в Stack OverFlow, и я надеюсь, что однажды даже я смогу ответить на сомнения других людей