Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java Do while:n korvaus for:lla

Sivun loppuun

hevonen [14.10.2008 22:53:25]

#

Miten seuraavan koodin voi korvata for -lauseella?

      int arvauksia =0;
      boolean löytyi=false;

      do {
         arvauksia++;

         System.out.println("Arvauksesi: ");
         int arvaus= lukija.nextInt();

         löytyi = binHae(luvut, arvaus);
         if (!löytyi)
           System.out.println("Väärin. Uusiks:");
      }  while (!löytyi);

binHae on binäärihaku, kun taas luvut on taulukko numeroita.

For -lauseen keskimmäinen osa hämää minua. En tiedä, mitä laittaisin rajaksi (X) tuohon kohtaan. Esimerkiksi:

for(arvauksia=0; arvauksia < X; arvauksia++)

Päärynämies [14.10.2008 23:03:41]

#

Javassa for -silmukan keskellä oleva ehto saa olla myös tyhjä, jolloin silmukka menee läpi aina ja ikuisesti, jollei sitä keskeytä silmukan sisällä.

Toki voihan tuohon laittaa ehdoksi saman mikä sinulla on while -silmukassa.

Valmista koodia en tähän kirjoita.

Teuro [14.10.2008 23:04:34]

#

Ei kannata yrittää minusta vääntää for rakennetta, koska do-while toimii ihan hyvin tuossa. Mistä muuten ajatus for-rakenteen käyttöön? Jotenkin voisi ajatella, että haluat rajoittaa arvausmäärään johonkin tiettyyn määrään, mutta senkin voit helposti toteuttaa nykyisessä versiossa laittamalla vertailun

while(arvauksia <= maksimi);

Vai onko sinusta nykyisessä rakenteessa jotakin aivan kamalan hankalaa tehdä?

Antti Laaksonen [14.10.2008 23:07:09]

#

Tämä olisi mielestäni lähinnä alkuperäistä do-silmukkaa:

for (arvauksia = 0; !löytyi; arvauksia++)

Siis for-silmukan keskimmäisen lausekkeen ei tarvitse olla muotoa a < b.

Teuro [14.10.2008 23:09:53]

#

Mutta edelleen onko mielekästä lähteä muuttamaan ihan hyvää ja rakenteellisesti oikeaa kontrollirakennetta toiseksi ilman perusteluja? for on kuitenkin tarkoitettu minusta selkeästi rajatulle joukolle tapahtumia, kun taas while suoritetaan kunnes ehto ei ole tosi ja do-while muutoin samoin, mutta ainakin kerran.

tgunner [14.10.2008 23:10:30]

#

Veikkaan, että kyseessä on koulutehtävä, ja siksi muutos.

hevonen [14.10.2008 23:12:35]

#

Nykyinen rakenne on näppärä. For -lauseke on minusta hieno, minkä takia halusin sitä käyttää.
Kiitos vastauksista!

Jaska [14.10.2008 23:20:20]

#

Stroustrup kirjoitti muistaakseni kirjassaan "C++ -ohjelmointi", että do-while -silmukka on potentiaalinen virheiden lähde, sillä silmukka suoritetaan ainakin kerran. Mutta huolellisella ohjelmoinnilla ei kyseisessä silmukassa pitäisi olla mitään vikaa. Itse en ole do-whileä käyttänyt omissa ohjelmissani kertaakaan lukuun ottamatta yliopiston ohjelmointikurssin laskaritehtäviä, joissa sitä oli pakko käyttää. Suunnittelen silmukat aina toisin.

Teuro [14.10.2008 23:24:42]

#

Eikös melkein jokainen toistorakenne voi jäädä ikuiseen silmukkaan, jos toistoehto suunniteltu väärin, vai ymmärsinkö pointtisi väärin? Millä tavalla do-while on virhealtiimpi? Minusta tässä tapauksessa do-while on perusteltu toistorakenne, ja ilmeisen hyvin toteutettukin, vaikka toisaalta turha arvauksia laskuri onkin silmukassa.

Jaska [14.10.2008 23:27:28]

#

Jokainen toistorakenne voi jäädä ikuiseen silmukkaan. Luin vaan kirjasta suosituksen ja aloin noudattamaan sitä sen kummemmin miettimättä asiaa enempää. Kukin koodatkoon omalla tyylillään.

Grez [14.10.2008 23:34:33]

#

Teuro kirjoitti:

Eikös melkein jokainen toistorakenne voi jäädä ikuiseen silmukkaan, jos toistoehto suunniteltu väärin, vai ymmärsinkö pointtisi väärin?

Nähdäkseni Jaskan pointti oli, että do-while suoritetaan aina vähintään kerran. Jos siis on mahdollista, että sitä ei pitäisi suorittaa kertaakaan (esim. joukon läpikäynti jos joukko voi olla tyhjä), niin joudutaan sisällyttämään do-while if:n sisään. Toisaalta silloin on järkevämpää käyttää toistorakennetta, jossa tarkistus tehdään ennen suoritusta ja joka voidaan täten suorittaa myös 0 kertaa. Eli esim. while (ehto) { koodi }

hevonen [14.10.2008 23:40:02]

#

Heräsi muutama kysymys tuosta Antin koodista.

1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?

2. Voiko seuraavaa koodia for-silmukan keskiosassa:

!muuttuja

kirjoittaa yhtälö- tai epäyhtälömuotoon. Tuo muoto hämää minua.

Teuro [14.10.2008 23:42:20]

#

Mutta eikös silloin ole käytetty juurikin väärää ohjausrakennetta, jos on mahdollista, että tutkittava tietorakenne onkin tyhjä. Tällöin for / while puolustaa paikkaansa.

Ymmärsin toki pointin nyt. Turha tästä kai enempää on jauhaa, koska asia selvisi ilmeisesti myös aloittajalle.

Grez [14.10.2008 23:44:16]

#

hevonen kirjoitti:

1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?

Totta kai voi. Ainoa mikä for-loopissa keskiosassa on olennaista on, että sen saa tulkittua totuusarvoksi (todeksi tai epätodeksi). Se, mitä koodia siinä yhteydessä mahdollisesti suoritetaan ei ole olennaista.

for(a;b;c) { d; }

voitasiin kirjoittaa yhtä hyvin (joskin a:n näkyvyydessä taitaa olla ero)

a;
while(b) {
  d;
  c;
}

hevonen kirjoitti:

Tuo muoto hämää minua.

Millä tavalla?

Teuro kirjoitti:

Mutta eikös silloin ole käytetty juurikin väärää ohjausrakennetta, jos on mahdollista, että tutkittava tietorakenne onkin tyhjä.

Kyllä. Olettaisinkin että ideana on että do while -rakennetta ei tulisi käyttää oletusarvoisesti vaan ainoastaan kun on tarkkaan harkittu että se on parempi kuin while.

hevonen [14.10.2008 23:53:33]

#

Grez kirjoitti:

Ainoa mikä kääntäjää kiinnostaa on, että se saa tulkittua sen todeksi tai epätodeksi.

Tämä selvensi asiaa.
Eli

!muuttuja

tarkoittaa vain, että suoritetaan for ehtoa niin kauan, kunnes se on tosi.

Kiitos!

Sami [14.10.2008 23:58:27]

#

hevonen kirjoitti:

Heräsi muutama kysymys tuosta Antin koodista.

1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?

2. Voiko seuraavaa koodia for-silmukan keskiosassa:

!muuttuja

kirjoittaa yhtälö- tai epäyhtälömuotoon. Tuo muoto hämää minua.

1. Ensimmäinen osa for-silmukasta on varattu muuttujien alustusta varten ja se suoritetaan aina tasan yhden kerran. Toinen osa on ehtolause (eli mitä tahansa, minkä paluuarvo on true tai false) ja silmukan sisältö suoritetaan, jos tämä on tosi. Kolmas osa suoritetaan aina jokaisen kierroksen lopussa, jonka jälkeen tarkistetaan taas onko toistoehto vielä voimassa.

2. muuttuja == false tai muuttuja != true ajaisivat saman asian. Yleensä on kuitenkin selkeää käyttää !muuttuja.


Tuossa grezin esimerkissä myös näkyvyysalue saadaan samaksi lisäämällä yhdet aaltosulut näin (on täysin sallittua luoda aaltosuluin eroteltuja koodilohkoja, vaikkei aaltosulun edessä olisikaan mitään avainsanaa):

{
  a;
  while(b) {
    d;
    c;
  }
}

grez kirjoitti:

Kyllä. Olettaisinkin että ideana on että do while -rakennetta ei tulisi käyttää oletusarvoisesti vaan ainoastaan kun on tarkkaan harkittu että se on parempi kuin while.

whilen ja do-whilen välillä on yksi selvä ero: do-whilen sisällä oleva koodi suoritetaan aina vähintään yhden kerran, koska ehto tarkistetaan aina lohkon lopuksi, toisin kuin whilessä, missä se tarkistetaan heti ensimmäisenä.

Esimerkiksi seuraavissa hieman tekaistuissa esimerkeissä ero tulee toivottavasti esille.

int luku = arvoToinenLuvuista(-1, 1);
do {
  System.out.println("anna luku");
  luku = lueLuku();
} while (luku >= 0);

ja

int luku = arvoToinenLuvuista(-1, 1);
while (luku >= 0) {
  System.out.println("anna luku");
  luku = lueLuku();
};

tekevät täsmälleen saman, jos muuttuja luku sattuu saamaan alussa arvon 1. Jos se taas sattuu saamaan arvoksi -1, niin ensimmäinen kyselee silti lukuja kunnes saa nollaa pienemmän, jälkimmäinen taas ei kysy käyttäjältä lukua lainkaan, koska ehto oli alunperinkin epätosi.

hevonen [15.10.2008 00:18:10]

#

Kiitos Sami!
Sain lopulta koodin tehtyä - teidän ansiosta. Vastaus siis on:

boolean löytyi=false;
     for(int arvauksia=0; !löytyi; arvauksia++) {
        System.out.println("Arvauksesi: ");
        int arvaus= lukija.nextInt();

        löytyi = binHae(luvut, arvaus);
        if (löytyi==false)
           System.out.println("Väärin. Uusiksi.");
        else {
           arvauksia++;
           System.out.println("Oikein! Tarvitsit yhteensä "+arvauksia+" arvausta.");
        }
      }

   }

Grez [15.10.2008 00:27:14]

#

Sami kirjoitti:

whilen ja do-whilen välillä on yksi selvä ero: do-whilen sisällä oleva koodi suoritetaan aina vähintään yhden kerran

Niin, en pysty oikein tulkitsemaan tuota Jaskan kommenttia muuten, kuin että tuo on potentiaalinen virheiden lähde, jos koodari ei huomioi tuota tosiasiaa. Vai voiko Jaskan kommentin mielestäsi tulkita muulla tavalla?

Kyseessä ei siis ollut oma mielipiteeni. Oma mielpiteeni on, että virhelähde on näppimistön ja tuolin välissä.

Hevonen kirjoitti:

Vastaus siis on:

Miksi arvausten määrää kasvatetaan kahdella per looppi?

hevonen [15.10.2008 00:44:48]

#

Grez: kyllä se arvausten määrä kasvaa vain yhdellä - kokeilin. :) Lopussa vain else loopissa on tuo +1 arvausten määrään, koska lähtöarvo oli 0.

Grez [15.10.2008 00:50:28]

#

Hupsista, mun moka. Katsoin vaan nopeasti että siellä oli arvauksia++ kaksi kertaa. Eikö lähtöarvoksi olisi ollut järkevämpää pistää 1?

Omaan silmään seuraava näyttäisi selkäemmältä:

int arvauksia=1;
System.out.println("Arvauksesi: ");
while (!binHae(luvut, lukija.nextInt()))
{
	System.out.println("Väärin. Uusi arvauksesi: ");
	arvauksia++;
}
System.out.println("Oikein! Tarvitsit yhteensä "+arvauksia+" arvausta.");

Tuon ei ole tarkoitus olla mikään mallisuoritus, varmaan monien mielestä tuo on sekavampi. Pistimpähän nyt kuitenkin.

Jaska [15.10.2008 02:17:27]

#

Grez kirjoitti:

Niin, en pysty oikein tulkitsemaan tuota Jaskan kommenttia muuten, kuin että tuo on potentiaalinen virheiden lähde, jos koodari ei huomioi tuota tosiasiaa. Vai voiko Jaskan kommentin mielestäsi tulkita muulla tavalla?

Tätä tarkoitin.

Stroustrup kirjoitti:

Minun kokemukseni mukaan do-lause on virheiden ja sekaannusten lähde. Tämä johtuu siitä, että sen runko suoritetaan kerran ennen ehdon testaamista. Jotta runko toimisi oikein, ehdon on oltava hyvin lähellä toteutumista jo silmukan ensimmäisellä kierroksella. Olen yllättävän usein havainnut, että ehto ei ole ollut voimassa joko ohjelmaa kirjoittaessa ja testatessa tai myöhemmin, kun edeltäviä lauseita on muutettu. Minusta ehdon pitäisi olla alussa, jotta sen näkee heti, ja siksi yritän välttää do-lauseita.

Näin siis Bjarne Stroustrup kirjassaan C++ -ohjelmointi.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta