Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Ускорение поиска числа факториала

Ответить
Настройки темы
C/C++ - Ускорение поиска числа факториала

Старожил


Сообщения: 222
Благодарности: 1

Профиль | Отправить PM | Цитировать


Люди помогите сделать бысрый алгоритм нахождения числа из его факториала.
Я писал вот такой код но он оч медленный
Код: Выделить весь код
#include <iostream.h>
#include <fstream.h>
int faknom(int a)
{
	int i=1;
	while(a!=i)
	{
		a=a/i;
		i++;
	};
	return i;
};
int main()
{
	int Nfak;
	ifstream fin("input.txt");
	fin>>Nfak;
	fin.close();
	ofstream fout("output.txt");
	fout<<faknom(Nfak)<<endl;
	fout.close();
	return 0;
}
В файле input.txt лежит значение факториала N! числа N, а в файле output.txt должно быть записано значение N.
Как ускорить алгоритм расчета?

Отправлено: 13:00, 01-06-2008

 

редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Цитата DaRiYs:
Время выполнения программы для даной задачи ограничено 1 секундой и обьем кода до 4кб. »
Обычно 64кб ограничение на размер исходника (по ACM'овским правилам).

Цитата mrcnn:
Что такое контестер, что такое ACM и что такое контестер типра ACM? »
http://en.wikipedia.org/wiki/ACM_Int...amming_Contest

Так вот, если ограничение всё-таки 64 кб, то спокойно можно сделать таблицу. (длина десятичной записи n!) -> значение n. Длина для всех факториалов начиная с 10! точно различна (для значений меньше можно использовать честный подбор). Длина 2000! - 5737. Элементарная программа на питоне (или любом другом языке, в котором встроена поддержка больших чисел) легко позволяет построить такую таблицу за пару минут.

-------
http://ivank.ru


Отправлено: 17:26, 01-06-2008 | #21



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Старожил


Сообщения: 222
Благодарности: 1

Профиль | Отправить PM | Цитировать


Ну так у меня ограничение кода до 4 кб. Эт не АСМ а ему подобный

-------
Подпись, нарушающая правила конференции, отредактирована администратором


Отправлено: 17:43, 01-06-2008 | #22


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Если очень хочется извратиться и впихнуть всё в 4кб, то можно закодировать таблицу в виде сдвигов между соседними значениями. Т.к. мы умножаем максимум на 2000, то длина изменяется не более, чем на 4 знака каждый раз; но не менее, чем на один. Для хранения этой информации достаточно 2 бит. А для хранения всех сдвигов - 4000 бит, которые можно записать в виде строки (если использовать только печатные символы из нижней половины ascii, чтобы можно было вставить в исходный текст без изменений) всего в 4000/log2(64)=667 символов, ещё 3кб на код останется . И потом декодировать оттуда нужную информацию небольшим кусочком кода.

Всё решение будет типа такого:
Код: Выделить весь код
unsigned char[] diff_table="blah-blah blah..."; //667 символов таблицы.

// получить i-й сдвиг из таблицы.
int getDiff(int i) {
    unsigned char c = diff_table[i/6] - 32;
    int diff = (c >> ((i%6)*2)) & 3; 
    return diff;
}
// ....
char fac_str[10000];
cin >> fac_str; // зачитываем факториал, _как строку_

int need_len = strlen(fac_str); // длина факториала, для которого надо найти n
int n = 0; // ответ будет здесь
if (need_len <= 8) {
    // n <= 10, тупо подбираем
    int facn = 1;
    int fac = atoi(fac_str);
    for (n = 1; facn < fac; ++n) {
        facn *= n;
    }
} else {
    int len = 8; // длина факториала 10
    // начинаем подбирать с 11
    for (n = 11; len < need_len; ++n) {
        len += getDiff(n);
    }
}
А можно, всё-таки, честно запрограммировать длинное умножение и не париться с извращениями. Ссылку в яндекс, где объясняется, как правильно умножать длинные числа, я уже бросал.

-------
http://ivank.ru


Последний раз редактировалось ivank, 01-06-2008 в 19:19.


Отправлено: 17:52, 01-06-2008 | #23


Аватара для Altair86

Новый участник


Сообщения: 15
Благодарности: 2

Профиль | Отправить PM | Цитировать


Могу предложить еще вариант без длинной арифметики. Не знаю, будет ли он работать быстрее, поскольку там много вычислений с плавающей точкой... и влезет ли в нужный объем.
Правильно работать он будет, только если число в файле заведомо является факториалом.
Способ: приближенное значение натурального логарифма факториала числа n равно
ln(n!)=1/2(ln(2)+ln (Pi))+ln(n)+n*ln(n)-n
десятичный логарифм равен
Log(n!)=ln(n!)/ln(10)
Количество знаков в факториале будет равно Log(n!)+1, округленному снизу.
Считываем из файла факториал в виде символьной строки. Считаем количество знаков в этой строке. Дальше ищем на отрезке числовой оси (1;2000) нужное нам число n методом деления отрезка пополам. То есть, проверяем числа 1 и 2000 (считаем по формуле), если кол-ва цифр в их факториалах не подходят, берем число в середине отрезка (например 1000), считаем кол-во цифр в его факториале. Если опять не подходит, берем середину отрезка (1;1000) или (1000;2000)-- в зависимости от того, больше или меньше кол-во знаков в числе из файла, чем в 1000! Дальше снова, максимум за 10--12 шагов число n точно определяется
И одна тонкость: для чисел, меньших 7, лучше сохранить факториалы в файле с программой, и сначала проверять не является ли n одним из этих чисел. после чего делить отрезок не от 1 до 2000, а от 7 до 2000. (потому, что факториалы разных чисел, меньших 7, могут иметь одинаковое кол-во знаков)

-------
Будь проклят тот день, когда обезьяна слезла с дерева и научилась говорить...

Это сообщение посчитали полезным следующие участники:

Отправлено: 18:53, 01-06-2008 | #24


Старожил


Сообщения: 222
Благодарности: 1

Профиль | Отправить PM | Цитировать


Мож хтонибудь всетаки напишет код на ассемблере для использования его в С++

-------
Подпись, нарушающая правила конференции, отредактирована администратором


Отправлено: 19:56, 01-06-2008 | #25


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


Цитата Drongo:
Можно на примере или прочесть где?! »
Пример для MSVS 6+

Код: Выделить весь код
#include <Windows.h>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
SYSTEMTIME st;
GetSystemTime(&st);//GetLocalTime()
cout << "\n" <<st.wSecond << " " <<st.wMilliseconds;
Sleep(1000);
GetSystemTime(&st);//GetLocalTime()
cout << "\n" <<st.wSecond << " " <<st.wMilliseconds;
return 0;
}

Для данного примера разницы между GetSystemTime() и GetLocalTime() нет. А вообще первая возвращает время по Гринвичу UTC, вторая по выбранному свойствах системы часовому поясу.

ivank, а как быть с iostream что б по стандарту? Или это » только в Linux, а micorosoft будет оставлять совместимость в своём компиляторе?
cout удобние printf
Или можно просто вывести значения st.wSecond и st.wMilliseconds через printf не усложняя код?
Со строчкой printf("%s %s",st.wSecond, st.wMilliseconds); компилится, но во время выполнения ошибка естественно
Цитата:
The instruction at "0x00000000" referenced memory at "0x00000000". The memory could not be "read".
Так как не совпадение типов. Чем собственно и удобен cout, что не брезгливый к этому. За это он не в стандарте?

Отправлено: 19:57, 01-06-2008 | #26


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Admiral,
Цитата Admiral:
ivank, а как бы по стандарту что в ситуации с iostream? Или это только в Linux, а micorosoft будет оставлять совместимость в своём компиляторе? »
Не понял вопроса Заголовочный файл iostream есть в стандарте и всегда будет и в gcc и в msvc. Нет в стандарте заголовочного файла iostream.h, который объявляет всё в глобальной области видимости (а не в std), но абсолютное большинство компиляторов его всё равно поддерживают, как раз для совместимости.

Цитата Admiral:
cout удобние printf »
Спорное утверждение Если попробовать вывести что-то с более-менее сложным форматом, то форматная строка printf намного удобнее (мне во всяком случае).

Цитата Admiral:
Со сторчкой printf("%s %s",st.wSecond, st.wMilliseconds); компилится но во время выполнения, естественно ошибка »
Все приличные компиляторы умеют выдавать warning на такой код, очень уж распространённая ошибка

DaRiYs, за вас никто ничего писать не будет. Вам предложили методы решения задачи (целых 3). Если вы чётко объясните, что вас в них не устраивает (или что непонятно), то можно будет продолжать диалог.

-------
http://ivank.ru


Отправлено: 20:10, 01-06-2008 | #27


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


ivank, вопрос навеян этим постом, я об этом в предыдущем посте указал », когда сказал про Linux.
Да я понимаю, что строка printf("%s %s",st.wSecond, st.wMilliseconds); ошибочна. Я к примеру показал сравнения с cout << "\n" <<st.wSecond << " " <<st.wMilliseconds; которой кроме себя самой не нужно приведения типов, что б не вызывать ошибку при выполнении.
Компилятор MS C++ 2008 Express прохлопал всё без Warnings, возможно по дефолтному уровню предупреждений не положено замечать эту строчку как потенциально опасной. Сам я использую в основном printf, но когда отлаживаю программу и ещё не знаю нужной функции приведения типов, использую cout, так как он их щёлкает как орешки и выводит мне нужное значение. Можно и Debug средствами среды узнавать значения переменных, но они не всегда доступны.

Отправлено: 20:27, 01-06-2008 | #28


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Цитата Admiral:
ivank, вопрос навеян этим постом, я об этом в предыдущем посте указал », когда сказал про Linux. »
Вероятно я там неясно выразился. <iostream.h> официально не существует, просто <iostream> - вполне есть в стандарте.

-------
http://ivank.ru

Это сообщение посчитали полезным следующие участники:

Отправлено: 20:32, 01-06-2008 | #29


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


ivank, не прошло и дня.
printf("time %02u:%02u:%02u:%03u\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
и ни каких сout с #include <iostream> и using namespace std;
а лишь printf c #include <stdio.h>
нашёл здесь.

Отправлено: 20:44, 01-06-2008 | #30



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Ускорение поиска числа факториала

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Простые числа на Си++ nemo555 Программирование и базы данных 13 13-03-2007 21:24
*Теория* | Числа Фибоначчи Grub Программирование и базы данных 8 28-07-2006 14:23
четность числа elfoflorien Вебмастеру 6 18-09-2005 20:49
Случайные числа на JavaScript Dimonweb Вебмастеру 2 12-08-2004 03:23
суммироват числа Artashes Программирование и базы данных 3 30-08-2003 18:31




 
Переход