Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

c++ - Bardziej "profesjonalny" kod (matura roz.)

IXOF 02 Oct 2014 20:05 5568 31
  • #1
    IXOF
    Level 18  
    Witam. Przymierzam się, aby w tym roku napisać maturę rozszerzoną, więc z arkuszy z dawnych lat wykonuje sobie programy. Tu jest treść zadania

    Code:
    Zadanie 5. Ciekawe napisy (10 pkt)
    
    W pliku NAPIS.TXT, w oddzielnych wierszach, znajduje się 1 000 napisów o długościach
    od 2 do 25 znaków. Każdy napis składa się z wielkich liter alfabetu łacińskiego.
    Wykorzystując dostępne narzędzia informatyczne, daj odpowiedzi do poniższych
    podpunktów. Odpowiedzi zapisz w kolejnych wierszach pliku ZADANIE5.TXT, a każdą
    poprzedź literą oznaczającą ten podpunkt.
    a) Napis pierwszy to taki napis, w którym suma kodów ASCII jest liczbą pierwszą.
    Przykładowo, suma kodów ASCII w napisie ABB wynosi 197 i jest liczbą pierwszą,
    co oznacza, że napis ABB jest napisem pierwszym. Podaj, ile jest napisów pierwszych
    w pliku NAPIS.TXT.
    b) Napis rosnący to taki napis, w którym kod ASCII każdej kolejnej litery jest większy
    od kodu poprzedniej. Podaj wszystkie napisy rosnące występujące w pliku NAPIS.TXT.
    c) Wypisz napisy z pliku NAPIS.TXT, które występują w nim więcej niż jeden raz (każdy
    taki napis wypisz tylko raz).




    Pierwsze dwa podpunkty wykonałem w miarę gładko, ale ostatni to męka. Dałem rade, ale (zaraz będzie kod) wykorzystałem tablice w której z góry założyłem jej rozmiar i oczywiście spora część pamięci zarezerwowanej jest nieużywana. Chciał bym to zrobić tak, aby używać tyle pamięci, ile potrzeba, nie mniej nie więcej, tylko nie bardzo mam pomysł. Szukałem coś o powiększaniu dynamicznej tablicy (realloc), ale nie bardzo umiem tego użyć. Kompilator (vs2013) wyrzucał
    Code:
    _crtIsValidHeapPointer(pUserData)

    yy znaczy nie kompilator. Kompilator przepuścił, ale gdy uruchomiłem program, to właśnie coś takiego wyskoczyło. I właśnie post pisze celem poznania lepszego sposobu na wykonanie tego polecenia, lub jakieś naprowadzenie (psedo kod czy coś) i wgl o ocenę bym prosił, czy Pan, który sprawdzał by mój kod do tego zadania nie zobaczył by jakichś rażących błędów.

    A tu kod :

    Code: cpp
    Log in, to see the code
  • Helpful post
    #2
    anonymousexd
    Level 24  
    W tym momencie program wyjdzie poza zakres tablicy jeśli w pliku będzie więcej niż 1000 napisów.
    Radzę skorzystać z std::vector lub dodać sprawdzanie ilości wczytanych napisów i jeśli przekroczy limit to break.
    Napisy wszystkie i tak musisz mieć w pamięci dla punktu c.
    Punkty a i b można by zrobić bez przechowywania wszystkich napisów jednocześnie w pamięci.

    W ostatnim punkcie aż prosi się wykorzystać tablicę hashującą dla optymalizacji szukania powtórzeń. A nawet jeśli nie chcesz korzystać z hashowania to i tak można by to zrobić szybciej (optymalniej), przemyśl swój kod.

    Do bool wyraz_rozsnacy(string a) przekazujesz teraz przez wartość - a możesz przekazywać w lepszy (a dokładniej szybszy) sposób, przez wskaźnik lub referencję.

    Wygodniej będzie jeśli załączysz też plik "NAPISY.txt" dla testów.
  • #3
    IXOF
    Level 18  
    Co do przekroczenia zakresów, to w zadaniu jest napisane, że plik ma 1000 napisów i na tyle jest robiony program ;) A punkty A i B robię podczas zapisywania do tablicy tzn.

    Pobieram napis, zapisuje do tablicy, robie punkty a i b i pobieram kolejny napis. Czy nie o to Ci chodzi mówiąc, że można je zrobić bez zapisu do tablicy ?


    Zgadza sie, że dla punktu C muszę mieć wszystko w tablicy, ale nie w dwóch. Jeżeli druga była by dynamiczna to jeszcze by przeszło, ale tak to mnie trochę w oczy kuje.
  • Helpful post
    #4
    anonymousexd
    Level 24  
    IXOF wrote:
    ]
    Zgadza sie, że dla punktu C muszę mieć wszystko w tablicy,


    Właśnie nie musisz mieć. Możesz w trakcie wczytywania sprawdzać czy dany napis wystąpił zero razy czy jeden raz. W przypadku zero - po prostu go dodajesz. W przypadku raz - dodajesz go i wypisujesz. W przypadku więcej niż raz - już go nie dodajesz do tablicy.

    Takich drobnych optymalizacji można w tym programie wymyśleć sporo.


    EDIT:

    Code: cpp
    Log in, to see the code

    Po co ta tablica: int * znaki = new int[a.length()];?
    Po co tam ten warunek if (a.length() -2 == licznik)? Bez tego bloku if można by się obyć, to tylko niepotrzebnie komplikuje kod.
    Czemu nie zwalniasz zajętej pamięci?
  • #5
    IXOF
    Level 18  
    anonymousexd wrote:






    Code: cpp
    Log in, to see the code


    Po co tam ten warunek if (a.length() -2 == licznik)? Bez tego bloku if można by się obyć, to tylko niepotrzebnie komplikuje kod.


    Tym fragmentem sprawdzam, czy każdy kolejny kod ascii znaku jest większy od poprzedniego, a ten warunek oznacza koniec wyrazu. W innym razie sprawdził bym, czy dwa sąsiadujące znaki są a<b i koniec, a musze jakoś przez cały wyraz przejść :)
  • Helpful post
    #6
    anonymousexd
    Level 24  
    Wiem co ten fragment kodu robi, i wiem że on poprawnie zwraca true lub false, ale sposób w jaki on to robi jest nieoptymalny i do tego każde wywołanie tej funkcji tworzy wyciek pamięci.
    W jakim celu jest tam tablica "znaki"?
  • #7
    IXOF
    Level 18  
    Hmmm, jest kompletnie bezużyteczna. Stworzyłem ją ponieważ kodem :

    Code: cpp
    Log in, to see the code




    Nie mogłem ruszyć programu. Wysypywał sie ponieważ było
    Code: cpp
    Log in, to see the code
    .
    Najpierw stworzyłem tablice, bo myślałem, że coś źle robie i tak będzie wygodniej, a potem doszedłem do tego, że musi być "-2" i wypadło mi z głowy, żeby to posprzątać.



    A na czym polega ten wyciek pamięci ? I w jaki sposób się go ustrzec ?
  • #9
    IXOF
    Level 18  
    hmmm, ale czy da się tak ją przerobić ? Wtedy wyrażenie char(a[licznik]) pominie mi pierwszy znak w wyrazie, co nie ?
  • #10
    anonymousexd
    Level 24  
    IXOF wrote:
    hmmm, ale czy da się tak ją przerobić ? Wtedy wyrażenie char(a[licznik]) pominie mi pierwszy znak w wyrazie, co nie ?


    Tak, ale przecież w bardzo prosty sposób możesz dostać się do znaku który jest jedno miejsce przed tym wskazanym przez licznik. Napisanie tego kodu jest banalne, mógłbym dać gotowca ale pomyśl chwilę i sam rozwiążesz problem.
  • #11
    IXOF
    Level 18  
    Code: cpp
    Log in, to see the code




    Czy o to chodziło ?
  • #12
    anonymousexd
    Level 24  
    IXOF wrote:
    Code: cpp
    Log in, to see the code




    Czy o to chodziło ?


    Już jest lepiej, ale wciąż nie zastosowałeś się do rady ze wskaźnikiem/referencją oraz rzutowanie na char w tym przypadku nie jest potrzebne.
  • #13
    IXOF
    Level 18  
    Referencję muszę poczytać dokładnie, bo jeszcze nie jestem pewny czy umiem, chodź z pierwszego wyniku z google jaki znalazłem nie wygląda to ciężko.
    Dlaczego rzutowanie nie jest potrzebne ? Program sam się domyśli, że gdy porównuje znaki to chodzi mi o ich kody ASCII ? :) c++ jest aż tak mądry ? :)
  • #14
    anonymousexd
    Level 24  
    IXOF wrote:

    Dlaczego rzutowanie nie jest potrzebne ? Program sam się domyśli, że gdy porównuje znaki to chodzi mi o ich kody ASCII ? :) c++ jest aż tak mądry ? :)


    Tu nawet nie o to chodzi. W przypadku obiektu string s już samo s[0] zwraca typ char, a jak zapewne się domyślasz rzutowanie char na char nie ma żadnego sensu.
  • Helpful post
    #16
    mcvsama
    Level 16  
    IXOF Zauważ, że wciąż w tej funkcji jest trochę niepotrzebnych rzeczy.

    Code: cpp
    Log in, to see the code


    Można napisać bardziej czytelnie: jeśli dany znak jest <= poprzedni znak. Czyli tak:

    Code: cpp
    Log in, to see the code


    Druga rzecz to taka, że prawie zawsze, w większości języków przyjmuje się że i, j, k, to takie typowe zmienne do iterowania po pętlach. Jeśli pętla jest bardzo rozwlekła, to może warto stosować pełne słowa, ale jeśli mieści się w trzech liniach, to jednoliterowe "i" będzie czytelniejsze. Oceń sam:

    Code: cpp
    Log in, to see the code
  • #17
    anonymousexd
    Level 24  
    Ale takie "i" nie mówi wcale czym ta zmienna jest. Jak już to lepiej dla indeksu znaku (char) skorzystaj z literki "c". Wtedy kod jest jeszcze bardziej czytelny.
  • #18
    mcvsama
    Level 16  
    Nie musi mówić, bo kod ma trzy linie i to widać od razu. Jeśli użyjesz c, to to będzie błędnie sugerować, że c zawiera znak, a nie jego indeks. *Edit* Chociaż z drugiej strony, jeśli widać, że c jest wewnątrz [], to też widać, że to raczej indeks (choć nie zawsze musi tak być).

    Popatrzyłem na oryginalny kod i mam jeszcze kilka innych uwag:
    • Zamiast pisać „TUTAJ ZACZYNA SIĘ PUNKT C” może lepiej po prostu wkleić ten punkt C, żeby od razu było wiadomo o co chodzi?
    • Zamiast licznik_a,_b,_c po prostu napisz o co chodzi: liczba_rosnacych, liczba_pierwszych, itp.
    • Nie musisz pisać if (a == true) – if w nawiasach przyjmuje wyrażenie logiczne. Jeśli a jest true, to nie trzeba dodatkowo go porównywać jeszcze raz do true.
    • Unikaj używania tablic bezpośrednio. Zwykle lepiej użyć std::array<> albo std::vector<>.
    • Do sprawdzenia powtarzających się napisów użyj std::multiset<>. Dodasz do niego każdy wyraz po kolei. Na końcu przejedziesz od multiset.begin() do .end() i uzyskasz liczbę powtórzeń za pomocą metody count() - tam, gdzie zwróci więcej niż 1, oznaczać będzie, że wyraz się powtórzył.
    • Funkcję liczba_pierwsza() możesz przerobić na bardzo podobną do wyraz_rosnący:

    Code: cpp
    Log in, to see the code
  • #19
    anonymousexd
    Level 24  
    mcvsama wrote:

     Unikaj używania tablic bezpośrednio. Zwykle lepiej użyć std::array<> albo std::vector<>.


    Nie radziłbym tak w przypadku kodu który ma być czysty i wykonywać się szybko. Czasem lepiej zaolokować więcej pamięci (jednokrotnie) i korzystać z zwykłej tablicy niż co chwila wywoływać "push_back" i operator []. Co prawda jest jeszcze reserve, ale nie komplikujmy już.


    mcvsama wrote:
    Jeśli użyjesz c, to to będzie błędnie sugerować, że c zawiera znak, a nie jego indeks. *Edit* Chociaż z drugiej strony, jeśli widać, że c jest wewnątrz [], to też widać, że to raczej indeks (choć nie zawsze musi tak być).


    I tak i nie, ale:
    Quote:
    W pliku NAPIS.TXT, w oddzielnych wierszach, znajduje się 1 000 napisów o długościach
    od 2 do 25 znaków.

    tutaj de facto te "c" mogłoby być typu char, bo przecież on i tak jest typem liczbowym, i to takim który mieści ilości z zakresu z polecenia zadania (2-25). Z tym że to by dużo nie dało bo procesor i tak pewnie by z tego nie skorzystał.
  • #20
    mcvsama
    Level 16  
    Plus dla tablic to szybkość, ale lepiej używać ich _tylko_ kiedy szybkość jest krytyczna. Wektory są tylko nieznacznie wolniejsze przy dostępie do elementów. Nie ma potrzeby używania w tym przypadku .push_back(), bo liczba napisów do wczytania jest znana. Konstruujesz od razu wektor danego rozmiaru i używasz tak jak tablicy. No i moim zdaniem bawienie się w ręczną obsługę tablicy jest bardziej komplikowaniem, niż użycie gotowego wektora, który to już ma w środku. ;-)

    Natomiast alokując tablice ręcznie musisz pamiętać o ich zwolnieniu (i to z delete[] a nie delete) nie tylko przy wyjściu z funkcji, ale także w przypadku gdy coś w środku kodu może rzucić wyjątkiem. Jeśli obu rzeczy nie obsłużysz, to powstanie wyciek pamięci. IXOF w swoim programie tablicę zaalokował i jej zapomniał zwolnić. Więc po co ręcznie bawić się w zarządzanie zasobami, skoro od tego jest RAII?

    'c' mogło by być typu char, ale w rejestrze i tak będzie miał on 32 albo 64 bity. Procesorowi nie robi to żadnej różnicy.
  • #21
    anonymousexd
    Level 24  
    mcvsama wrote:
    liczba napisów do wczytania jest znana.


    Przy tym założeniu idea użycia dynamicznej tablicy całkiem traci sens - bo po co tu dynamika? Jednym z nielicznych plusów tego rozwiązania może być tylko sprawdzanie błędów indexu przez vector.

    mcvsama wrote:

    Natomiast alokując tablice ręcznie musisz pamiętać o ich zwolnieniu


    A nie zgodzę się, w przypadku operatora new to jest oczywiście prawda, ale jest też inny sposób alokacji pamięci na stosie (dynamicznie) która się sama "zwalnia", ale to już jest mało znany mechanizm języka i często się z niego nie korzysta.
  • #22
    mcvsama
    Level 16  
    anonymousexd wrote:
    Przy tym założeniu idea użycia dynamicznej tablicy całkiem traci sens - bo po co tu dynamika?


    Dlatego przecież pisałem też o std::array<>. std::vector<> nie sprawdza błędów, tzn. nie ma takiego wymogu. Mnie chodzi o zarządzanie zasobami.

    anonymousexd wrote:
    A nie zgodzę się, w przypadku operatora new to jest oczywiście prawda, ale jest też inny sposób alokacji pamięci na stosie (dynamicznie) która się sama "zwalnia", ale to już jest mało znany mechanizm języka i często się z niego nie korzysta.


    Bo alloca() jest hakiem i zupełnie nie nadaje się do C++ (tylko do C). Jeśli braknie pamięci, to wtedy jest Undefined Behaviour. Po drugie - każdy element std::array<> czy std::vector<> zostanie poprawnie skonstruowany/zdekonstruowany. Jeśli skopiowałeś tam obiekty z nietrywialnymi destruktorami, to zostaną one poprawnie wywołane (w końcu RAII). A alloca() ma to w d…, więc po wyjściu ze scope'a zostaniesz z programem w jakimś niezdefiniowanym stanie (w przypadku std::string, których używa IXOF będzie wyciek pamięci, bo std::string swoją „treść” alokuje na stercie). Jeśli chciałbyś tego uniknąć… to niestety musiałbyś jawnie wywołać wszystkie destruktory. To po prostu nie jest rozwiązanie.

    Nie pominę też tego, że jest niewygodna, bo dostajesz z niej wskaźnik i musisz pamiętać jaki był rozmiar tablicy, bo nawet nie sprawdzisz sobie za pomocą metody .size() chociażby. ;-) A stos jest zwykle ograniczony, więc o większych tablicach lepiej zapomnieć (UB).

    W ogóle o czym ja mówię, żeby korzystać z alloca() to trzeba się ograniczyć wyłącznie do typów prostych i klas POD. Jakiekolwiek inne to haki z masą rzutowań wskaźników, jawnego wołania konstruktorów i destruktorów. Szkoda się męczyć…
  • #23
    IXOF
    Level 18  
    mcvsama wrote:
    IXOF Zauważ, że wciąż w tej funkcji jest trochę niepotrzebnych rzeczy.

    Code: cpp
    Log in, to see the code


    Można napisać bardziej czytelnie: jeśli dany znak jest <= poprzedni znak. Czyli tak:

    Code: cpp
    Log in, to see the code


    Druga rzecz to taka, że prawie zawsze, w większości języków przyjmuje się że i, j, k, to takie typowe zmienne do iterowania po pętlach. Jeśli pętla jest bardzo rozwlekła, to może warto stosować pełne słowa, ale jeśli mieści się w trzech liniach, to jednoliterowe "i" będzie czytelniejsze. Oceń sam:

    Code: cpp
    Log in, to see the code



    Wybacz kolego, ale po raz, to znak <= chyba być nie może, bo żaden element nie może się równać tyle co sąsiad. Wtedy wyraz nie jest rosnący, a po drugie, to może bardziej doświadczeni i owszem ale ja uważam, że mój zapis jest czytelniejszy. Twój zrozumiałem dopiero jak sobie rozrysowałem w paincie :D Co do i,j,k to kiedyś gdzieś przeczytałem, że zmienne dobrze jest deklarować względem ich użycia a nic o pętlach nie było. Spróbuje zmienić ten nawyk.





    mcvsama wrote:


    Popatrzyłem na oryginalny kod i mam jeszcze kilka innych uwag:
     Zamiast pisać „TUTAJ ZACZYNA SIĘ PUNKT C” może lepiej po prostu wkleić ten punkt C, żeby od razu było wiadomo o co chodzi?
     Zamiast licznik_a,_b,_c po prostu napisz o co chodzi: liczba_rosnacych, liczba_pierwszych, itp.

    [/syntax]




    No ten komentarz był po to, żeby nikt nie musiał się zagłębiać dokładnie gdzie zaczyna sie punkt C. A wkleiłem cały kod, bo jak zapewne zauważyłeś poprosiłem o ocenę całego programu :) Co do licznik_a to nie chciało mi się pisać dłuższej(Twojej wersji), żeby potem mniej pisania było. Zawsze to trochę znaków mniej, chociaż w sumie i tak są sugestie.. Chodziło o "licznik do pkt a, b itd.. "

    Co do kolejnych 3 pkt wezmę je sobie do serca ;)


    mcvsama wrote:


     Funkcję liczba_pierwsza() możesz przerobić na bardzo podobną do wyraz_rosnący:

    Code: cpp
    Log in, to see the code


    Co do tej funkcji to też ciężko miałem ją zrozumieć. W sumie to już pisałem posta, że to nie ma prawa działać, ale wrzuciłem to do kompilatora i ... działa :) przysiadłem i załapałem jak. Ale nie każdy na pierwszy rzut oka skojarzy, że żadna liczba parzysta oprócz 2 nie jest pierwsza :)
  • Helpful post
    #24
    mcvsama
    Level 16  
    IXOF wrote:
    Code: cpp
    Log in, to see the code


    Wybacz kolego, ale po raz, to znak <= chyba być nie może, bo żaden element nie może się równać tyle co sąsiad.


    Wybaczam, albowiem nie zauważyłeś, że w Twojej wersji była negacja (!), a w mojej nie ma. ;-) Wtedy < trzeba zamienić na >=, ale że zamieniłem miejscami lewy i prawy argument, to operator też zmienił kierunek na <=.

    Spróbuj przeczytać tego ifa tak jak leci: jeśli i-ty znak jest mniejszy lub równy poprzedniemu (i-ty minus 1), to należy przerwać z wynikiem „nie jest rosnący” (return false). Ale Twój kod też jest całkowicie OK. Poza tymi nadmiarowymi char() oczywiście.

    Nie musisz zmieniać nawyków. Zwykle jest tak, że krótsze słowa łatwiej ogarnąć wzrokiem, ale jeśli wolisz długie to czemu nie?

    Co do reszty - OK. Staram się pomóc ogólnie, mogę nie wiedzieć, że np. specjalnie dodałeś taki czy inny komentarz na potrzeby posta. :-)

    IXOF wrote:
    Co do tej funkcji to też ciężko miałem ją zrozumieć.


    Widocznie źle ją skomentowałem, założyłem że będzie to zbędne. Chodzi o to, że dwa proste przypadki (liczby 1 i mniejsze oraz 2) sprawdzasz trywialnie na początku (dwa pierwsze ify), a dla innych liczb sprawdzasz czy się dzielą przez _jakąkolwiek_ liczbę inną niż 1 i same siebie. Dlatego zakres pętli jest (i = 2; i < liczba - 1). I oczywiście popełniłem tutaj błąd, bo powinienem był sprawdzić i < liczba, nie liczba - 1. Albo i <= liczba - 1. Ale wracając - jeśli gdzieś w środku okaże się, że "liczba modulo i daje 0" (czytaj: "liczba" dzieli się przez "i"), to znaczy, że "liczba" nie może być pierwsza.

    Dlaczego pisałem, że ta funkcja jest dosyć podobna do wyraz_rosnacy()? Bo ona przerywa działanie od razu, gdy wykryje, że liczba nie może być pierwsza. Nie musi przelatywać wszystkich dzielników i zliczać, wystarczy, że znajdzie trzeci, żeby powiedzieć, że nie jest pierwsza. Podobnie wyraz_rosnacy() nie sprawdza wszystkich znaków - jeśli znajdzie pierwszy przypadek, gdzie kolejny znak jest niewiększy niż poprzedni, to już wiadomo, że wyraz nie jest „rosnący”.

    Z czasem spokojnie zaczniesz łapać takie rzeczy w mig, także nie obawiaj się, gdyż przyszłość jest świetlana!

    "There are only two hard problems in Computer Science: cache invalidation, naming things and off-by-one errors."
  • #25
    IXOF
    Level 18  
    IXOF wrote:
    Twój zrozumiałem dopiero jak sobie rozrysowałem w paincie




    mcvsama wrote:



    Wybaczam, albowiem nie zauważyłeś, że w Twojej wersji była negacja (!), a w mojej nie ma. ;-) Wtedy < trzeba zamienić na >=, ale że zamieniłem miejscami lewy i prawy argument, to operator też zmienił kierunek na <=.


    Odszczekuje wszystko i zwraca honor. Jednak nawet rozrysowanie w paincie nie pomogło. Zapomniało mi się zwrócić uwagę, że zamieniłeś porównywane pola miejscami (z lewej na prawą) i podczas analizy źle wstawiałem <=. Teraz jest wszystko jasne ;)



    mcvsama wrote:


    I oczywiście popełniłem tutaj błąd, bo powinienem był sprawdzić i < liczba, nie liczba - 1. Albo i <= liczba - 1.


    Błąd błędem, ale funkcja zadziałała poprawnie, zwróciła wynik taki jak moja funkcja i taki wynik jest w odpowiedzi. W sumie to pomyli się, jeżeli liczba, której nie sprawdziłeś okaże sie podzielna przez i, czy tak ?


    mcvsama wrote:

    Dlaczego pisałem, że ta funkcja jest dosyć podobna do wyraz_rosnacy()? Bo ona przerywa działanie od razu, gdy wykryje, że liczba nie może być pierwsza. Nie musi przelatywać wszystkich dzielników i zliczać, wystarczy, że znajdzie trzeci, żeby powiedzieć, że nie jest pierwsza. Podobnie wyraz_rosnacy() nie sprawdza wszystkich znaków - jeśli znajdzie pierwszy przypadek, gdzie kolejny znak jest niewiększy niż poprzedni, to już wiadomo, że wyraz nie jest „rosnący”.



    Tu się zgodzę, ale muszę bronić mojej funkcji liczba_pierwsza() ponieważ ona też nie przelatuje liczby do końca, tylko gdy wykryje więcej niż 2 dzielniki odrazu zwraca false ;) Jedyne co chyba jej brakuje to sprawdzenie na starcie liczb 0-2 ;)
  • Helpful post
    #26
    mcvsama
    Level 16  
    IXOF wrote:
    Błąd błędem, ale funkcja zadziałała poprawnie, zwróciła wynik taki jak moja funkcja i taki wynik jest w odpowiedzi. W sumie to pomyli się, jeżeli liczba, której nie sprawdziłeś okaże sie podzielna przez i, czy tak ?


    Pomyli się, jeśli liczba będzie podzielna przez 1, samą siebie i samą siebie pomniejszoną o 1. Myślę, że gdzieś na pewno znajdzie się taki przypadek, nawet jeśli dla liczb 0..100 zadziała poprawnie, to gdzieś tam dalej na pewno czai się taka wyjątkowa, dla której funkcja zadziała źle. :þ

    IXOF wrote:
    Tu się zgodzę, ale muszę bronić mojej funkcji liczba_pierwsza() ponieważ ona też nie przelatuje liczby do końca, tylko gdy wykryje więcej niż 2 dzielniki odrazu zwraca false ;)


    Całkowita racja! Niestarannie przeczytałem Twoją wersję.
  • #27
    anonymousexd
    Level 24  
    mcvsama wrote:

    Pomyli się, jeśli liczba będzie podzielna przez 1, samą siebie i samą siebie pomniejszoną o 1. Myślę, że gdzieś na pewno znajdzie się taki przypadek, nawet jeśli dla liczb 0..100 zadziała poprawnie, to gdzieś tam dalej na pewno czai się taka wyjątkowa, dla której funkcja zadziała źle. :þ


    Nie wprowadzaj ludzi w błąd. Nigdzie nie znajdzie się taki przypadek. Nawet nie znajdzie się dla liczb 0...oo! Dla danego N wszystkie jego dzielniki należą do od 1 do N/2, a dokładniej: do sqrt(N) - podstawy matematyki się kłaniają.
  • #28
    mcvsama
    Level 16  
    anonymousexd wrote:
    Nie wprowadzaj ludzi w błąd. Nigdzie nie znajdzie się taki przypadek. Nawet nie znajdzie się dla liczb 0...oo! Dla danego N wszystkie jego dzielniki należą do od 1 do N/2, a dokładniej: do sqrt(N) - podstawy matematyki się kłaniają.


    Racja, więc można skrócić jeszcze bardziej pętlę.
  • #29
    IXOF
    Level 18  
    Mam jeszcze pytanie. Chce sobie na dniach w domu zrobić maturę, tylko jeszcze jedno jest dla mnie nie jasne. Sposób zapisu algorytmów na ów maturze. A mianowicie, co znaczy coś takiego ?

    http://cke.edu.pl/images/files/matura/arkusze_2014/informatyka_PP_1_A1.pdf

    Zadanie 1 punkt 2.2.

    Chodzi mi o tą strzałkę, wtf ?

    Nie zamieściłem przykładu ponieważ zamiast strzałki pokazywał się kwadracik ;)
  • #30
    mcvsama
    Level 16  
    Zapewne „przypisz d+1 do d”.