Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Рекурсивная функция не хочет работать :)

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Описание: и счётчик прикрутить
hehagog545
Отправлено: 25 Августа, 2020 - 23:06:56
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




Привет, помогите разобраться.
Проблема: всегда выводит кол-во попыток 1 и нужно много раз f5 жать, до результата, т.е. оно не "проваливается/рекурсит" саму себя до победы. Растерялся
PHP:
скопировать код в буфер обмена
  1.  
  2. // Задача: функция 3 раза рандомит числа, от 0 до 5 и если конечная сумма меньше 14, то
  3. // рекурсим и увеличиваем кол-во попыток на 1
  4.  
  5. function sum14($quantityTry)
  6. {
  7.        
  8.   for ($i = 0; $i <= 3; $i++) { // ШАГ 0. Запускаем цикл на 3 раза = 3 рандома
  9.  
  10.     if($i == 3) { // ШАГ 2. После рандомов проверяем сумму
  11.                        
  12.       if($count < 14) { // Если сумма меньше 14
  13.         sum14($quantityTry++); // то рекурсимся и +1 к кол-ву попыток
  14.       } else {
  15.         return 'Результат ' . $count . '. За ' . $quantityTry . ' попыток'; // итог
  16.       }
  17.     }
  18.   $count += rand(0,6); // ШАГ 1. 3 раза рандомит и складывает сумму
  19.   }
  20. }
  21.  
  22.  
  23. $quantityTry=1;
  24. echo sum14($quantityTry); // тут жестокая реальность противится моей воле :\
  25.  

Спасибо Улыбка
 
 Top
Мелкий Супермодератор
Отправлено: 26 Августа, 2020 - 11:03:14
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




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


-----
PostgreSQL DBA
 
 Top
Vladimir Kheifets
Отправлено: 26 Августа, 2020 - 11:26:08
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 879
Дата рег-ции: Март 2017  
Откуда: Германия, Бавария


Помог: 37 раз(а)




hehagog545 пишет:
Привет, помогите разобраться.
Проблема: всегда выводит кол-во попыток 1 и нужно много раз f5 жать, до результата, т.е. оно не "проваливается/рекурсит" саму себя до победы.

Добрый день!
Видимо, if($i == 3) в этом цикле не нужен.
PHP:
скопировать код в буфер обмена
  1. for ($i = 0; $i <= 3; $i++) // ШАГ 0. Запускаем цикл на 3 раза = 3 рандома
  2. {
  3.     if($i == 3)
  4.     {
  5.       .....
  6.     }
  7. }

Попробуйте сделать так:
Спойлер (Отобразить)
Удачи!

(Отредактировано автором: 26 Августа, 2020 - 11:29:30)

 
 Top
hehagog545
Отправлено: 26 Августа, 2020 - 12:22:38
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




Vladimir Kheifets спасибо!
Спойлер (Отобразить)

Всё понял, и где был не прав и важность global.
Вот корректная версия:
PHP:
скопировать код в буфер обмена
  1.  
  2. function sum14($quantityTry)
  3. {
  4.   global $res; // 1 добавили global $res с наметкой на вывод
  5.  
  6.   for ($i = 0; $i <= 3; $i++) {
  7.  
  8.     if($i == 3) {
  9.                        
  10.       if($count < 14) {
  11.         $quantityTry++; // 2 вынесли отдельно, ибо sum14($quantityTry++); - не работает
  12.         sum14($quantityTry);
  13.       } else {
  14.         $res = 'Результат ' . $count . '. За ' . $quantityTry . ' попыток'; // убрали return
  15.       }
  16.     }
  17.   $count += rand(0,5);
  18.   }
  19. }
  20.                
  21.        
  22. $quantityTry=1;
  23. sum14($quantityTry); // ф-ция отработала и записала итог работы в global $res;
  24. echo $res; // вот его и выводим
  25.  


Всем спасибо за участие Улыбка
 
 Top
LIME
Отправлено: 26 Августа, 2020 - 16:26:24
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




hehagog545 res надо передавать в вызов
глобальное состояние есть зло
функция должна быть чистой(это термин) - данные на вход и данные на выход и ничего более
никаких сайдэффектов
$res уже может существовать в системе и ты либо свою логику неверно выполнишь либо чужую сломаешь
static не сильно лучше
лучше сразу привыкай нормально делать
 
 Top
hehagog545
Отправлено: 26 Августа, 2020 - 18:22:35
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




LIME спасибо. Про синоним зла и глобал слышал давно Улыбка
Подправил, версия без глобал:
PHP:
скопировать код в буфер обмена
  1.  
  2. function sum14($quantityTry)
  3. {
  4.   for ($i = 0; $i <= 3; $i++) {
  5.  
  6.     if($i == 3) {
  7.                        
  8.       if($count < 14) {
  9.         $quantityTry++;
  10.         sum14($quantityTry);
  11.       } else {
  12.         echo $res = 'Результат ' . $count . '. За ' . $quantityTry . ' попыток'; // выводим
  13.       }
  14.     }
  15.   $count += rand(0,5);
  16.   }
  17. }
  18.                        
  19. $quantityTry=1;
  20. sum14($quantityTry);
  21.  


Вообще кошерные функции возвращают результат, но ф-ция начинает не работать, если ретурн юзать вот так:
PHP:
скопировать код в буфер обмена
  1.  
  2. ...
  3. } else {
  4.      return $res = 'Результат ' . $count . '. За ' . $quantityTry . ' попыток';
  5.   }
  6. ...
  7.  

Подскажите почему оно не работает в данном применении? Спасибо

UPD:
(Предположение почему не работает с ретурном как следует: верно ли думать, что ретурн при рекурсии возвращает на 1 уровень вверх, а т.к. уровней углубления в рекурсию больше, от того и происходит ошибка. Т.к. ф-ция с ретурном работает, если:
1.повезло и она сгенерила с первого раза
2.также должно работать и для 2ух раз, а вот если глубина рекурсии больше 2ух, то уже ничего не выводит.)

(Отредактировано автором: 26 Августа, 2020 - 18:49:13)

 
 Top
LIME
Отправлено: 26 Августа, 2020 - 19:05:43
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




возможно я не понял чего ты хочешь, но ты глянь и докручивай сам если что
PHP:
скопировать код в буфер обмена
  1. function sum14(int $tries = 1, int $result = 0)
  2. {
  3.     for ($i = 0; $i <= 3; $i++) {
  4.         if ($i == 3) {
  5.             if ($result < 14) {
  6.                 [$tries, $result] = sum14(++$tries, $result);
  7.             }
  8.  
  9.             return [$tries, $result];
  10.         }
  11.         $result += rand(0, 5);
  12.     }
  13. }
  14.  
  15. [$tries, $result] = sum14();
  16. echo 'Результат ' . $result . '. За ' . $tries . ' попыток';

(Добавление)
или так
PHP:
скопировать код в буфер обмена
  1. function sum14(int $tries = 1, int $result = 0)
  2. {
  3.     for ($i = 0; $i <= 3; $i++) {
  4.         $result += rand(0, 5);
  5.     }
  6.     if ($result < 14) {
  7.         [$tries, $result] = sum14(++$tries, $result);
  8.     }
  9.  
  10.     return [$tries, $result];
  11. }

(Добавление)
я так понимаю цель изучить рекурсию? потому что если можно логику сделать циклом то лучше избегать рекурсии - у нее лишние накладные расходы на сам вызов(выделение и освобождение памяти)
и нужно помнить о максимальной глубине вложенности - стэк не бесконечен
(Добавление)
например числа фибоначи довольно быстро сдыхают на рекурсивном алгоритме
а циклом прям моментально считаются
 
 Top
hehagog545
Отправлено: 26 Августа, 2020 - 20:33:23
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




LIME, подскажи по ретурну и рекурсии.
Ретурн он сразу в начало возвращает, выходя из всех уровней рекурсии или на 1 уровень вверх возвращает, как брэйк?
И можно ли задавать, как брэйку уровень выхода?

Спасибо.

PS Всё начиналось вроде с простой задачки, но в ходе решения стали возникать теоретические вопросы в которых оказался пробел - вот и копаюсь, с вашей помощью Улыбка
 
 Top
LIME
Отправлено: 26 Августа, 2020 - 20:39:25
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




ретурн возвращает в точку вызова где бы она не была
hehagog545 пишет:
как брэйк
боже упаси
как ты себе это представляешь? я значит такой говорю- "уважаемая ф-ция, посчитай мне пжлст вот это"
а мне в ответ- "пшел на фиг! я наверх куда-то отдам результат"
ф-ция не знает как она вызвана и что такое рекурсия вообще
ее вызвали -> она посчитала -> результат вернула вызвавшему коду
 
 Top
hehagog545
Отправлено: 26 Августа, 2020 - 21:01:27
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




LIME спасибо, значит ретурн в рекурсивных ф-циях лучше не использовать, т.к. он просто не вернётся из недр, если глубина больше 1, то произойдёт логическая ошибка - как думаешь, за правило такую мысль можно выдать или есть исключения?
Спойлер (Отобразить)

(Отредактировано автором: 26 Августа, 2020 - 21:11:05)

 
 Top
LIME
Отправлено: 26 Августа, 2020 - 21:28:19
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




ты вообще не понял ничего
ретурн НУЖНО использовать
и только его
никаких глобал или статик
результат работы фции только в ретурне
hehagog545 пишет:
он просто не вернётся из недр
как это? вернется из самого первого вызова
накопившись во внетренних
глянь еще раз мои реализации рекурсии выше
попробуй мысленно выполнить действия
(Добавление)
лучше я уже не объясню
удаляюсь
(Добавление)
каждый вызов это новый экземпляр фции
 
 Top
hehagog545
Отправлено: 27 Августа, 2020 - 09:29:44
Post Id


Новичок


Покинул форум
Сообщений всего: 11
Дата рег-ции: Авг. 2020  


Помог: 0 раз(а)




LIME ок, спасибо, я не правильно представил себе работу ретурна Растерялся

Объясните пожалуйста почему в этом примере счетчик работает:
Листинг 1
PHP:
скопировать код в буфер обмена
  1.  
  2. function sum14($quantityTry = 1)
  3. {
  4.         $res;
  5.         for ($i = 0; $i <= 3; $i++)
  6.         {
  7.                 $count += rand(0,5);
  8.         }
  9.  
  10.         if($count < 14)
  11.         {
  12.                 $quantityTry++;
  13.                 sum14($quantityTry);
  14.         }
  15.         else
  16.         {      
  17.                 // Работает счётчик
  18.                 echo $res = 'Результат ' . $count . '. За ' . $quantityTry . ' попыток';
  19.         }
  20.                
  21. }
  22.  


А в этом счётчик не работает:
Листинг 2
PHP:
скопировать код в буфер обмена
  1.  
  2. function sum14($quantityTry = 1)
  3. {
  4.         $res;
  5.         for ($i = 0; $i <= 3; $i++)
  6.         {
  7.                 $count += rand(0,5);
  8.         }
  9.  
  10.         if($count < 14)
  11.         {
  12.                 $quantityTry++;
  13.                 sum14($quantityTry);
  14.         }
  15.         else
  16.         {      
  17.                 // Не работает счётчик
  18.                 return $res = 'Результат ' . $count . '. За ' . $quantityTry . ' попыток';
  19.         }
  20.                
  21. }      
  22.                        
  23. echo sum14();
  24.  


И ещё одно недоразумение увиделось. В листинге 1 'Результат' бывает равен и 16 и 17 и 18.
Как такое может быть, если максимальное рандомное число 5 и оно суммируется не более 3ёх раз?
(5 * 3 = 15 // максимум)
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB