• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Kurs C++ - odc. 5 (liczenie ciągu Fibonacciego)

Fiszki IT
Fiszki IT
0 głosów
899 wizyt
pytanie zadane 7 lutego 2019 w C i C++ przez akinhet Nowicjusz (170 p.)

Witam, otóż kilka dni temu zacząłem naukę C++ wraz z serią video poradników pana Mirosława. Dotarłem do odcinka piątego i gdy pan Mirosław opisał na czym ma polegać ostatni przykład w tym odcinku, postanowiłem, że spróbuje sam go zrobić. Po uzupełnieniu kodu o kilka rzeczy, o których pan Mirosław mówił podczas wyjaśniania danego zadania i kilku testach zauważyłem dziwną właściwość mojego kodu. Otóż, gdy chciałem wyznaczyć 50 liczb Fibonacciego, ostatnia 50 liczba wyświetlała się jako dosyć długi zapis typu long double, jednak z minusem, a nie jak można by się spodziewać plusem. Co więcej problem znikał (50 wyświetlało się jako poprawny wynik), gdy tylko zmieniałem długość ciągu o jakąkolwiek wartość, zarówno w górę jak i w dół. Całą sytuację zbadałem nieco dogłębniej i jak się okazało problem dotyczy wszystkich liczb w których na końcu jest jedno zero, a przed nim liczba nieparzysta, choć nie wszystkich (np. 2210,  ale już 2010 wyświetla się źle). Czy może mi ktoś wytłumaczyć co jest nie tak z tym kodem? Z góry dzięki.

#include <iostream>
#include <iomanip>

using namespace std;

int liczba;

int main()
{
    cout << "Podaj do ktorej liczby chcesz wyznaczyc ciag Fibonacciego: " << endl;
    cin >> liczba;

    //Ustalanie wartości dwóch pierwszych liczb w ciągu
    long double fib[liczba-1];
    fib[0] = 1;
    fib[1] = 1;

    //Liczenie kolejnych liczb ciągu
    for(int i=2; i<liczba; i++)
    {
        fib[i] = fib[i-1] + fib[i-2];
    }

    cout << setprecision(liczba);

    //Wyświetlanie kolejnych liczb ciągu
    for(int i=0; i<liczba; i++)
    {
        cout << endl << i+1 << ". " << fib[i];
    }

    //Wyświetlanie konkretnej liczby ciągu
    //cout << liczba << ". " << fib[liczba-1];

    //Obliczanie przybliżenia złotej proporcji
    //cout << "zlota liczba " << fib[liczba-1]/fib[liczba-2];

    return 0;
}

 

2 odpowiedzi

0 głosów
odpowiedź 7 lutego 2019 przez niezalogowany
wybrane 7 lutego 2019 przez akinhet
 
Najlepsza

Co jest nie tak z tym kodem?

  1. Tworzysz tablicę o rozmiarze liczba - 1, a w pętli odwołujesz się do elementu poza tablicą(fib[i = liczba]). Więc wynik jest tak naprawdę losowy (UB). To powinno rozwiązać problem.
  2. Stosujesz VLA, co jest całkowicie niepotrzebne. Tablice o zmiennym rozmiarze tworzy się inaczej.
  3. Nie ma sensu operować na liczbach zmiennoprzecinkowych (jeżeli pierwsze wyrazy są całkowite). Typy zmiennoprzecinkowe nie są w stanie utrzymać precyzję tylko do kilku liczb. Użyj np long long int żeby wyniki były zawsze poprawne (oczywiście w obsługiwanym zakresie).
  4. Nie używaj zmiennych globalnych.
  5. Nie używaj przestrzeni nazw std::. 
  6. Nie stosuj komentarzy do opisywania trywialnych rzeczy. Kod jest na tyle czytelny, że na pierwszy rzut ok widać co się dzieje.
  7. Do nazywania zmiennych używaj języka angielskiego.

 Poprawny kod:

#include <iostream>

int main()
{
	int liczba;
	std::cout << "Podaj do ktorej liczby chcesz wyznaczyc ciag Fibonacciego: \n";
	std::cin >> liczba;

	long long int *fib = new long long int[liczba];
	fib[0] = 1;
	fib[1] = 1;

	for (int i = 2; i<liczba; i++)
	{
		fib[i] = fib[i - 1] + fib[i - 2];
	}

	for (int i = 0; i<liczba; i++)
	{
		std::cout << "\n" << i + 1 << ". " << fib[i];
	}
    delete[] fib;
}
komentarz 7 lutego 2019 przez akinhet Nowicjusz (170 p.)

1. Szczerze też nie wiem z czego to wynika. Łap kod, może u ciebie będzie coś innego (dodam, że ja korzystam z Code Blocksa z GNU GCC Compilerem).

#include <iostream>

int main()
{
    int liczba;

    std::cout << "Podaj do ktorej liczby chcesz wyznaczyc ciag Fibonacciego: " << std::endl;
    std::cin >> liczba;

    long long int fib[liczba-1];
    fib[0] = 1;
    fib[1] = 1;

    for(int i=2; i<liczba; i++)
    {
        fib[i] = fib[i-1] + fib[i-2];
    }

    for(int i=0; i<liczba; i++)
    {
        std::cout << std::endl << i+1 << ". " << fib[i];
    }

    //std::cout << std::endl << liczba << ". " << fib[liczba-1];

    //std::cout << std::endl << "zlota liczba " << fib[liczba-1]/fib[liczba-2];

    return 0;
}

2. Rozumiem to jak najbardziej, tylko nie wydało mi się to zbyt logiczne.

5. Ok, postaram się.

7. Dzięki :D Tak nieskromnie dodam, że gdy uczyłem się html-a i trochę JS-a to właśnie z takiej anglojęzycznej stronki korzystałem, chociaż html-a do końca nigdy nie ogarnąłem, gdy zaczęli dorzucać do niego jakieś zabezpieczenia związane z JS-em (a certyfikat dostałem i tak XD).

A za rady też jak najbardziej dzięki :D Przymierzam się teraz gdzie pójść po podstawówce, więc każda rada jest dla mnie super. A tak już by the way, to jak uważasz, lepsze jest technikum czy samouctwo? Bo szczerze tuż za rogiem egzamin po podstawówce, a ja nadal zbytnio nie wiem gdzie pójdę XD.

komentarz 7 lutego 2019 przez niezalogowany
1. Mój GCC faktycznie policzył ostatni wynik :D Nie zmienia to faktu, że to jest to UB i nie ma gwarancji, że zawsze tak będzie. Na przykład możesz przez przypadek spróbować przez przypadek odwołać się do pamięci innego programu co skończy się prawdopodobnie zamknięciem programu. Usuń -1 - tak jak jest w kodzie co poprawiłem.

To zależy od bardzo wielu czynników. Warto wybrać dobre technikum. W tym czasie będziesz miał czas żeby znaleźć ulubione technologie i względem nich wybierzesz dalszy rozwój. Poczytaj też inne tematy na forum o tym. Warto pomyśleć o studiach - często jest to ważny atut - chociaż jest to bardzo zależne o wybranej drogi. C++ to nie jest jedyna droga rozwoju. Pamiętaj to tym ;) Może okaże się, że będziesz wolał Javę czy Pythona. Myślę, że jak określisz swoje preferencje i będziesz miał już jakąś większą wiedzę to sam znajdziesz najlepszą dla siebie odpowiedź.
komentarz 7 lutego 2019 przez akinhet Nowicjusz (170 p.)
1. No widzisz :D Ale faktycznie, już to wyrzuciłem i przeformatowałem kod tak jak poradziłeś.

 Generalnie to w dzisiejszej perspektywie studia są priorytetem, ale jak to mówią pożyjemy, zobaczymy. Na ten moment technikum wydaje mi się najrozsądniejsze, dlatego staram się przyswoić tych kilka najpopularniejszych języków przyswoić, ale w praktyce C++ to jest drugi język za który się faktycznie poważnie zabrałem (wcześniej był html, ale go trochę porzuciłem nie znajdując w nim nic atrakcyjnego). Jeszcze po drodze była przygoda ze Small Basic-iem, ale powiedzmy sobie szczerze: to nie jest poważny język programowania. Javy, ani Pythona jeszcze nie próbowałem, chociaż słyszałem, że Java jest dość niewdzięcznym językiem i, że lepiej się zabrać za Pythona, bo podobno jest bardziej uniwersalny i przystępniejszy.
komentarz 7 lutego 2019 przez niezalogowany
Wszystko zależy od tego jak bardzo się zainteresujesz. Możesz trafić na złe studia/szkołę gdzie uczy się złych praktyk i przestarzałych technologii, albo wykładowcy nie ma zbyt dużej wiedzy. Może być pół na pół, a może być naprawdę nieźle - zdobędziesz wachlarz wiedzy i umiejętności, lub na którą mógłbyś sam nie trafić.

Co do Pythona również uważam, że jest prosty i przyjemny (chociaż słyszałem, że jest trudny w masterowaniu). Java w sumie też uważam jako fajny język do pewnych zastosowań. Wszystko zależy od preferencji ;)
komentarz 7 lutego 2019 przez akinhet Nowicjusz (170 p.)

No nie wiem, pożyjemy, zobaczymy. W każdym razie dzięki za pomoc i na razie smiley.

0 głosów
odpowiedź 7 lutego 2019 przez FuRaJ Nowicjusz (140 p.)

Cześć Akihnet!

Twój problem wynika z faktu, iż przypisałeś funkcję setprecision do zmiennej liczba zamiast wskazać maszynie liczbę cyfr co do dokładności jej obliczeń.

-> cout << setprecision(liczba);

Zamiast tego powinieneś ustawić np. 

-> cout << setprecision(50);

Dzięki temu twój program będzie wyświetlał wynik z dokładnością do pięćdziesięciu cyfr.


Odpowiedź na pytanie dlaczego w Twoim przypadku pięćdziesiąta liczba w ciągu Fibonacciego wyświetlała się niepoprawnie nasuwa się sama. 

 

Pozdrawiam cieplutko i powodzenia w nauce! ^^

 

komentarz 7 lutego 2019 przez akinhet Nowicjusz (170 p.)
edycja 7 lutego 2019 przez akinhet

Ok, w takim razie pytanie: czy setprecision nie może operować zmiennymi? Poza tym czy to przypadkiem nie oznaczało by, że każda ostatnia policzona liczba byłaby źle obliczoną? Bo generalnie jeżeli setprecision może wyciągać dane ze zmiennych to nie widzę przyczyn dlaczego tak miałoby się dziać, dlatego, że wśród liczb Fibonacciego numery porządkowe rosną znacznie szybciej niż liczba cyfr w liczbach (jest to około 1 dodatkowa cyfra co 4 - 5 kolejnych liczb).

Podobne pytania

0 głosów
1 odpowiedź 139 wizyt
0 głosów
2 odpowiedzi 225 wizyt
pytanie zadane 7 lipca 2015 w C i C++ przez A1ien1385 Nowicjusz (150 p.)
0 głosów
2 odpowiedzi 180 wizyt
pytanie zadane 3 maja 2015 w C i C++ przez Wiktor Stary wyjadacz (11,100 p.)
Porady nie od parady
Forum posiada swój własny serwer Discord, dzięki któremu będziesz mógł po prostu pogadać z innymi Pasjonatami lub zapytać o jakiś problem. Podstrona z chatem znajduje się w menu pod ikoną człowieka w dymku.IRC

84,746 zapytań

133,553 odpowiedzi

295,966 komentarzy

56,007 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...