Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Рекурсия And Стек

4.8K
21 ноября 2005 года
Jump
128 / / 09.11.2005
Я понимаю, что проблема тривиальная... Но поиском ответа на вопрос не нашел. Подскажите как бороться с переполнением стека.

Я "боролся" с этим подсчетом подвызовов. Экспериментально замерял сколько подвызовов данная функция "держит", принимал это за максисмум, а дальше если число превышается, то тупо останавливал выполнение.
585
21 ноября 2005 года
honeybeer
297 / / 06.09.2004
Цитата:
Originally posted by Jump
Я понимаю, что проблема тривиальная... Но поиском ответа на вопрос не нашел. Подскажите как бороться с переполнением стека.

Я "боролся" с этим подсчетом подвызовов. Экспериментально замерял сколько подвызовов данная функция "держит", принимал это за максисмум, а дальше если число превышается, то тупо останавливал выполнение.


 
Код:
try
    {...}
catch(EOverflow &e)
    {...}
4.8K
21 ноября 2005 года
Jump
128 / / 09.11.2005
А есть какой способ продолжить выполнение, сбросив, допустим, часть стека в оперативу, или вообще может есть какой-нибудь тип функций, работающих без заваливания стека своими возвратами :) ...

Или это все уже из области слишком нетривиального?...
9.7K
21 ноября 2005 года
DaemonDZK
59 / / 08.11.2005
Цитата:
Originally posted by Jump
А есть какой способ продолжить выполнение, сбросив, допустим, часть стека в оперативу, или вообще может есть какой-нибудь тип функций, работающих без заваливания стека своими возвратами :) ...

Или это все уже из области слишком нетривиального?...



Думаю проще будет сделать функцию нерекурсивной.

4.8K
21 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by honeybeer
 
Код:
try
    {...}
catch(EOverflow &e)
    {...}



Не работает, однако... У меня в функции несколько вариантов ее подвызова, дак я даже не общий трай, а отдельно для каждого подвызова сделал так... И по нулям, трай даже не срабатывает... Зато теперь сообщение о переполнении не выскакивает - прога просто сразу аннигилируется :D

4.8K
21 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by DaemonDZK
Думаю проще будет сделать функцию нерекурсивной.


Думал над этим... Слишком не оптимально получается... Собственно говоря все началось со скачивания мат-парсера, выложенного на этом сайте - он работает с ошибкой. И задался я целью попробовать написать для себя мат-парсер (ну мало в и-нете мат-парсеров :) ). Сперва как раз и написал без рекурсии - работает. Потом пришла в голову неплохая оптимизация с рекурсией.
Дак вот рекурсивный вариант перемалывает выражение, длинной в 60 вордовских листов, не успеваешь кнопку отпустить, а первый вариант молотит это выражение полминуты... Проблема в том, что стоит добавить в то выражение еще хоть один символ, и рекурсивный падает, а первый вариант все равно работает......

4.8K
22 ноября 2005 года
Jump
128 / / 09.11.2005
Подскажите еще пожалуйста, что кидается в стек при вызове функции, и что каждый элемент при этом занимает.
Я полон решимости решить проблему со стеком, и при этом хочу сделать это применимым для любого случая!

Пока идея заключается в том, чтобы в случае перепнения сбрасывать определенную часть стека в оперативу.

Задача в том чтобы определить сколько заданная функция запихивает в стек при одиночном вызове.
585
22 ноября 2005 года
honeybeer
297 / / 06.09.2004
Цитата:
Originally posted by Jump
Подскажите еще пожалуйста, что кидается в стек при вызове функции, и что каждый элемент при этом занимает.
Я полон решимости решить проблему со стеком, и при этом хочу сделать это применимым для любого случая!

Пока идея заключается в том, чтобы в случае перепнения сбрасывать определенную часть стека в оперативу.

Задача в том чтобы определить сколько заданная функция запихивает в стек при одиночном вызове.


Debug Windows->CPU там есть окошко стека

3
22 ноября 2005 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Jump
Подскажите еще пожалуйста, что кидается в стек при вызове функции, и что каждый элемент при этом занимает.
Я полон решимости решить проблему со стеком, и при этом хочу сделать это применимым для любого случая!


В стек кидается очень много и всякого разного... :)
Это и параметры вызова, и копии регистров, и локальные переменные, и различные данные для механизмов проверки целостности стека и пр.

Поэтому для любого случая не получится скорее всего. Да и не за чем.

Как уже говорилось, лучше отказаться от рекурсии.
Это выигрышный вариант по нескольким критериям: память, скорость и пр.

4.8K
22 ноября 2005 года
Jump
128 / / 09.11.2005
Я немного "порыбачил" в стеке... Похоже туда действительно очень много чего пихается. Многое понял, но не все, а без понимания всего задачку не решишь.

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

Меня еще вот какой вопрос терзает: может быть есть како-нибуть тип функций в билдере(да и не только), которые все свои данные(за исключением пожалуй адреса возврата) хранят в памяти, а не в стеке? Такая функция работала бы помедленней(самую малость, т.к. стек у виндоз-приложений все равно виртуальный, и валяется в памяти), но для рекурсии это был бы идеальный вариант.
585
22 ноября 2005 года
honeybeer
297 / / 06.09.2004
А рекурсия для тебя критична?
4.8K
22 ноября 2005 года
Jump
128 / / 09.11.2005
Я б мог кинуть код... ток боюсь он длинноват... :)
В общем, если там делать без рекурсии, то придется делать многомерный разноветкоразмерный массив :D (дерево, короче) для хранения промежуточных результатов вычислений. А с рекурсией имеем вполне красивенькую функцию... которая имеет несколько вариаций своего подвызова...
3
22 ноября 2005 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Jump

В общем, если там делать без рекурсии, то придется делать многомерный разноветкоразмерный массив :D (дерево, короче) для хранения промежуточных результатов вычислений.


А так тебе придется сделать тоже самое только через... другое место.
Любая рекурсия в конечном счете разворачивается в цикл. Это может сделать программист, а может сделать компилятор. Ты же пытаешься сделать нечто на промежуточном уровне. Вопрос целесообразности.

585
22 ноября 2005 года
honeybeer
297 / / 06.09.2004
Цитата:
Originally posted by Jump
Я б мог кинуть код... ток боюсь он длинноват... :)
В общем, если там делать без рекурсии, то придется делать многомерный разноветкоразмерный массив :D (дерево, короче) для хранения промежуточных результатов вычислений. А с рекурсией имеем вполне красивенькую функцию... которая имеет несколько вариаций своего подвызова...


Ну показал бы... глядишь и мысли бы появились, либо как избавиться от нее, либо как ловчее ее использовать

4.8K
22 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by honeybeer
Ну показал бы... глядишь и мысли бы появились, либо как избавиться от нее, либо как ловчее ее использовать



В краце (сложно про нее сказать в краце):
В первой половине выполнения (когда идет нарастание числа подвызовов, идем в глубину) рекурс как бы строит дерево очередности выполнения с запоминанием границ выражений (на каждом следующем этапе делит выражения на более мелкие части). Когда доходит до конца (делить уже нечего и это "дерево" построено) функции начинают возвращать . Т.е. начинается "спуск по ветвям к корню". У каждого узла получается всегда либо одна ветвь (когда считать уже нечего, нужно просто воспользоваться функцией TryStrToFloat для перевода строчки в число) либо две ветви (два значения (уже не строковых) и операция между ними).

Исходник немножко оформлю и выложу скорее всего завтра...

4.8K
24 ноября 2005 года
Jump
128 / / 09.11.2005
С меня код (все обработки ошибок убраны)...
С вас предложения :)

Код:
//Рекурсивная функция, в конечном итоге
//возвращающая результат заданного выражения
double op(char *str,int strLen)
{
    int i,l[2],opId=-1,opPos=-1;
    char *op_str[2], oper=0, tmp;
    double res,res1,res2;

    //Ищем оператор в строке(справа-налево) в порядке обратном
    //приоритета операторов, пропуская содержимое скобок
    if(!FindOperatorPriorReverse(str,strLen-1,0,&opPos,&opId)){
        //Если при этом есть скобки(дополнительная глубина), то раскрываем их
        if(str[strLen-1]==')'){
            if(str[0]=='('){
                op_str[0]=str+1;
                l[0]=strLen-2;
                res = op(op_str[0],l[0]);//Выполняем op для выражения в скобках
            }
            else if(str[0]=='-' && str[1]=='('){
                op_str[0]=str+2;
                l[0]=strLen-3;
                res = -op(op_str[0],l[0]);//Для скобок с инвертирующим минусом перед ними
            };
        }
        //Если скобок нет, то строка - это число в текстовом
        //виде, которое и нужно просто перевести в числовой
        //вид и возвратить
        else{
            tmp = str[strLen];
            str[strLen]=0;
            if(!TryStrToFloat((String)str,res)){
                if(str[0]=='(')MessageBox(0,"Лишняя открывающая скобка!","Ошибка!",MB_ICONEXCLAMATION|MB_OK);
                else MessageBox(0,"Недопустимый аргумент!","Ошибка!",MB_ICONEXCLAMATION|MB_OK);
                res = NaN;
            };
            str[strLen]=tmp;
        };
    }
    //Если в строке присутствует операция...
    else{
        oper = str[opPos];
        tmp = str[strLen];
        str[opPos] = 0;
        str[strLen]= 0;

        //Первый операнд
        op_str[0] = str;
        l[0] = opPos;
        res1 = op(op_str[0],l[0]);
        //Второй операнд
        op_str[1] = str+opPos+1;
        l[1] = strLen-opPos-1;
        res2 = op(op_str[1],l[1]);

        switch(oper){
            case '^': res = pow(res1,res2);break;
            case '/': res = res1/res2;break;
            case '*': res = res1*res2;break;
            case '-': res = res1-res2;break;
            case '+': res = res1+res2;break;
        };

        //Восстанавливаем обнуления
        str[opPos]=oper;
        str[strLen]=tmp;
    };
    return res;
}


Функция bool FindOperatorPriorReverse(char *str, int Begin, int End, int *Pos, int *Id), возвращает true, если операция в строке найдена, и false в противном случае; имеет следующие параметры:
str = указатель на строчку в которой искать
Begin = начальная позиция для поиска
End = конечная позиция (End<Begin, ищем с конца)
Pos = указатель на переменную, в которую вернется позиция найденной операции
Id = указатель на переменную, в которую вернется ИД операции (операции для поиска согласно приоритета "^/*-+")

Ее код не выкладывал для укорочения выложенного, т.к. сама она еще вызывает две функции...
4.8K
25 ноября 2005 года
Jump
128 / / 09.11.2005
Up...
Шо, не кто не подсобит с рекурсией? Т.е. о том как ее убрать или хотя б ловчей использовать.
3
28 ноября 2005 года
Green
4.8K / / 20.01.2000
Я бы разбил задачу на две подзадачи:
первая - разбивка выражения на токены;
вторая - проход по списку токенов.

Подробнее остановлюсь на второй подзадаче.
Хоть решение и не очень красивое (позднее объясню, в чем некрасивость), но его можно потом сделать красивее.

В общем случае у нас идет чередование: цисло - операция - число, иногда встречаются скобки.
Идем по списку токенов:
1) первое число помещаем в стек;
2) помещаем туда же операцию
3) помещаем следующее число;
4) смотрим следующую операцию, если её приоретет не выше приоретета предыдущей операции, раскручиваем стек; если же выше, то выполняем шаг 2);
5) и так повторяем до конца выражения, в конце раскручиваем стек.

Пример:
2+4*6+5

Состояние стека:
 
Код:
2  2  2  2   26  26  31
   +  +  +       +
   4  4  24      5
      *
      6


Для обработка скобок вводим доп.шаги:
3а) если встретилась открывающая скобка, то заносим её в стек и начинаем процедуру с шага 1);
3б) если встретилась закрывающая скобка, то раскручиваем стек до первой открывающей скобки.

Пример:
2+4*(2+4)+5

Состояние стека:
 
Код:
2  2  2  2  2  2  2   26  31
   +  +  +  +  +  +   +
   4  4  4  4  4  24  5
      *  *  *  *
      (  (  (  6
         2  2  
            +
            4


Некрасиво то, что стек у нас хранит как числа, так и операции, т.е. два разных типа, которые можно объединить только одним понятием - токен.
4.8K
29 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by Green

Пример:
2+4*6+5

Состояние стека:
 
Код:
2  2  2  2   26  26  31
   +  +  +       +
   4  4  24      5
      *
      6



Идея мне очень нравится :), правда тут придется работать в режиме асма...
И опять же не куда не девается работа со СТЕКОМ, который будет лимитировать все своим крохотным размером...

Кстате не подскажете как с флоатами в асме работать? Я так помню там отдельный стек, куда все пихать, и с двумя последними можно работать, вроде так? И подскажите функции, или крохотный примерчик :) , хоть это уже и не по теме...

3
29 ноября 2005 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Jump
Идея мне очень нравится :), правда тут придется работать в режиме асма...
И опять же не куда не девается работа со СТЕКОМ, который будет лимитировать все своим крохотным размером...


Не вижу необходимости асма.
Под стеком я понимал не программный стек, а просто структуру хранения данных, например обычный стандартный контейнер.

4.8K
29 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by Green
Не вижу необходимости асма.
Под стеком я понимал не программный стек, а просто структуру хранения данных, например обычный стандартный контейнер.


стандартный контейнер - что это? я не в курсе...

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

 
Код:
struct Token{
    double Value;
    bool IsOperand; //Истинно - значит операнд, иначе - это операция
};

Но это - ...гхм...)
8.8K
30 ноября 2005 года
dark_king
35 / / 27.10.2005
Это как я понимаю нечто вроде строчного калькулятора. Ох и намучался я с ним в свое время. Сейчас смотрю исходники и поражаюсь - как этот зверь работает. Но как не парадоксально - работает. DLL с функцией юзаю давольно часто.
Кстати структурка, описывающая лексическую единицу:
 
Код:
struct lecsem
{
  int who;
  double ch;
};

Где who - это и число, и скобка, и функция и переменная, в общем все что угодно. А ch инициализируется если who - число.
Единственное - ни пойму - где ты достал 60 листов формул. Подскажи! Я бы свой калькулетр оттестировал. Правда у меня другая беда была. Надо было мне мою функцию из DLL в цикле вызывать. Так вот: при статическом подключении происходит страшная утечка памяти. После n-й итерации виртуальная память системы просто заканчивается и программа вылетает. Пришлось загружать DLL динамически и освобождать ее же через некоторое кол-во итераций. Не подскажите-ли как с этим можно бороться?
3
30 ноября 2005 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by dark_king
Так вот: при статическом подключении происходит страшная утечка памяти. После n-й итерации виртуальная память системы просто заканчивается и программа вылетает. Пришлось загружать DLL динамически и освобождать ее же через некоторое кол-во итераций. Не подскажите-ли как с этим можно бороться?


Проверь свой код на утечки памяти... :)

Цитата:
Originally posted by Jump

стандартный контейнер - что это? я не в курсе...


std::vector
std::list
std::map
std::deque
и пр.

4.8K
30 ноября 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by dark_king
Единственное - ни пойму - где ты достал 60 листов формул. Подскажи!



Да фонарно :) Пишешь небольшое выражение, так чтоб содержало всевозможные вариации-перевариации всего что только можно, ставишь в конце выражения "+", копируешь все это хозяйство, и вставляешь до посинения :D

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

ЗЫ: Доклад в универе по данной теме заработал... Нужны примеры... много :)


Цитата:
Originally posted by Green
std::vector
std::list
std::map
std::deque
и пр.



Благодарю!
Правда, по опыту работы с std::vector, думаю, что сильно пострадает скорость (по сравнению с программным стеком)... Хотя, наверное, это и есть цена возможности работать с практически не ограниченными по размеру выражениями.

8.8K
06 декабря 2005 года
dark_king
35 / / 27.10.2005
Цитата:
Originally posted by Jump
Кстати, если кто занимался такой охинеей, как написанием подобного строчного калькулятора, киньте плз исходники (хотяб ключевых функций), или сцилку, если таковая есть. И если можно комментарий от автора...

ЗЫ: Доклад в универе по данной теме заработал... Нужны примеры... много :)


Файл с кодом прилагаю.
Извини, что несколько длинновато, зато готовая функция. Правда в таком виде она тебе не подойдет, т.к. работает с огранниченным кол-вом лексемм.
В краце об аргументах:
1) - указатель на строку сод. ф-лу
2) - указатель на массив структур, содержащие имена переменных и их значения, если в твоих ф-лах не используется символьных пер-ных, то NULL
3) - размер вышеописанного массива (в штуках, а не в байтах :-))
4) - код ошибки, если оная произошла.
ret.value - значение, посчитанной ф-лы.
Да, я тут не предусмотрел ошибку переполнения массива лексемм, так, что поосторожнее с этим.
В ПРОМЕЖУТОЧНЫХ функциях - думаю разберешся.
Есть предположение, что данный алгоритм хорошо оптимизирован.
Буду признателен, если кто-нибудь опровергнет или подтвердит данное предположене.
Вообще, заранее благодарю за любую критику. Можно на мыло [email]dark_king@inbox.ru[/email]

8.8K
06 декабря 2005 года
dark_king
35 / / 27.10.2005
Цитата:
Originally posted by Jump
Кстати, если кто занимался такой охинеей, как написанием подобного строчного калькулятора, киньте плз исходники (хотяб ключевых функций), или сцилку, если таковая есть. И если можно комментарий от автора...


код приложил в виде файла, написал длинное описание, но оно кильнулось при попытке отправить, так что если не разбирешся, спрашивай. За критику проги буду благодарить всех!:-) Кидайте идеи по совершенствованию на ящик [email]dark_king@inbox.ru[/email]
Тебе совершенствовать придется, т.к. ф-я работает с огр. кол-вом лексемм.

4.8K
06 декабря 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by dark_king
код приложил в виде файла, написал длинное описание, но оно кильнулось при попытке отправить, так что если не разбирешся, спрашивай. За критику проги буду благодарить всех!:-) Кидайте идеи по совершенствованию на ящик [email]dark_king@inbox.ru[/email]
Тебе совершенствовать придется, т.к. ф-я работает с огр. кол-вом лексемм.



Как кильнулось?! Совсем?! Если файлик вдруг не совсем умер :) мож на мылье отправишь... Плииииз (jump99 сбк yandex тчк ru)

Код длинный... Пока разберусь - сессия кончится :D

8.8K
07 декабря 2005 года
dark_king
35 / / 27.10.2005
Цитата:
Originally posted by Jump
Как кильнулось?! Совсем?! Если файлик вдруг не совсем умер :) мож на мылье отправишь... Плииииз (jump99 сбк yandex тчк ru)

Код длинный... Пока разберусь - сессия кончится :D


В общем писал в ответ, а при попытке отправить произошел сбой связи. Вот так и кильнулось.
Ну да ладно, сейчас повторим.
variable - структура содержащая информацию о символьных переменных (name - имя, znachen - значение), если такие используются.
getprior - внутренняя ф-ция, отвечающая за выдачу приоритета операциям.
digitlen - возвращает длину (в символах) числа, записанного по правилам С++.
double calculator(char*, variable*, int, char*&) - основная ф-ия.
Параметры:
1) IN указатель на строку, содержащую формулу.
2) IN указатель на массив структур, содержащих значения символьных переменных, использующихся в формуле. (NULL, если не используются)
3) IN количество вышеописанных структур (в штуках, а не в байтах)
4) OUT описание ошибки, если таковая имела место.
Тьфу блин, да есть же описание.
Посмотри предыдущий ответ, все-таки дошел. А большого описания - шаг за шагом никогда и не было.
Писать его в лом. Так что задавай вопросы, отвечу.

4.8K
07 декабря 2005 года
Jump
128 / / 09.11.2005
Цитата:
Originally posted by dark_king
....


Благодарствую! ...Дак эта штука еще и переменные понимает! Четко :)
Сори, что сразу описание не заметил... обычный затуп с перелистом странички.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог