Страница 1 из 3 123 ПоследняяПоследняя
Показано с 1 по 10 из 28

Тема: Рекурсия и с чем её едят

  1. #1
    ыыыыы Аватар для Mexanizm
    Регистрация
    16.01.2012
    Адрес
    Россия. Воронеж
    Возраст
    30
    Сообщений
    2,450
    Репутация: 287

    Звание: как роза среди колючек

    Лампочка Рекурсия и с чем её едят

    Здравствуйте уважаемые пользователи.
    В этом уроке я хочу рассказать пр процесс называемый "Рекурсия".
    Постараюсь привести примеры и рассказать зачем и где используется.

    Сначала немножечко углубимся в теорию.

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

    Термин «рекурсия» используется в различных специальных областях знаний — от лингвистики до логики, но наиболее широкое применение находит в математике и информатике. В математике и информатике рекурсия имеет отношение к методу определения функций: рекурсивно заданная функция в своём определении содержит саму себя, в частности, рекурсивной является функция, заданная рекуррентной формулой. Таким образом, можно одним выражением дать бесконечный набор способов вычисления функции, определить множество объектов через самого себя с использованием ранее заданных частных определений.

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

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

    Преимущество рекурсивного определения объекта заключается в том, что такое конечное определение теоретически способно описывать бесконечно большое число объектов. С помощью рекурсивной программы же возможно описать бесконечное вычисление, причём без явных повторений частей программы.

    Реализация рекурсивных вызовов функций в практически применяемых языках и средах программирования, как правило, опирается на механизм стека вызовов — адрес возврата и локальные переменные функции записываются в стек, благодаря чему каждый следующий рекурсивный вызов этой функции пользуется своим набором локальных переменных и за счёт этого работает корректно. Оборотной стороной этого довольно простого по структуре механизма является то, что на каждый рекурсивный вызов требуется некоторое количество оперативной памяти компьютера, и при чрезмерно большой глубине рекурсии может наступить переполнение стека вызовов. Вследствие этого, обычно рекомендуется избегать рекурсивных программ, которые приводят (или в некоторых условиях могут приводить) к слишком большой глубине рекурсии.



    Основное

    Возможно при компилировании мода вы могли заметить вот такое сообщение:
    Пример:
    Код:
    Header size:           2644 bytes
    Code size:            47964 bytes
    Data size:            72096 bytes
    Stack/heap size:       16384 bytes; estimated max. usage: unknown, due to recursion
    Total requirements:  124504 bytes
    *Цифры приведены примерные

    Обратим наше внимание на строчку
    Код:
    Stack/heap size:    16384 bytes; estimated max. usage: unknown, due to recursion
    Попробуем собственно разобрать что эта строчка значит.
    - Строка выводит сообщение о расчёте памяти используемой модом в процессе работы. Другими словами компилятор рассчитывает используемую память из Стека(Stack) модом и выводит
    информацию.

    Теперь разберём детально.


    Код:
    Stack/heap size:    16384 bytes;
    Это объём Стека в байтах.

    Код:
    estimated max. usage: unknown, due to recursion
    - В этой строчке приводится результат используемой максимальный памяти рассчитанный компилятором.
    На месте слова "unknown" должен собственно быть сам расчёт памяти(результат расчёта).
    "Unknown" или "Неизвестно" выводится тогда когда компилятор не может посчитать максимальный объём памяти используемый модом.
    Это вызвано как раз использованием рекурсии, а детально не может посчитать сколько раз функция будет вызвана и какой объём памяти она затратит(вроде так).




    Теперь приведу пример, где компилятор смог рассчитать количество используемой памяти

    Код:
    Header size:          14376 bytes
    Code size:          1923348 bytes
    Data size:          2137132 bytes
    Stack/heap size:      16384 bytes; estimated max. usage=3052 cells (12208 bytes)
    Total requirements: 4091240 bytes
    Как мы видим, слова"Unknown" уже нет. На его месте мы уже видим другую строчку
    Код:
    estimated max. usage=3052 cells (12208 bytes)
    которая сообщает нам, что мод будет затрачивать 3052(12208 байт) памяти из Стека во время работы, что не превышает максимальный объём Стека.



    В этой ветке я постараюсь привести примеры и по возможности объяснить принцип их действия.

    Пример 1:

    PHP код:
    main()
    {
              
    printf("%d"Test(25)); // Напишет 64
    }

    stock Test(var,num)
    {
              if(
    num>=0)
              {
                  return var*
    Test(var,num-1);
              }
              return 
    1;

    Мы вызываем функцию Test с параметром 2 и 5. Напомню, что в нашей функции первый параметр - число которое возводим в степень, второй параметр - степень.
    После вызова функции, она проверяет чему равна переменная num если она больше или равна (или равна, потому что отсчет в языках программирования идет с нуля), то функция умножает число на вызов самой себя, при этом num становится меньше на единицу. Зачем?
    Надо помнить, что необходимо предусматривать выход из рекурсии. Иначе она станет бесконечной и ваш скрипт (а вместе с ним и сервер) зависнет.
    В моем примере, выход из рекурсии - это
    if(num>=0) и num-1.
    Код выполняется только если num больше или равна нулю, а так как при каждом выполнении кода num уменьшается на один, бесконечной рекурсии не будет.
    Попробуйте убрать выход из рекурсии и проверьте что будет.


    __________________________________________________ __________________________________________________ __

    Пример 2:

    PHP код:
    func(value)
    {
        
    printf("%d", ++value);
        if(
    value 50)
            return 
    func(value);
        return 
    true;

    Мы вызываем функцию func с параметром value. В консоль сервера выводится значение параметра, а также прибавляется единица с помощью инкремента(++)
    Дальше проверка, что если параметр value меньше 50 то вызвать функцию ещё раз, и так до того пока параметр value не будет равным 50.


    __________________________________________________ __________________________________________________ __




    Рекурсия опасна тем, что при запуске функции из которой вызывается эта же самая функция, может переполнить память Стека и случится необратимый краш мода.
    Другими словами ввести в бесконечный цикл.(вроде так)
    Но это случится если рекурсия будет написана "Криво".


    Пример:

    PHP код:
    stock Test(var)
    {
        
    Test(var);
        return 
    1;

    Функция Test при вызове из другого скрипта войдёт в бесконечную рекурсию и в конечном итоге свалит мод в краш, так как функция вызывается из своего же "Тела" без очистки из Стека, что даст нам переполнение памяти.




    Основываясь на своём опыте( так как сталкивался с такой проблемой) я щас детально постараюсь объяснить как можно найти рекурсивный код.
    Для начала нужно проверить подключённые к моду инклуды на наличии рекурсий. Это можно сдлелать, подключив их к чистому new.pwn и скомпилировав.
    Если сообщение о рекурсии после компилирования не выдастся то с инклудами всё нормально.
    Коротенькое отступление: У меня вызывал рекурсию инклуды командного процессора YCMD (от Y_less).

    PHP код:
    y_master
    y_command 
    Если же вы удостоверились, что рекурсии в инклудах нет, то принимайтесь за поиск рекурсивного кода в моде, в ручную.
    Маленькая хитрость: при поиске рекурсии в моде я начал отключать по паблику / стоку (public / stock) и каждый раз компилировал. В конечном итоге я закомментировал нужный сток, и при компилировании рекурсия исчезла. Искать же сразу просто просматривая код, как мне кажется, не очень удачная мысль. Вы можете пропустить нужный код.

    Я сначала приступил к очень внимательному просмотру код но потратил на это очень много времени и сил, и к тому же это не принесло пользы. В последствии догадался до способа описанного выше, и уже спустя час кропотливой работы компилятор не выдал сообщения о рекурсии.





    Также нашёл рекурсивный код в моде RLS.
    Может пригодится...

    PHP код:
    stock StartSpectate(playeridspecid)
    {
        for(new 
    x=0x<GetMaxPlayers(); x++)
        {
            if(
    GetPlayerState(x) == PLAYER_STATE_SPECTATING && gSpectateID[x] == playerid)
            {
                
    AdvanceSpectate(x);
            }
        }
        if(
    IsPlayerInAnyVehicle(specid))
        {
            
    SetPlayerInterior(playerid,GetPlayerInterior(specid));
            
    SetPlayerVirtualWorld(playeridGetPlayerVirtualWorld(specid));
            
    TogglePlayerSpectating(playerid1);
            
    PlayerSpectateVehicle(playeridGetPlayerVehicleID(specid));
            
    gSpectateID[playerid] = specid;
            
    gSpectateType[playerid] = ADMIN_SPEC_TYPE_VEHICLE;
        }
        else
        {
            
    SetPlayerInterior(playerid,GetPlayerInterior(specid));
            
    SetPlayerVirtualWorld(playeridGetPlayerVirtualWorld(specid));
            
    TogglePlayerSpectating(playerid1);
            
    PlayerSpectatePlayer(playeridspecid);
            
    gSpectateID[playerid] = specid;
            
    gSpectateType[playerid] = ADMIN_SPEC_TYPE_PLAYER;
        }
        new 
    ping GetPlayerPing(specid);
        new 
    Float:health;
        
    GetPlayerHealth(specidhealth);
        new 
    string[100], name[24];
        
    GetPlayerName(specid,name,sizeof(name));
        new 
    lvl PlayerInfo[specid][pLevel];
        new 
    warns PlayerInfo[specid][pWarns];
        
    format(string,sizeof(string),"~n~~n~~n~~n~~n~~n~~n~~w~%s ID:%d~n~ LVL: %d Warns: %d ~n~ HP: %.0f ~r~PING: %d "name,specid,lvl,warns,health,ping);
        
    GameTextForPlayer(playerid,string,9999,3);
        return 
    1;
    }

    stock AdvanceSpectate(playerid)
    {
        if(
    ConnectedPlayers() == 2) { StopSpectate(playerid); return 1; }
        if(
    GetPlayerState(playerid) == PLAYER_STATE_SPECTATING && gSpectateID[playerid] != INVALID_PLAYER_ID) {
            for(new 
    x=gSpectateID[playerid]+1x<=GetMaxPlayers(); x++) {
                if(
    == MAX_PLAYERS) { 0; }
                if(
    IsPlayerConnected(x) && != playerid) {
                    if(
    GetPlayerState(x) == PLAYER_STATE_SPECTATING && gSpectateID[x] != INVALID_PLAYER_ID ||
                            (
    GetPlayerState(x) != && GetPlayerState(x) != && GetPlayerState(x) != 3))
                    {
                        continue;
                    }
                    else
                    {
                        
    StartSpectate(playeridx);
                        break;
                    }
                }
            }
        }
        return 
    1;






    Дополнительный материал


    Стек (англ. stack — стопка) — структура данных, представляющая из себя список элементов организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»).

    Другими словами Stack или Heap(куча) это память в которой загружается информация о текущем паблике: его индекс, аргументы, кол-во аргументов
    стек очищается только после успешного выполнения паблика.
    Размер Стека :16384(4096 байт).
    Много важной информации хранится в stack'е, такой как техническая информация о текущей функции, из-за которой PAWN знает куда возвращаться. Используя слишком много памяти, вы можете переписать информацию в stack, возвращая(returning) в случайную точку в коде, что означает абсолютный крэш. В конце концов ваша информация может быть испорчена, когда ее перезапишет другая информация
    Я думаю информации о Стеке должно хватить






    Благодарю вас за ознакомление с моим уроком. В нём я постарался изложить всю доступную мне информацию, которую пришлось пережить на горьком опыте.
    Также использовал достаточно информации с других источников таких как Википедия, Лукоморье, samp com.
    Некоторую информацию про Стек я позаимствовал из урока Владокса "Переполнение стека, или "почему нельзя возвращать массивы"".
    Благодарю Frog163 за предоставление второго примера рекурсии. Также, первые два примера я позаимствовал у человека с ником _Dark_
    Автор данного урока я, то есть Mexanizm93




    Уважаемые форумчане.

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



    Урок написан специально для lightcode.ru. При копировании материала на другие источники прошу указывать ссылку на оригинал и автора урока.
    Спасибо



    Автор данного урока я, то есть Mexanizm93
    Modern RP





  2. #2
    Read-only Аватар для MacMailler
    Регистрация
    03.04.2012
    Адрес
    East Kazakhstan
    Возраст
    30
    Сообщений
    1,047
    Репутация: 211

    Звание: - весьма и весьма положительная личность

    Re: Рекурсия и с чем её едят

    Полезный урок.

  3. #3
    [GM] Skill Training Mode Аватар для Gameyer
    Регистрация
    13.04.2010
    Адрес
    Россия
    Возраст
    28
    Сообщений
    2,296
    Репутация: 236

    Звание: - весьма и весьма положительная личность

    Re: Рекурсия и с чем её едят

    И где же в этом отрывке из мода RLS рекурсия?
    Skill Training Mode v3.1 Download
    Download

    Skill Training Mode Offical Web Site
    www.samp-stm.ru

    Skill Training Mode Offical Forum
    www.samp-stm.do.am

  4. #4
    ? FreeLancer ? Аватар для RastaOrecha
    Регистрация
    12.07.2011
    Адрес
    Челябинск
    Возраст
    26
    Сообщений
    1,857
    Репутация: 229

    Звание: - весьма и весьма положительная личность
    Делал рекурсию с зеркалами чтобы поржать

    Stack/heap size: 16384 bytes; estimated max. usage: unknown, due to recursion
    Это рекурсия?

  5. #5
    ыыыыы Аватар для Mexanizm
    Регистрация
    16.01.2012
    Адрес
    Россия. Воронеж
    Возраст
    30
    Сообщений
    2,450
    Репутация: 287

    Звание: как роза среди колючек

    Re: Рекурсия и с чем её едят

    Цитата Сообщение от RastaOrecha Посмотреть сообщение
    Делал рекурсию с зеркалами чтобы поржать
    xD

    Это рекурсия?
    Да. Компилятор не смог рассчитать максимально затрачиваемую память из стека из за рекурсии.

    Gameyer,
    Вызов функции A из тела функции B, вызов функции B из тела функции A. Это рекурсия

    MacMailler,
    Спасибо


    Немножечко дополню урок вечерком
    Modern RP





  6. #6
    Активный пользователь
    Регистрация
    11.12.2012
    Адрес
    Тюмень
    Возраст
    28
    Сообщений
    101
    Репутация: 18

    Звание: на пути к лучшему

    Re: Рекурсия и с чем её едят

    Понравился урок. Молодец.

  7. #7
    ыыыыы Аватар для Mexanizm
    Регистрация
    16.01.2012
    Адрес
    Россия. Воронеж
    Возраст
    30
    Сообщений
    2,450
    Репутация: 287

    Звание: как роза среди колючек

    Re: Рекурсия и с чем её едят

    Цитата Сообщение от lovely Посмотреть сообщение
    Понравился урок. Молодец.
    Спасибо
    Modern RP





  8. #8
    Люблю Окса :3 Аватар для Folleah
    Регистрация
    26.09.2012
    Сообщений
    2,045
    Репутация: 184

    Звание: - весьма и весьма положительная личность

    Re: Рекурсия и с чем её едят

    Нормально, но некоторые недочеты в тексте нашёл.

  9. #9
    ыыыыы Аватар для Mexanizm
    Регистрация
    16.01.2012
    Адрес
    Россия. Воронеж
    Возраст
    30
    Сообщений
    2,450
    Репутация: 287

    Звание: как роза среди колючек

    Re: Рекурсия и с чем её едят

    Цитата Сообщение от Folleah Посмотреть сообщение
    Нормально, но некоторые недочеты в тексте нашёл.
    Я уже редактировать не могу урок. Придётся оставить всё так..
    Modern RP





  10. #10
    Активный пользователь Аватар для Sistems
    Регистрация
    06.10.2012
    Адрес
    Душанбе
    Возраст
    28
    Сообщений
    504
    Репутация: 66

    Звание: скоро придёт к известности

    Re: Рекурсия и с чем её едят

    Цитата Сообщение от MacMailler Посмотреть сообщение
    Полезный урок.
    :bf: !

Страница 1 из 3 123 ПоследняяПоследняя

Похожие темы

  1. Что такое string и с чем его едят
    от ArtemkO в разделе Вопросы по скриптингу
    Ответов: 2
    Последнее сообщение: 02.02.2013, 17:38
  2. Рекурсия
    от TAP04eGG в разделе Беседка
    Ответов: 8
    Последнее сообщение: 22.01.2012, 15:40

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •