Pętla FOR - znalazłem buga czy to tak ma być?

Pętla FOR - znalazłem buga czy to tak ma być?
Artur Gacek
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:2
0

Cześć!

Do wykonania miałem proste zadanie ze ślimakiem, który w ciągu dnia wychodzi po słupie, a w nocy zjeżdża o określoną wartość.
Należy obliczyć ilość dni których potrzebuje ślimak do wejścia na słup.
Być może chciałem to zrobić zbyt bardzo na skróty i jakość tego kodu nie powala, jednakże prosiłbym o wyjaśnienie.

**Dlaczego, pomimo spełnienia warunku FALSE, przy 8 okrążeniu pętli dokonuje się inkrementacja? W sumie result powinien wynosić 8 a nie 10, **

Kopiuj
public class Main {

    public static void main(String[] args) {

        int h = 10; //Wysokość słupa
        int a = 3; //Tyle ślimak wychodzi w ciągu dnia
        int b = 2; //Tyle ślimak zjeżdża w nocy
        int result = 0;

        for(; h > 0; h += b) {
            h -= a;
            result++;
        }
        System.out.println(result);
}
}

Dzięki z góry za wyjaśnienie,
Artur

edytowany 1x, ostatnio: Shalom
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
2
  1. Logika to tu nie powala, bo sugerowałaby że zaczynasz od h=0 i przerywasz kiedy h==10 a ty robisz jakieś cuda na kiju
  2. Nie bardzo rozumiem twój problem. Skoro wchodzi o 3 a zjeżdża o 2 to znaczy że każdego dnia wysokość zmienia się sumarycznie o 1. Skoro słup ma 10 to siłą rzeczy trzeba 10 dni. Weź pod uwagę że warunek pętli jest ewaluowany RAZ na obieg pętli a nie że magicznie ja przeywa kiedykolwiek kiedy wartość zmiennej nie spełniłaby warunku.
Kopiuj
for(int i=0;i<10;i++){
    int x = i;
    i = 100; // pętla wcale sie nie przerywa bo warunek będzie sprawdziony dopiero przy nowym obiegu!
    System.out.println("To sie wypisze");
    i = x;
}

"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 4x, ostatnio: Shalom
Zobacz pozostały 1 komentarz
Shalom
No niby jak? o_O Inkrementacja odbywa się PO obiegu pętli a warunek jest sprawdzany PRZED obiegiem pętli. W 8 dniu zaczynasz pętlę z h=2, warunek h>0 jest spełniony, wykonujesz h -= a czyli h=-1, następnie pętla się kończy więc wykonuje się akcja po pętli czyli h += b więc h=1 i znów warunek pętli h>0 jest spełniony...
K5
Pomijając kod, autor ma racje. 8 dnia wysokość ślimaka wyniesie 10 więc już nie liczysz, że w nocy spadnie bo kończysz 'zadanie' ;p
Shalom
@kixe52: tak byłoby w poprawnym rozwiązaniu. Ja odnoszę się do zaprezentowanego kodu.
K5
Odnosiłem się do tego 'Skoro wchodzi o 3 a zjeżdża o 2 to znaczy że każdego dnia wysokość zmienia się sumarycznie o 1. Skoro słup ma 10 to siłą rzeczy trzeba 10 dni.'
Shalom
Jeszcze raz: tak to zostało zaimplementowane. Równie dobrze mógłby tam robić h-=1
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:3 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
2
Shalom napisał(a):
  1. Nie bardzo rozumiem twój problem. Skoro wchodzi o 3 a zjeżdża o 2 to znaczy że każdego dnia wysokość zmienia się sumarycznie o 1. Skoro słup ma 10 to siłą rzeczy trzeba 10 dni.

Jest błąd w pętli i pętla działa według logiki @Shalom.
@Shalom, @Op zauważcie że jak ślimak wszedł w dzień to już w nocy nie zjedzie więc z każdego dnia wchodzi 1m za wyjątkiem ostatniego gdzie wchodzi trzy metry

brzydka poprawka na szybko:

Kopiuj
 for(; h > 0; h += b) {
            h -= a;
            result++;
            if (h > 0) break;
        }, 

Ale to powinno być napisane inaczej, może:

Kopiuj
 h -= a;
 result =+ 1;
 while(h > 0) {
      h += b
      h -= a;
      result =+ 1;
 } 

Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 7x, ostatnio: KamilAdam
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
2
Kopiuj
for(A;B;C){
    D
}

A - wykona się raz przed całą pętlą
B - wykona się przed każdym obiegiem pętli i pętla wykona kolejny obieg tylko jeśli B zwróci true
C - wykona się po każdym obiegu pętli
D - wykona się w każdym obiegu pętli jeśli B było true, wykona się przed C


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
Artur Gacek
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:2
0

Teraz już rozumiem. Przyjąłem, że pętla zawsze sprawdza B zanim wykona C (przy drugim i kolejnym przebiegu).
W dodatku debuger utwierdzał mnie w tym przekonaniu, pewnie źle go zinterpretowałem

Dzięki za pomoc!

Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Zamiast zgadywać warto sie zastanowić jak to sie implementuje:

Kopiuj
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }

Kompiluje się do:

Kopiuj
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 3 L0
    ICONST_0
    ISTORE 1
   L1
   FRAME APPEND [I]
    ILOAD 1
    BIPUSH 10
    IF_ICMPGE L2
   L3
    LINENUMBER 4 L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ILOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (I)V
   L4
    LINENUMBER 3 L4
    IINC 1 1
    GOTO L1
   L2
    LINENUMBER 6 L2
   FRAME CHOP 1
    RETURN
   L5
    LOCALVARIABLE i I L1 L2 1
    LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
    MAXSTACK = 2
    MAXLOCALS = 2
}

Interesuje nas kawałek między L1 i L2. Zobacz że mamy:

Kopiuj
   L1
   FRAME APPEND [I]
    ILOAD 1
    BIPUSH 10
    IF_ICMPGE L2

Czyli ładujemy pierwszą zmienną lokalną, porównujemy z 10 i jak jest greater or equal to skaczemy do L2 czyli za pętle.
Potem mamy tego naszego printa, a dopiero po nim:

Kopiuj
    IINC 1 1
    GOTO L1
   L2

Czyli na sam koniec pętli jest inkrementacja i skok na początek.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
PI
No tak, w końcu kto nie analizuje skompilowanego kodu :D :D
Shalom
Nigdy nie ufaj kompilatorowi ;)
BraVolt
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 4 lata
  • Lokalizacja:Warszawa
  • Postów:2918
1

IMHO naturalne podejście. Usuwanie dopiero rekurencji kiedy jest taka potrzeba

Fibonacci, factorial, naturalne definicja jest rekurencyjna. Fibonacci można prosto napisać rekurencyjnie, memoizatiion (DP), step up z generowaniem tablicy wcześniejszych wyników albo w pętli while.
Rekurencyjne podejście do takich tematów, Fibonacci albo ślimak na słupie jest najbardziej intuicyjne

Najlepiej sobie rozrysować na kartce pierwsze kilka dni, ślimak zaczął od zera, idzie 3 m w górę, nie doszedł do wierzchołka, zjechał w nocy 2 m
Nowy dzień, obudził się 1 m nad ziemią, nie doszedł do wierzchołka do wieczora, idzie spać, zjeżdża 2 m w dół...

Pewnego dnia doszedł na szczyt i tu koniec opowieści.

@Artur Gacek: zadanie nie był ani całkiem proste, ani banalne. IMHO inna wersja fizz-buzz, pokazująca jak programista myśli
I dlatego uważam, że jak jakieś "rozmowy algorytmiczne" to tylko przy "tablicy", a nie zadania domowe an tydzień albo anonimowo codility na czas.
Przy okazji Fibonacci, ile tematów do omówienia przy szerszym sprawdzaniu wiedzy na interview przy okazji prostego zadanka? ;) - Dali proste zadanie ze ślimakiem, w końcu coś napisałem według. mnie rozwiązałem 100%, ale nie pytali więcej i się już nie odezwali... ;)

snail.js

Kopiuj
const poleHeight = 10
const goesUp = 3
const goesDown = 2
let currentPosition = 0
let days = 0

function climb() {

    //from down till dusk
    days++
    currentPosition += goesUp;
    if (currentPosition >= poleHeight) {
        return days;
    }


    // from dusk till down
    currentPosition -= goesDown;

    // another day of hard work
    climb()
}

climb()

console.log(days);

Konsola

Kopiuj
 node snail
8


"Kiedy wiedzieć czy zacząć nauke Springa? bo w czystej Javie to nic ciekawego nie zrobie chyba"
Ein Volk, ein Reich, ein Kwa-Kwa ***** ***
edytowany 2x, ostatnio: BraVolt

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.