Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Рекурсивная функция 
:(
    Опции темы
Pete
Дата 10.6.2006, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Void @  10.6.2006,  18:11 Найти цитируемый пост)
Есть алгоритмы, которые рекурсивны по своей природе, и для их итеративной реализации придется организовывать собственный стек.

Скажем так: любой рекурсивный алгоритм из Кормена, насколько я их помню, можно переписать в итерационном виде с увеличением быстродействия. Если ты имеешь в виду что-то, быть может, экзотическое, то прошу в студию.
 smile  


--------------------
Совет учиться на ошибках других бесполезен; научиться чему-либо можно только на собственных ошибках. (Бернард Шоу)
Не откладывай на завтра то, что можешь сделать сегодня. (Пословица)
А теперь выпишем точное значение числа пи... (Препод)
Жахни, Пендальф! © Гоблин
PM   Вверх
Void
Дата 10.6.2006, 18:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

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



Pete, ничего экзотического, перепиши обычную быструю сортировку (Хоара), не создавая собственного стека.
И сравни быстродействие эмуляции стека с явной рекурсией. Такой вариант, возможно, окажется быстрее, но ненамного. И даже в этом я не уверен. 

Это сообщение отредактировал(а) Void - 10.6.2006, 18:23


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
Pete
Дата 10.6.2006, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Хм.. Согласен. Пока не встречал ее итерационной реализации без стека. Сравнение этих алгоритмов в скорости, наверное, уже больше зависит от системы. Конечно, отсутствие объявления новых переменных на каждом уровне рекурсии придаст определенное ускорение, хотя, кто знает...
(ЗЫ: мы пока от темы не ушли далеко? smile )  

Это сообщение отредактировал(а) Pete - 10.6.2006, 18:45


--------------------
Совет учиться на ошибках других бесполезен; научиться чему-либо можно только на собственных ошибках. (Бернард Шоу)
Не откладывай на завтра то, что можешь сделать сегодня. (Пословица)
А теперь выпишем точное значение числа пи... (Препод)
Жахни, Пендальф! © Гоблин
PM   Вверх
Xenon
Дата 10.6.2006, 20:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Ну мне кажется тут такой же "большой" прирост в скорости, что и при использовании
Код
 
int x=5;
x=x<<1;

Вместо
Код

int x=5;
x*=2
 


--------------------
user posted image  
PM MAIL   Вверх
kirjanov
Дата 10.6.2006, 22:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 326
Регистрация: 22.1.2006
Где: Dark wood of erro r

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



XenonSk
конечно, прирост производительности явно не будет большим. Может твой компилятор и сгенерирует эквивалентный код, как в верхней инструкции. Что может быть более показательным сейчас, как использование интерпретируемых языков.... 
PM MAIL   Вверх
Xenon
Дата 10.6.2006, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



kirjanov, То, что кинул я считается не одним и тем же ... Вообще говорят, что часто побитовый сдвиг дает хороший прирост smile 


--------------------
user posted image  
PM MAIL   Вверх
Void
Дата 10.6.2006, 23:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

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



Цитата(XenonSk @  11.6.2006,  00:34 Найти цитируемый пост)
Вообще говорят, что часто побитовый сдвиг дает хороший прирост 

Я не знаю компилятора, настолько тупого, чтобы умножение или деление на константу он не превратил в битовый сдвиг.
И, кстати, в случае знакововых чисел можно сильно огрести, использовав сдвиг вправо вместо деления:
Код
#include <cstdio>
#include <cstdlib>

int main() {
    int x = -1;
    printf("%i %i", x >> 1, x / 2);
}

Цитата
-1 0


И еще:
Код
#include <cstdio>
#include <cstdlib>

int main() {
    int x = rand();
    int y = rand();
    x <<= 1;
    y *= 2;
    printf("%i %i", x, y);
}

Код
;;;    int x = rand();
        call      _rand                                         ;5.10
$B1$8:
        mov       ebx, eax                                      ;5.10
$B1$2:
;;;    int y = rand();
        call      _rand                                         ;6.10
$B1$3:
;;;    x <<= 1;
        add       ebx, ebx                                      ;7.2
;;;    y *= 2;
        add       eax, eax                                      ;8.2

Это Intel C++ 9.0 в режиме максимальной оптимизации.
Не оптимизируйте, и не оптимизируемы будете smile 


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
Xenon
Дата 10.6.2006, 23:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Void, просто говорю, что в справочнике написано, а об "вылезании" там тоже писали smile 


--------------------
user posted image  
PM MAIL   Вверх
MAKCim
Дата 11.6.2006, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата

ничего экзотического, перепиши обычную быструю сортировку (Хоара), не создавая собственного стека.
И сравни быстродействие эмуляции стека с явной рекурсией. Такой вариант, возможно, окажется быстрее, но ненамного. И даже в этом я не уверен. 

думаю вариант с эмуляцией будет быстрее
насколько я знаю при рекурсивном вызове в стек заносится все окружение (локальные переменные) и адрес возврата
при эмуляции заносятся лишь необходимые данные
при быстрой организации нашего стека (например статический массив) думаю он будет по-эффективнее явной рекурсии 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Void
Дата 11.6.2006, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

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



Цитата(MAKCim @  11.6.2006,  11:45 Найти цитируемый пост)
насколько я знаю при рекурсивном вызове в стек заносится все окружение (локальные переменные) и адрес возврата

В стек заносится лишь адрес возврата и параметры вызываемой функции.
Да, вызываемая функция выделяет место на стеке для своих локальных переменных, но это — одна инструкция изменения регистра стека.
Цитата(MAKCim @  11.6.2006,  11:45 Найти цитируемый пост)
при быстрой организации нашего стека (например статический массив)

Кажется, уже обсуждалось, что статические переменные не могут дать никакого преимущества в скорости перед локальными. 


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
MAKCim
Дата 12.6.2006, 09:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата

В стек заносится лишь адрес возврата и параметры вызываемой функции.

я это и имел в виду, не так выразился
Цитата

Кажется, уже обсуждалось, что статические переменные не могут дать никакого преимущества в скорости перед локальными. 

под статическим массивом я подразумевал массив на стеке (размер известен в compile-time)
как пример можно взять рекурсивную функцию
Код

void F(int a)
{
    if (a==63) return;
    F(a+1);
    std::cout<<a<<std::endl;
}

и эквивалентную ее итеративную с эмуляцией стека
Код

void G(int a)
{
    int stack[63];
    char index=0;
    while (index!=63)
    {
        stack[index]=a;
        ++index;
        ++a;
    }
    while (--index) std::cout<<stack[index]<<std::endl;
    std::cout<<stack[index]<<std::endl;
}

и вызов
Код

int main()
{
    F(0);
    G(0);
    return 0;
}

тут итеративная выигрывает в используемой памяти (261 против 512 байт) и по количеству команд процессора
(326 против 575 (вывод считаем оной командой; командную реализацию while и if не рассматриваем))
так как любая рекурсивная программа сводится к итеративной, то, как показывает пример, при правильной ее организации она оказывается более эффективной  

Это сообщение отредактировал(а) MAKCim - 12.6.2006, 09:42


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Void
Дата 14.6.2006, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

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



Эх, люблю я бенчмарки проводить smile Вот и в этот раз не выдержал и написал тест. Все ту же быструю сортировку в двух вариантах: явная рекурсия и эмуляция через стек.
Код
#include <iostream>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>
#include <climits>
#include <cstdlib>
#include <ctime>


// Возвращает медиану из первого, последнего и серединного элемента.
template <typename Iterator, typename Comparer>
inline Iterator find_pivot(Iterator begin, Iterator end,
                           const Comparer &cmp) {
    Iterator middle = begin + (end - begin) / 2;
    if (cmp(*begin, *middle) && cmp(*(end - 1), *begin)
        || !cmp(*begin, *middle) && !cmp(*(end - 1), *begin))
        return begin;
    else if (cmp(*(end - 1), *middle) && cmp(*begin, *(end - 1))
        || !cmp(*(end - 1), *middle) && !cmp(*begin, *(end - 1)))
        return end - 1;
    return middle;
}

template <typename Iterator, typename Comparer>
inline Iterator partition(Iterator begin, Iterator end, Iterator pivot,
                          const Comparer &cmp) {
    typename std::iterator_traits<Iterator>::value_type pivotValue(*pivot);
    std::iter_swap(pivot, end - 1);
    Iterator p = std::partition(begin, end - 1, std::bind2nd(cmp, pivotValue));
    iter_swap(p, end - 1);
    return p;
}

template <typename Iterator, typename Comparer>
void rec_qsort(Iterator begin, Iterator end,
               const Comparer &cmp = Comparer()) {
    if (end - begin > 1) {
        Iterator pivot = find_pivot(begin, end, cmp);
        pivot = partition(begin, end, pivot, cmp);
        if (pivot - begin > end - pivot) {
            rec_qsort(begin, pivot, cmp);
            rec_qsort(pivot + 1, end, cmp);
        } else {
            rec_qsort(pivot + 1, end, cmp);
            rec_qsort(begin, pivot, cmp);
        }
    }
}

template <typename Iterator>
void rec_qsort(Iterator begin, Iterator end) {
    rec_qsort(begin, end,
        std::less<typename std::iterator_traits<Iterator>::value_type>());
}

template <typename Iterator, typename Comparer>
void qsort(Iterator begin, Iterator end, const Comparer &cmp = Comparer()) {
    // глубина рекурсии не превышает log_2(n), где n - длина сортируемой
    // последовательности
    std::pair<Iterator, Iterator> stack[
        sizeof(typename std::iterator_traits<Iterator>::difference_type) *
        CHAR_BIT];
    size_t top = 0;
    stack[top++] = std::make_pair(begin, end);
    while (top) {
        --top;
        begin = stack[top].first;
        end = stack[top].second;
        while (end - begin > 1) {
            Iterator pivot = find_pivot(begin, end, cmp);
            pivot = partition(begin, end, pivot, cmp);
            if (pivot - begin > end - pivot) {
                stack[top++] = std::make_pair(begin, pivot);
                begin = pivot + 1;
            } else {
                stack[top++] = std::make_pair(pivot + 1, end);
                end = pivot;
            }
        }
    }
}

template <typename Iterator>
void qsort(Iterator begin, Iterator end) {
    qsort(begin, end,
        std::less<typename std::iterator_traits<Iterator>::value_type>());
}


class timer {
    clock_t start_;
public:
    timer() : start_(clock()) { }

    double elapsed() {
        return 1.0 * (clock() - start_) / CLOCKS_PER_SEC;
    }

    void reset() {
        start_ = clock();
    }
};


int myrandom() {
    return rand() * (RAND_MAX + 1) + rand();
}


int main() {
    const size_t arraySize = 40000000;

    srand(time(NULL));
    std::vector<int> a(arraySize), b;
    std::generate(a.begin(), a.end(), myrandom);
    b = a;
    
    timer t;
    rec_qsort(a.begin(), a.end());
    std::cout << "Recursion:\t" << t.elapsed() << " sec" << std::endl;
    
    t.reset();
    qsort(b.begin(), b.end());
    std::cout << "No recursion:\t" << t.elapsed() << " sec" << std::endl;
}

Результаты:
GCC 3.4.5 (MinGW)
Цитата
Recursion:      7.797 sec
No recursion:   7.781 sec

Recursion:      7.797 sec
No recursion:   7.766 sec

Recursion:      7.812 sec
No recursion:   7.782 sec

Recursion:      7.797 sec
No recursion:   7.781 sec

Recursion:      7.797 sec
No recursion:   7.859 sec

VC 8.0:
Цитата
Recursion:      8.61 sec
No recursion:   8.719 sec

Recursion:      8.656 sec
No recursion:   8.766 sec

Recursion:      8.625 sec
No recursion:   8.781 sec

Recursion:      8.61 sec
No recursion:   8.765 sec

Recursion:      8.656 sec
No recursion:   8.735 sec

Вот такая забавная картина, не находите? smile
Так стоит ли заморачиваться с ручной эмуляцией стека ради пары процентов производительности, которые в зависимости от компилятора могут оказаться и на той, и на другой стороне? ИМХО, нет.
В данном случае можно было оценить верхний предел глубины рекурсии, однако выделяя под стек массив постоянного размера мы в любом случае рискуем молчаливо вылететь за его пределы. Используя же динамический массив мы рискуем свести на нет все призрачные преимущества эмуляции рекурсии. 


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

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

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


 




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


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

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