Как уменьшить этот фрагмент кода, чтобы избежать TLE

#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, и я надеюсь, что однажды даже я смогу ответить на сомнения других людей