Задача №4 - Вывести число Фибоначчи

Задачи №4 из этого списка:

Условие задачи:

Вывести на экран N-ное число Фибоначчи

Мое решение:

<?php
$f1 = 0;
$f2 = $f1 + 1;
echo $f1 . '<br>';
echo $f2 . '<br>';
for ($i=0; $i<rand(8, 15); $i++){
    $f3 = $f1 + $f2;
    echo $f3 . '<br>';
    $f1 = $f2;
    $f2 = $f3;
}

Key Words for FKN + antitotal forum (CS VSU):

melisa's picture

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

<?php
function fibonachi ($n)
{
    $f1 = 0;
    $f2 = $f1 + 1;
    echo $f1 . '<br>';
    echo $f2 . '<br>';
    for ($i = 3; $i <= $n; $i++) {
        $f3 = $f1 + $f2;
        echo $f3 . '<br>';
        $f1 = $f2;
        $f2 = $f3;
    }
}
fibonachi(8);
melisa's picture

Читайте условие внимательнее: на экране должен быть результат - N-ное число последовательности. Только одно число. Вы выводите всю последовательность. Можете выводить, для оценки корректности работы это даже хорошо. Но где результат?

Вуаля:

<?php
function fibonachi ($n)
{
    $k = rand(8, 20);
    echo 'Последовтельность состояит из ' . $k . ' элементов ' . '<br>';
    echo '<br>';
    $f1 = 0;
    $f2 = $f1 + 1;
    echo $f1 . '<br>';
    echo $f2 . '<br>';
    for ($i = 1; $i <= $k - 2; $i++){
        $f3 = $f1 + $f2;
        if ($n >= $k or abs($n - $k)<2){
            $s = 'находится за пределами текущей последовательности';
        } elseif ($n == $i){
            $s = $f3;
        }
        echo $f3 . '<br>';
        $f1 = $f2;
        $f2 = $f3;
    }
    echo '<br>';
    echo 'Номер числа последовательности: ' . $s;
}
$a = rand(8 , 20);
echo 'Необходимо вывести значение ' . $a . ' числа поcледовательности' . '<br>';
fibonachi($a);
melisa's picture

программа работает некорректно:

  1. Вы решили не совсем ту задачу, которая была по условию. В условии последовательность Фиббоначи. Она бесконечная, а значит, такого быть не может:

    находится за пределами текущей последовательности

    Ваша основная задача: вывести конкретное число бесконечной последовательности. Дан его порядковый номер (числа).

  2. $k = rand(8, 20);

    $k не может быть случайным. См. п.1 Последовательность бесконечная.

  3. for ($i = 1; $i <= $k - 2; $i++){

    можно использовать некое $k для вывода на экран части последовательности (с целью отладки), но как это может быть случайное число?

  4. Ответ в итоге неверный:

    Необходимо вывести значение 10 числа поcледовательности
    Последовтельность состояит из 14 элементов

    0
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    89
    144
    233

    Номер числа последовательности: 89

    Зачем мы выводили последовательность? Чтобы можно было прямо на экране посчитать тот ли порядковый элемент выводится. Считаем. Не тот(

<?php
function fibonachiValue ($n)
{
    echo 'Нужно вывести зачение номера последовательности ' . $n . '<br>';
    echo '<br>';
    $f1 = 0;
    $f2 = 1;
    if ($n == 0){
        echo 'Нулевого номера последоставльености не может быть!';
    } elseif ($n == 1){
        echo $f1 . '<br>';
        echo '<br>';
        echo 'Значение номера ' . $n . ' последовательности ' . $f1;
    } elseif ($n == 2){
        echo $f1 . '<br>';
        echo $f2 . '<br>';
        echo '<br>';
        echo 'Значение номера ' . $n . ' последовательности ' . $f2;
    } elseif ($n > 2) {
        echo $f1 . '<br>';
        echo $f2 . '<br>';
        for ($i = 3; $i <= $n; $i++) {
            $f3 = $f1 + $f2;
            echo $f3 . '<br>';
            $f1 = $f2;
            $f2 = $f3;
            if ($i == $n) {
                echo '<br>';
                echo 'Значение номера ' . $n . ' последовательности ' . $f3;
            }
        }
    }
}
fibonachiValue(rand(0, 4));

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

С нетерпением жду обратной связи!

melisa's picture

  1.         echo $f1 . '<br>';
            echo $f2 . '<br>';

    Это повторяющийся код, вынесите его из конструкции if-else наружу

  2. с отрицательными значениями не нужно

Код

echo $f1 . '<br>';
echo $f2 . '<br>';

да, повторяется, но не везде! При первом условии мы проверяем значение n=0 и f1 и f2 вообще не выводятся, дальше мы проверяем n=1, тогда выводится только f1, дальше n=2 и только здесь начинается вывод как f1 так и f2, и при n=3 выводятся все остальные значения

Мне кажется что выносить f1 и f2 не совсем целесообразно, либо, я просто не знаю как это сделать... подскажите!

melisa's picture

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

да, повторяется, но не везде!

И всё же я предлагаю выводить первые два числа последовательности всегда, даже если требуется найти 0 или 1 элемент. Это не так важно, т.к. вывод последовательности нужен только для отладки. В реальной программе после разработки мы его вообще удалим.

Всегда держите в голове, какой конкретно должен быть результат в задаче.

Какой у нас должен быть результат?

N-ное число последовательности: такое-то

О том, сколько чисел последовательности выведено на экран, ничего не сказано. Мы выводим последовательность чисто для того, чтобы можно быть посчитать пальчиком, правильно ли решено. Вот если бы Вы вывели меньше цифр последовательности, чем искомое, я бы Вам сказала:

А как я посчитаю? Выведите-ка побольше. Как я результат проверю?

Да, лишние данные тоже выводить ни к чему, но в данном случае, это скорее упростит нам задачу, чем усложнит. И на результат не повлияет.

Если хотите педантично подойти к выводу на экран, вынесите вывод первых двух элементов в отдельную функцию, и вызывайте там, где надо.

<?php
function fibonachiValue ($n)
{
    function outputF1 ($a){
        echo $a . '<br>';
    }
    function outputF1F2 ($a, $b){
        echo $a . '<br>';
        echo $b . '<br>';
    }
    echo 'Нужно вывести зачение номера последовательности ' . $n . '<br>';
    echo '<br>';
    $f1 = 0;
    $f2 = 1;
    if ($n == 0){
        echo 'Нулевого номера последовательности не может быть!';
    } elseif ($n == 1){
        outputF1($f1);
        echo '<br>' . 'Значение номера ' . $n . ' последовательности ' . $f1;
    } elseif ($n == 2){
        outputF1F2($f1, $f2);
        echo '<br>' . 'Значение номера ' . $n . ' последовательности ' . $f2;
    } elseif ($n > 2) {
        outputF1F2($f1, $f2);
        for ($i = 3; $i <= $n; $i++) {
            $f3 = $f1 + $f2;
            echo $f3 . '<br>';
            $f1 = $f2;
            $f2 = $f3;
            if ($i == $n) {
                echo '<br>' . 'Значение номера ' . $n . ' последовательности ' . $f3;
            }
        }
    }
}
fibonachiValue(rand(0, 4));
melisa's picture

  1. function fibonachiValue ($n)
    {
        function outputF1 ($a){
            echo $a . '<br>';
        }
        function outputF1F2 ($a, $b){
            echo $a . '<br>';
            echo $b . '<br>';
        }
        // ...
    }

    Возвращаемся к области видимости. Если Вы объявили функции внутри функции, Вы не сможете использовать их нигде "снаружи". А вот если объявите снаружи, то сможете и там, и там. Поэтому так не делают. Вынесите это из функции.

  2.     function outputF1 ($a){
            echo $a . '<br>';
        }
    • В функции всего одна строчка кода. Выделение её отдельно себя не оправдывает абсолютно. Что так одна, что так - никакого сокращения.
    • Если уж Вы её создали, используйте свой код:
      function outputF1F2 ($a, $b){
              outputF1($a);
              echo $b . '<br>';
          }
  3. function outputF1F2()

    Неправильное название. f1 и f2 - это всего лишь названия переменных, которые ни о чём не говорят. Мало того, что они, кстати, тоже могли бы называться более информативно, так ещё и в название метода их вставили...

    Это отдельная функция. Она делает НЕЧТО. И вот так и надо её назвать. Например, outputTwoStrings() или ещё конкретнее: outputTwoNumbersInColumn(). Самой функции всё равно, числа это Фибоначчи или календарь за 2018 год. Она печатает две строки в столбик.

Хотя я предлагала сделать проще ;)

Я все это понимаю, прекрасно понимаю!

Вы рассуждаете масштабами реальных проектов, в контексте того, что вот эта маленькая функция - это всего лишь небольшой функционал одного большого проекта и "захломлять" его не надо, от него требуется чтобы он просто правильно работал и все. Но поймите, для меня на текущий момент решение этой задачи и есть тот самый реальный большой проект, который я делаю. Да, я понимаю, где-то криво, где-то косо, но он мой... родной и он работает (конкретно в контексте этой задачи!). Безусловно та информация, которая Вы мне говорите - она очень ценная, основная ее ценность - это Ваш опыт, конечно же я очень и очень к ней прислушиваюсь и стараюсь делать все как надо, потому что Ваш опыт реализации реальных проектов говорит что "именно так, а не как иначе", потому что потом можно будет "заблудиться". Но ведь Вы тоже когда-то были на моем месте и я больше чем уверен в какой-то момент "заблудились" в одном из проектов и долго и мучительно искали решения тем самым нарабатывая свой опыт... Поэтому прошу Вас не судить меня строго, повторюсь Ваши советы очень ценны, спасибо Вам за них, но реального опыта я наберусь только при реализации реального проекта, всего же опыта не передашь и вот тогда, когда я пару раз "заблужусь" - я в очередной раз вспомню Вас и про себя скажу Вам огромное спасибо и продолжу искать выход из дебрей кода )))

Итого: задача принята?

melisa's picture

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

А так, да, принято.

Лучше удалить здесь несколько строк.

<?php
function fibonachiValue($n)
{
    $f1 = 0;
    $f2 = 1;
    $f3 = 0;
    
    for ($i = 1; $i <= $n; $i++) {
        $f3  = $f1;
        $f1  = $f2;
        $f2 += $f3;
    }

    echo '<br>' . 'Значение номера ' . $n . ' последовательности ' . $f3;
}

fibonachiValue(rand(0, 4));