Strona 1 z 3 123 OstatniOstatni
Pokaż wyniki 1 do 10 z 21

Temat: Błędny program - średnia

  1. #1
    Zarejestrowany
    Feb 2009
    Postów
    51

    Domyślnie Błędny program - średnia

    Próbuję napisać pewien program. Liczy on średnią ocen uczniów.
    Jednak program nie działa. Próbowałem go zmieniać, ale było jeszcze gorzej.
    Jest to program ze SPOJa, jeśli ktoś wie, co to jest. Tu jest treść zadania (nie trzeba się logować ani nic z tych rzeczy):
    http://pl.spoj.pl/problems/PPODST/

    A oto mój kod:
    Kod:
    #!/usr/bin/perl
    # Autor: kokosoko
    use strict;
    my $tekst = <STDIN>;
    my $x=0;
    my $suma;
    my $n;
    $n = <STDIN>;
    while($n--)
    {
    $tekst =~ /\w\s+\w\s+(\d+(\.\d+)?)/;
    $x+=$5;
    }
    $x=sprintf "%.2f",$x/$n;
    print "$x\n";
    Liczy się długość kodu, ale skrócę go potem. Najbardziej mnie intryguje, co może być źle, bo próbowałem postępować wg instrukcji TQM odnośnie regex-ów z tego trzeciego tutoriala z PERLa.
    Ostatnio edytowane przez kokosoko : 04-27-2009 - 16:39

  2. #2
    Avatar GSG-9
    GSG-9 jest offline Shapeshifter
    Zarejestrowany
    Jul 2007
    Skąd
    C:\Perl\bin
    Postów
    1,578

    Domyślnie

    napisalem cos takiego, niestety nie zaokragla jak trzeba, ale wynik jest bardzo bliski. o czyms zapomnialem?
    Kod:
    #! perl
    use strict;
    my @tab;
    chomp( my $count = <STDIN> ); # liczbe uczniow ignoruje, nie przyda sie :P
    while(<STDIN>)
    {
    if($_ =~ /^\s*$/) { licz(); }
    if (/(\d.\d+)/ or /(\d)/)  {push (@tab, "$1");}
    }
    sub licz { 
    my $srednia = $tab[int($#tab / 2)] + (($tab[int($#tab / 2) + 1] - $tab[int($#tab / 2)]) / 2);
    print $srednia;
    }
    War, war never changes.

  3. #3
    Zarejestrowany
    Feb 2009
    Postów
    51

    Domyślnie

    Tyle że to trochę za bardzo zaawansowany kod, jak na mnie. A nie chcę mieć zrobionego tego zadania przez kogoś, tylko nauczyć się na moich błędach i przy pomocy zrobić je [prawie] sam. Nie sprawiłoby mi satysfakcji wklejenie kodu na żywca zgapionego.
    Ale i tak dzięki, że Ci się chciało.

  4. #4
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Ja bym to zapisal w 1 linii ale najpierw moze podaj tak...

    Mamy wczytac dane z STDIN - pierwsza linia to ilosc uczniow, pozostale linie to Imie Nazwisko Srednia (srednia ucznia, moze byc zapisana jako N.NN).

    Co ja bym zrobil?
    1. Olac pierwsza linie - nie interesuje nas, bo to liczba uczniow... a co jesli liczba ucznow podana w tej linii bedzie inna niz prawdziwa ilosc uczniow dalej? No niestety musimy zalozyc ze dane sa poprawne bo taka jest specyfikacja zadania.
    2. Regex zmienic na luzniejszy - interesuja nas linie ktore maja nazwiska i oceny, kazda inna linia to ilosc uczniow :P
    3. napisac w wersji rozwleklej a pozniej skracac :P

    Limit długości kodu źródłowego: 50000B
    LOOOL OMG ROTFL

    To teraz powaznie do pracy... wersja w pelni zgodna ze specyfikacja. Dodalem 'no warnings' bo wyswietlalo pare ostrzezen ale i tak sa one bez znaczenia tutaj...

    Kod:
    #!/usr/bin/perl
    use strict;
    no warnings;
    
    #
    # oczekiwany wynik programu: 4.46
    #
    
    # inicjalizacja zmiennych ktorych bedziemy uzywac
    my ($ile_osob, @oceny) = (undef, undef);
    # wczytujemy dane
    while (<DATA>) {
    	chomp;
    	$ile_osob =$_ if ! defined $ile_osob; # tylko jesli nie jest ustawione a wiec tylko dla pierwszej linii
    	$_ =~ m/\s+(\d.*?)$/;
    	push @oceny, $1;
    }
    
    # maly debug
    print "Osob:\t$ile_osob\nOceny:\t", join ' ', @oceny , "\n";
    
    # dodajemy oceny
    my $suma=0;
    foreach my $ocena (@oceny) {
    	$suma += $ocena;
    }
    
    printf ("Wynik: %.02f\n", $suma/$ile_osob);
    
    # tutaj male oszustwo - co nastepuje po __DATA__ mozna traktowac jako dane 
    # jest to opisane gdzies w manualu perla ale nie pamietam gdzie :-P
    __DATA__
    4
    Michal Zegarski 5.75
    Arkadiusz Flegma 3
    Monika Prawinska 4.85
    Tomasz Patwa 4.24
    Odpalam skrypt i co mam?

    Kod:
    Osob:	4
    Oceny:	  5.75 3 4.85 4.24 
    Wynik: 4.46
    Wiec kod na 100% dziala... no to teraz wersja bardzo krotka ktora robi dokladnie to samo, czyta dane poprawnie ale nie jest logicznie mowiac do konca zgodna ze specyfikacja, bo nie interesuje sie w ogole tym ilu uczniow ma byc w klasie - pomija pierwsza wartosc i sama zlicza uczniow :-)
    Kod mozna skrocic jeszcze bardziej ale nie bedzie mialo to sensu - stanie sie bardzo nieczytelny a nie o to chodzi...

    Kod:
    #!/usr/bin/perl
    use strict;
    
    my ($suma, @oceny);
    while (<DATA>) {
    	push @oceny, $1 if $_ =~ m/^\w.*?\s+(\d.*?)$/;
    }
    map {$suma+=$_} @oceny;
    printf ("Wynik: %.02f\n", $suma / ($#oceny+1));
    
    __DATA__
    4
    Michal Zegarski 5.75
    Arkadiusz Flegma 3
    Monika Prawinska 4.85
    Tomasz Patwa 4.24
    Wynik tak samo... 4.46
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  5. #5
    Zarejestrowany
    Feb 2009
    Postów
    51

    Domyślnie

    Ale mi chodziło o sprawdzenie kodu, a nie napisanie nowego programu. A poza tym nie chcę oszukiwać.
    Nie rozumiem tylko, co jest źle w moim kodzie. W sumie chyba łatwiej to sprawdzić, niż pisać nowy, dłuższy program.

    Tak więc przepraszam, że straciliście przeze mnie czas, jeśli zbyt niejasno powiedziałem, o jaką pomoc proszę.

  6. #6
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    @kokosko - przepraszam ze popsulem zabawe... juz wyjasniam co z Twoim kodem nie tak:

    #1 - regex zbierajacy oceny... dane beda w $1 a nie $5 bo przeciez tam nie ma 5 nawiasow ktore moglyby zebrac dane...
    #2 - while ($n--)... a pozniej dzielenie przez $n - to petla bez wyjscia wiec nieco lipnie... bo odejmowac od $n mozna do konca swiata i jeszcze dluzej

    Nawet gdyby zatrzymalo sie na $n==0 to mialbys dalej dzielenie przez zero, tak byc nie moze. Nieco martwi mnie tez to, ze nadpisujesz znaczenia zmiennych - najpierw uzywasz $n jako licznika, pozniej jako iteratora w petli, na koniec przez $n dzielisz.

    Te dwa problemy rozkladaja Twoj kod.

    UPDATE:
    Wyjasnie jeszcze co do tego while ($n--) bo tutaj chyba wiem co chciales osiagnac ale cos nie wyszlo...

    Przypuszczam, ze myslales w ten sposob... Jesli $n przypisze ilosc ludzi jaka powinna byc w klasie to pozniej bede czytal wlasnie tyle linii i nic wiecej (ma to sens w sumie). Tak wiec aby policzyc bede dzialal tak dlugo jak dlugo $n wieksze od zera bo jak bedzie $n==0 to bedzie FALSE i petla sie skonczy.
    Blisko... ale while ($n--) da TRUE zawsze gdy uda sie wykonac operacje $n-- czyli doslownie zawsze. Musialbys zmienic to na while ($n>0) i w petli dac $n-- to wtedy mialbys warunek koncowy.

    Poza tym uzycie $n jako iteratora w petli - w najlepszym wypadku skonczysz z $n==1 a w najgorszym z $n==0 wiec bedzie totalna lipa. W takich przypadkach proponowalbym zastosowac zapis for (1 .. $n) {} ktory spowoduje, ze petla wykona sie dokladnie $n razy. Numer przebiegu bedzie w $_ a dane z STDIN trzeba wpczytac wewnatrz petli.

    Jesli mam cos jeszcze wyjasnic to wal smialo.
    Ostatnio edytowane przez TQM : 04-26-2009 - 23:06
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  7. #7
    Zarejestrowany
    Feb 2009
    Postów
    51

    Domyślnie

    Ale jak zmieniłem kod na:
    Kod:
    #!/usr/bin/perl
    # Autor: kokosoko
    use strict;
    my $tekst = <STDIN>;
    my $x=0;
    my $suma;
    my $n;my $m;
    $n = <STDIN>;
    $m = $n;
    while($n>0)
    {
    $n-=1;
    $tekst =~ /\w\s+\w\s+(\d+(\.\d+)?)/;
    $x+=$1;
    }
    $x=sprintf "%.2f",$x/$m;
    print "$x\n";
    albo tak:
    Kod:
    #!/usr/bin/perl
    # Autor: kokosoko
    use strict;
    my $tekst = <STDIN>;
    my $x=0;
    my $suma;
    my $n;my $m;my $i;
    $n = <STDIN>;
    $m = $n;
    for($i=1;$i<$n;$i++)
    {
    $tekst =~ /\w\s+\w\s+(\d+(\.\d+)?)/;
    $x+=$1;
    }
    $x=sprintf "%.2f",$x/$n;
    print "$x\n";
    to i tak mi wyskakuje błąd dzielenia przez 0. :-/
    Ostatnio edytowane przez kokosoko : 04-27-2009 - 16:49

  8. #8
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Nie bardzo wiem jakim cudem... no ale - w tym wypadku sprawdz jaka wartosc ma $n zaraz po wczytaniu pierwszej linii bo tylko tutaj moze byc blad. Poza tym:

    - $n jest przed tekstem...
    - linia $tekst=<STDIN> wczytuje tylko jedna linie a nie wszystkie...
    - nie wiem "po czym" ta petla for albo while ma smigac... caly czas obrabiasz jedna i te sama linie tekstu!

    EDIT:
    musisz popracowac na logika swojego programu... dane wchodza w konkretnej postaci, wiec mozna to wyjasnic mniej wiecej tak:

    Kod:
    1. pobieramy $n z STDIN
    2. $suma = 0
    3. dla $i=1; $i<=$n; $i++ robimy:
      3a. wczytaj linie z STDIN
      3b. regex
      3c. $suma += $1 ($1 z regexa)
      3d. zwiekszamy $i o 1
    4. wyswietlamy wynik dzielenia $suma / $n
    sorry ale nie chce mi sie rysowac schematu blokowego
    Ostatnio edytowane przez TQM : 04-27-2009 - 19:47
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  9. #9
    Zarejestrowany
    Feb 2009
    Postów
    51

    Domyślnie

    Ok. Udało mi się nanieść poprawki. Program nadal nie działa, ale teraz wiem, gdzie jest błąd. Znajduje się on w regexie.
    Oto kod:
    Kod:
    #!/usr/bin/perl
    # Autor: kokosoko
    use strict;
    my $n;my $i;
    $n = <STDIN>;
    my $x=0;
    my $suma;
    for($i=1;$i<=$n;$i++)
    {
    my $tekst = <STDIN>;
    $tekst =~ /\w\s+\w\s+(\d+(\.\d+)?)/;
    $x+=$1;
    }
    $x=sprintf "%.2f",$x/$n;
    print "$x\n";
    Sprawdzałem i jest zła odpowiedź, bo:
    $1 = 0
    $2 = 0
    $3 = 0
    $4 = 0
    $5 = 0
    $6 = 0
    $7 = 0
    $8 = 0
    Te ostatnie na wszelki wypadek dałem.
    Wszystkie są równe 0, więc dla jakich kolwiek danych odpowiedź to: 0.00.

  10. #10
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    ok - to sprobuj moze zapisac regex inaczej - bardziej ogolnie wcale nie znaczy gorzej

    EDIT:
    Ja wlasnie w perlu wyciagam dane z logow... mam 2 logi - jeden z naszego systemu, drugi z obcego systemu. Moj log ma 160MB (plik .csv a w nim 4.1mln linii) ktory musze zaladowac i wyszukac zdarzenia ktore pojawiaja sie tez w logu dostarczonym przez pewna firme.

    Po prostu potega! Perl jest idealny do takich zadan a napisanie skryptu z prostym regexem zajmuje doslownie kilka minut
    Ostatnio edytowane przez TQM : 04-28-2009 - 22:36
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

Strona 1 z 3 123 OstatniOstatni

Podobne wątki

  1. program zdalnie otwierajacy inny program:P
    By northdakota in forum C/C++
    Odpowiedzi: 9
    Autor: 02-27-2009, 23:48
  2. Odpowiedzi: 8
    Autor: 07-26-2008, 09:05
  3. Szkoła średnia
    By lukasz6547 in forum Off Topic
    Odpowiedzi: 1
    Autor: 05-15-2008, 00:07
  4. program
    By Goku1994 in forum Hacking
    Odpowiedzi: 9
    Autor: 08-05-2007, 15:51

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj