Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Факториал, чето совсем не понятное задание 
:(
    Опции темы
EKoshelev
Дата 6.12.2004, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



maxim1000
Цитата

это практически никакого ускорения не даст


В том смысле, что считать сумму натуральных логарифмов по всем числам, а потом экспоненту по получившемуся. Может подскажешь, как разложить в ряд натуральный логарифм??? Там можно будет покумекать с многоразрядными делами потом...
Добавлено @ 16:08
А, ну понял.
Ну всё равно подскажи, как логарифм разложить.


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
maxim1000
Дата 6.12.2004, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



Цитата
В том смысле, что считать сумму натуральных логарифмов по всем числам, а потом экспоненту по получившемуся.

точнее в переходе от основания 10 к основанию e.
т.к. разница в сложности будет не больше одной операции деления
а вообще у логарифмов и подобных функций есть недостаток:
их результат очень часто бывает иррациональным, что приводит к неточности представления информации, в этом случае можно говорить только о приблизительном значении факториала, а значит, последним его цифрам доверять вообще не стоит...
Цитата
Может подскажешь, как разложить в ряд натуральный логарифм???

ряда не помню
к тому же есть разные ряды (Тейлора, Фурье)
если в Тейлора, то попробуй разложить ln(1+x) с помощью производных
кроме того, можно еще искать логарифм с помощью бисекции (правда, тогда придется реализовывать еще и операцию корня)


--------------------
qqq
PM WWW   Вверх
Aslan74
Дата 23.12.2004, 20:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 23.12.2004

Репутация: нет
Всего: нет



Надо выделить степени 2 и 5, встречающиеся в разложениях i = 2, n
на множители, и посчитать их степени отдельно. Потом, если степень 2 больше,
домножить на 2 в степени (степень 2 - степень 5), иначе 5 в степени (степень 5 - степень 2),
остаток пойдет в замыкающие нули.
Причем все умножения делаются только для последней цифры, без "длинной" арифметики

// отделить степени 2 и 5
// разбить число на C * 2^x2 * 5^x5
void Decompose(int& n, int& x2, int& x5)
{
for (x2 = 0; n%2 == 0; n/= 2, x2++);
for (x5 = 0; n%5 == 0; n/= 5, x5++);
}

// последняя ненулевая цифра n!
int Factorial(int n)
{
int res = 1, n2 = 0, n5 = 0;
for (int i = 2; i <= n; i++)
{
int r= i, x2, x5;
Decompose(r, x2, x5);
// отдельно домножаем степени 2 и 5, отдельно остальное
res= (res * r)%10; // взять последнюю цифру
n2+= x2;
n5+= x5;
}

// домножить на 2 или 5
if (n2 > n5)
for (int i = 0; i < n2-n5; i++)
res= (res * 2)%10; // взять последнюю цифру
else
if (n2 < n5)
for (int i = 0; i < n5-n2; i++)
res= (res * 5)%10; // взять последнюю цифру

return res;
}

P.S. Вычисляя n! для проверки обнаружил неприятный факт - в C Builder нет range checking (проверки переполнения)
Добавлено @ 20:35
Надо выделить степени 2 и 5, встречающиеся в разложениях i = 2, n
на множители, и посчитать их степени отдельно. Потом, если степень 2 больше, домножить на 2 в степени (степень 2 - степень 5), иначе 5 в степени (степень 5 - степень 2), остаток пойдет в замыкающие нули.
Причем все умножения делаются только для последней цифры, без "длинной" арифметики

// отделить степени 2 и 5
// разбить число на C * 2^x2 * 5^x5
void Decompose(int& n, int& x2, int& x5)
{
for (x2 = 0; n%2 == 0; n/= 2, x2++);
for (x5 = 0; n%5 == 0; n/= 5, x5++);
}

// последняя ненулевая цифра n!
int Factorial(int n)
{
int res = 1, n2 = 0, n5 = 0;
for (int i = 2; i <= n; i++)
{
int r= i, x2, x5;
Decompose(r, x2, x5);
// отдельно домножаем степени 2 и 5, отдельно остальное
res= (res * r)%10; // взять последнюю цифру
n2+= x2;
n5+= x5;
}

// домножить на 2 или 5
if (n2 > n5)
for (int i = 0; i < n2-n5; i++)
res= (res * 2)%10; // взять последнюю цифру
else
if (n2 < n5)
for (int i = 0; i < n5-n2; i++)
res= (res * 5)%10; // взять последнюю цифру

return res;
}

P.S. Вычисляя n! для проверки обнаружил неприятный факт - в C Builder нет range checking (проверки переполнения)
PM MAIL WWW ICQ Skype   Вверх
ovr2000
Дата 28.12.2004, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 30.11.2004

Репутация: нет
Всего: нет



Зачем же так сложно.
Всего, при перемножении n! будет встречено множителей с 5-ками: целая часть(n/5) + челая часть (n/25) и т.д.
Это меньше, чем Сумма от 1 до k(k понятно количество членов получившегося ряда) (n/5^i, i=1бл), а это геометрическая прогрессия, значит сумма(Выше) равна n*((1/5-1/5^(k+1))/(1-1/5) < n/4 (это оченка количества 5 во всем числе n!)
Если мы возьмем только первые степени двойки хотя бы от трех множителей из каждого десятка (а там ведь каждый второй - четный), то это будет n*0.3>n*/4=n*0.25
Значит посчитав 5-ки, можно будет отнять только 2 от четных чисел, не считая все множители
Чтобы зря не множить на 10, сразу отнимем их количество от 5, посчитав ряд (я имею в виду точно, а не приближенно)
В результате получится только три цикла, безо всякого вложения.
Например:
Код

Dim l, n, j As Integer
Dim i, k, t As Long

   t = CLng(NF)
   'Посчитаем количество 5
   k = 0
   While t >= 5
       t = Fix(t / 5)
       k = k + t
   Wend
   'Сразу не учтем целые 10
   t = CLng(NF)
   While t >= 10
       t = Fix(t / 10)
       k = k - t
   Wend
   
   n = 1
   l = 1
   For i = 2 To CLng(NF)
       l = l + 1
       If k = 0 Then
       Select Case l
           Case 5
           Case 10
               i = i + 1
               l = 1
           Case Else
               n = (n * l) Mod 10
           End Select
       Else
           Select Case l
           Case 2
               k = k - 1
           Case 4
               k = k - 1
               i = i + 1
               l = 5
               n = (n * 2) Mod 10
           Case 6
               k = k - 1
               n = (n * 3) Mod 10
           Case 10
               i = i + 1
               l = 1
           Case Else
               n = (n * l) Mod 10
           End Select
       End If
   Next
   n = n Mod 10
   Label3.Caption = str(n)

Добавлено @ 12:42
Заметьте, все вычисления идут с типом integer, кроме самого числа, которое может быть и очень большим
Добавлено @ 12:44
Да, кстати, третий раз делить на 2 (case 6) можно ненадо, т.к. мы уже отняли десятки
PM MAIL   Вверх
EKoshelev
Дата 28.12.2004, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



maxim1000, а по моему дак всё будет не только рациональным, но ещё и целым (ну или типа 123.999999934345793487), я на маленьких числах пробовал.

Aslan74 и ovr2000, я чё-то нить вашего разговора не поймал...


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
ovr2000
Дата 28.12.2004, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 30.11.2004

Репутация: нет
Всего: нет



Да суть в порядке чисел, в алгоритмах не используются числа больше сотни, за исключением самого числа N
Именно это я хотел сказать, т.к. все алгоритмы, кроме последних двух , при определенных числах N уходили в переполнение
PM MAIL   Вверх
GePo
Дата 29.12.2004, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 30.3.2003
Где: Москва

Репутация: нет
Всего: 3



да когда ж вы читать научитесь. Я уже давно написал решение, которое не переполняется, в нем есть все "гениальные идеи", которые потом всем пришли, и вообще то с математически доказанной верностью.
Похоже кому-то влом смотреть чье-то решение, кроме своего любимого... smile
--------------------
PM MAIL WWW   Вверх
EagleThePredator
Дата 24.11.2005, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 24.11.2005

Репутация: нет
Всего: нет



GePo
smile Спасибо за алгоритм! Мне очень помог.
PM   Вверх
sadovoya
Дата 15.10.2006, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 15.10.2006

Репутация: нет
Всего: нет



Может, это не совсем то, что нужно, но вдруг кому-нибудь пригодится. У меня есть небольшой пример на Delphi работы с очень большими (по порядку величины) целыми числами. Демонстрируется лишь сам принцип - разделение числа на значущую часть и порядок. Адрес: http://sadovoya.narod.ru/BIG_NUMBERS.ZIP
PM MAIL   Вверх
integral
Дата 28.10.2006, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 278
Регистрация: 3.7.2006
Где: Dnipropetrovs' ;k, Ukraine

Репутация: нет
Всего: нет



А вот пример на Java, на своей машине я смог вычеслить 100001! за 9 мин 24 сек:
private String calkFacktorial(String str)
    {
        if(str.equals("0")) return "1";
        BigInteger i = new BigInteger("1");
        BigInteger n = new BigInteger(str);
        BigInteger result = new BigInteger("1");
        
        for(; !i.equals(n); i = i.add(BigInteger.ONE))
        {
            result = result.multiply(i);
        }
        
        return result.multiply(n).toString();
    }


--------------------
import my.opinion.*;
жж
PM ICQ   Вверх
esperant0
Дата 28.10.2006, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 714
Регистрация: 20.5.2005

Репутация: 4
Всего: 14



Цитата(integral @ 28.10.2006,  16:29)
А вот пример на Java, на своей машине я смог вычеслить 100001! за 9 мин 24 сек:
private String calkFacktorial(String str)
    {
        if(str.equals("0")) return "1";
        BigInteger i = new BigInteger("1");
        BigInteger n = new BigInteger(str);
        BigInteger result = new BigInteger("1");
        
        for(; !i.equals(n); i = i.add(BigInteger.ONE))
        {
            result = result.multiply(i);
        }
        
        return result.multiply(n).toString();
    }

а я за своей за 12 секунд считал


--------------------
 
 Student->Teacher Assistant ->Research assistant->Microsoft Software Development Engineer 

Пользователь получил наказание за то, что проигнорировал замечание которое было написано модератором  а затем стерто и которое он - пользователь не мог видеть. 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0551 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.