Soluzione Esercizio 9 dell'Esercitazione #2

Esercizio 9

Obiettivo: Affrontare alcuni problemi e trucchi ricorrenti nella programmazione.

Attività:

  1. Sapete che la variabile x può assumere i valori 0 o 1 (e nessun altro). Scrivete, usando l'operatore condizionale "?:", un'istruzione di assegnamento che assegna alla variabile y il valore 1 se x è 0 e il valore 0 se x è 1. Scrivete un breve programma per verificare che la vostra soluzione è corretta. Nota Anche se questa soluzione funziona, non è sicuramente la migliore possibile: si vedano i punti seguenti.
  2. Sapete che la variabile x può assumere i valori 0 o 1 (e nessun altro). Usate, invece dell'operatore condizionale "?:", l'operatore di modulo "%" e scrivete un'istruzione di assegnamento che assegna alla variabile y il valore 1 se x è 0 e il valore 0 se x è 1. Scrivete un breve programma per verificare che la vostra soluzione è corretta. Suggerimento Se a y assegnate x + 1, il risultato è corretto se x vale 0, ma se x vale 1 in y vi ritrovate il valore 2. Però se prendete il "modulo 2"... Nota Anche questa soluzione, pur funzionante, non è la migliore possibile: si veda il punto seguente.
  3. In realtà, nei due esercizi precedenti gli operatori condizionale "?:" e modulo "%" non sono necessari. Anzi, sono di gran lunga superflui e si può fare di meglio senza. Come? Scrivete un breve programma per verificare che la vostra soluzione è corretta. Suggerimento: chiedetevi quanto vale x + y, e risolvete l'equazione...
    Nota: Questa soluzione è di gran lunga migliore delle precedenti. Vi può sembrare un dettaglio, ma è importante e può costarvi punti all'esame...
  4. Scrivete un'espressione per il calcolo del valore assoluto di un numero x. Scrivere anche un breve programma contenente tale espressione per controllarne la correttezza. Suggerimento: usate l'operatore condizionale "?:".
  5. State realizzando un gioco da tavolo in Java e dovete gestire il turno fra i vari giocatori. Per fare ciò usate una variabile turno, di tipo int. Supponiamo per semplicità che ci siano 2 giocatori; quindi turno dovrà assumere in sequenza i valori 0, 1, 0, 1, 0, 1,... Scrivete l'istruzione di assegnamento che dal valore corrente di turno calcola il valore successivo. Suggerimento Non vi sarete già dimenticati le prime tre attività di questo esercizio, no? ;-)
  6. Supponiamo ora che, nel nostro gioco da tavolo, ci siano 4 giocatori; quindi turno dovrà assumere in sequenza i valori 0, 1, 2, 3, 0, 1, 2, 3, 0, ... e così via. Completate il programma seguente, scrivendo l'istruzione di assegnamento che assegna di volta in volta a turno il valore corretto sulla base del valore precedente. Suggerimento: Quali possono essere i valori assunti dal resto della divisione di un numero per 4?
    class Turno {
        public static void main(String[] args) {
    	int turno;
    	int i;
    	turno = 0;
    	i = 0;
    	while (i <= 20) {
    	    System.out.println("Giro numero " + i + " Ora e' di turno giocatore" + turno);
    	    turno = //COMPLETARE!!
    	    i = i + 1;
    	}
        }
    }
    
  7. E se i giocatori sono 7 e quindi si vuole che turno assuma ciclicamente i valori 0, 1, 2, 3, 4, 5 e 6?
  8. Scrivete l'istruzione di assegnamento che assegna alla variabile intera x il valore di y/2 se y è pari, e il valore di y/3 se y è dispari. Usate l'operatore condizionale "?:". Scrivete un programma per verificare la correttezza.
  9. Scrivete l'istruzione di assegnamento che assegna alla variabile intera x il valore di y/2 se y è pari, e il valore di (y-1)/2 se y è dispari. Scrivete un programma per verificare la correttezza. Suggerimento: NON usate l'operatore condizionale.
  10. Scrivete un semplice programmino che verifica che effettuare un'operazione di scorrimento verso sinistra ("<<") equivale ad effettuare una moltiplicazione per 2.

Soluzione

  1. Per scrivere questa istruzione, che miglioreremo negli esercizi immediatamente seguenti, osserviamo semplicemente che la sua struttura deve essere del tipo: y deve assumere un valore dato da "se x vale zero, allora 1, altrimenti 0 (ossia se x vale uno, allora 0)". In Java, usando l'operatore condizionale, si ha quindi:
        y = (x == 0) ? 1 : 0;
    
    (le parentesi non sono necessarie ma aiutano la comprensione). Un programma che verifica la correttezza della nostra risposta può essere:
    class Trucchi {
        public static void main(String[] args) {
            int x, y;
            x = 0;
            y = x == 0 ? 1 : 0;
            System.out.println(y);
            x = 1;
            y = (x == 0) ? 1 : 0;
            System.out.println(y);
        }
    }
    
    (a x viene assegnato prima 0 e poi 1; in entrambi i casi l'espressione viene valutata e il risultato visualizzato). L'esecuzione del programma è:
    >javac Trucchi.java
    >java Trucchi
    1
    0
    
    Ripetiamo ancora una volta che questa non è una buona soluzione, e passiamo subito a vederne di migliori.
  2. Ricordiamo innanzitutto che l'operatore modulo dà il resto della divisione intera; quindi, ad esempio, 13 modulo 5 dà 3 (perché 13 diviso 5 fa 2 con resto 3). In Java l'operatore di modulo è il "%" (e viene usato come in 13 % 5).
    Veniamo ora all'esercizio. Il suggerimento ci dà, di fatto, la soluzione: ci viene detto di "assegnare a y il modulo 2 dell'espressione x + 1", ossia, in Java
        y = (x + 1) % 2;
    
    Vediamo di capire perché funziona. Possiamo vederlo in due modi: Il breve programma di verifica è lasciato al lettore (è analogo al programma precedente). Passiamo piuttosto a vedere la soluzione migliore...
  3. Dopo aver fatto fatica per trovare soluzioni corrette ma brutte, ripensiamo al problema seguendo il suggerimento. Ci sono i soliti due casi: se x vale 0, y vale 1 e se x vale 1, y vale 0. Quindi, x + y può valere solo 1. Ma allora abbiamo l'equazione x + y = 1, che possiamo riscrivere come y = 1 - x. E questa equazione può essere immediatamente trasformata nell'istruzione
        y = 1 - x;
    
    Osservate che il simbolo "=" nelle righe precedenti ha due significati: in termini matematici indica l'uguaglianza, mentre nel codice Java significa piuttosto "diventa" (ad esempio, l'ultima istruzione può essere letta come "y diventa 1 meno x"). Il breve programma di verifica è sempre analogo ai precedenti.
    Questa soluzione è migliore delle precedenti perché:
  4. Il valore assoluto di un numero x è: In Java, con l'operatore condizionale, possiamo scrivere la semplice istruzione seguente, che assegna a y il valore assoluto di x:
        y = x >= 0 ? x : -x;
    
    Altre soluzioni sono:
        y = x > 0 ? x : -x;
    
        y = x < 0 ? -x : x;
    
        y = x <= 0 ? -x : x;
    
  5. Se l'intermezzo sul valore assoluto vi ha distratto, il suggerimento vi ha riportato sulla retta via. Basta ri-analizzare l'istruzione
        y = 1 - x;
    
    dell'attività 3 e osservare che qui siamo in una situazione analoga, con l'unica differenza che c'è un'unica variabile (turno) anziché due (x e y), e che turno svolge il ruolo di entrambe: va usato nella parte destra dell'assegnamento per calcolare il nuovo valore, e va usato nella parte sinistra dell'assegnamento per assumere il nuovo valore. Quindi la risposta (migliore) è:
        turno = 1 - turno;
    
    L'uso di una ulteriore variabile, come in
        int temp;
        temp = 1 - turno;
        turno = temp;
    
    è ovviamente superfluo e porta a una soluzione meno efficiente ed elegante. Infatti, non ha nessun senso fare un passo "intermedio" che in realtà non è intermedio per niente... (è solo in più!)
    Spendiamo due righe anche per gli incorreggibili che avessero risposto
        turno = turno == 0 ? 1 : 0;
    
    o
        turno = (turno + 1) % 2;
    
    Cosa dire, se non che siete "caldamente" invitati a rivedervi con più attenzione le attività precedenti??
  6. In questo caso lo stratagemma adottato nel caso precedente non funziona (provare per credere...). Però non dimentichiamoci delle soluzioni alternative. Questa volta, come ci indica il suggerimento, l'operatore di modulo è proprio quello che ci serve, siccome ci consente di "tenere confinati" i valori di turno fra 0 e 3. L'istruzione completa da inserire nel programma è:
        turno = (turno + 1) % 4;
    
    Vediamo perchè funziona. Questo assegnamento fa sì che: Quindi, come già detto in precedenza, l'operatore di modulo (in questo caso modulo 4) ci permette di "tenere confinati" i valori (fra 0 e, in questo caso, 3).
    Se eseguiamo il programma otteniamo:
    >java Turno
    Giro numero 0 Ora e' di turno giocatore 0
    Giro numero 1 Ora e' di turno giocatore 1
    Giro numero 2 Ora e' di turno giocatore 2
    Giro numero 3 Ora e' di turno giocatore 3
    Giro numero 4 Ora e' di turno giocatore 0
    Giro numero 5 Ora e' di turno giocatore 1
    Giro numero 6 Ora e' di turno giocatore 2
    Giro numero 7 Ora e' di turno giocatore 3
    Giro numero 8 Ora e' di turno giocatore 0
    Giro numero 9 Ora e' di turno giocatore 1
    Giro numero 10 Ora e' di turno giocatore 2
    Giro numero 11 Ora e' di turno giocatore 3
    Giro numero 12 Ora e' di turno giocatore 0
    Giro numero 13 Ora e' di turno giocatore 1
    Giro numero 14 Ora e' di turno giocatore 2
    Giro numero 15 Ora e' di turno giocatore 3
    Giro numero 16 Ora e' di turno giocatore 0
    Giro numero 17 Ora e' di turno giocatore 1
    Giro numero 18 Ora e' di turno giocatore 2
    Giro numero 19 Ora e' di turno giocatore 3
    Giro numero 20 Ora e' di turno giocatore 0
    
    Osserviamo che si sarebbe potuto scrivere un programma con comportamento analogo sfruttando la variabile i, ma così facendo non avremmo risolto l'esercizio, che ci chiedeva esplicitamente di scrivere "l'istruzione di assegnamento che assegna di volta in volta a turno il valore corretto sulla base del valore precedente."
  7. Beh, la modifica rispetto all'attività precedente è veramente minima... La risposta è:
        turno = (turno + 1) % 7;
    
    Verificatene da soli il funzionamento.
  8. Dobbiamo assegnare a x un valore ottenuto in due modi diversi a seconda se y sia pari o dispari. Come visto nell'attività 2 dell'esercizio 6, per sapere se y è pari basta verificare il valore dell'espressione booleana y % 2 == 0. Quindi:
        x = y % 2 == 0 ? y / 2 : y / 3;
    
    Notate il modo di ragionare. Non stiamo dicendo "se y è pari assegno a x il valore y / 2 e se y è dispari assegno a x il valore y / 3". Stiamo invece dicendo: "devo assegnare a x un valore; se y è pari il valore è y / 2 e se y è dispari il valore è y / 3". L'assegnamento viene fatto "a monte".
  9. Ok ,ok, era una domanda trabocchetto. Se non avete letto il suggerimento probabilmente avete risposto "meccanicamente"
        x = y % 2 == 0 ? y / 2 : (y - 1) / 2;
    
    (le parentesi sono necessarie perché l'operatore di divisione è prioritario rispetto a quello di sottrazione). Questa risposta è corretta, ma non è la migliore. Il suggerimento dovrebbe mettervi la pulce nell'orecchio... Come funziona la divisione intera? Se il dividendo (il numero che viene diviso) è pari, non succede niente di strano; se il dividendo invece è dispari, il risultato è lo stesso che si otterrebbe sottraendo uno al dividendo (ad esempio, tredici diviso due fa sei, così come dodici...). Ma allora lo "scrupolo" di sottrarre 1 a y quando y è dispari è uno scrupolo completamente inutile, tanto ci pensa già la divisione intera... Quindi la risposta corretta è semplicemente:
        x = y / 2;
    
    Questo assegnamento darà il risultato voluto in entrambi i casi.
  10. È una domanda molto semplice. Ad esempio:
    class ScorrimentoVersoSinistra {
        public static void main(String[] args) {
            int x;
            x = 3;
            System.out.println(x << 1);
        }
    }
    

Fate l'amore e non la guerra! Valid HTML 4.01! Valid CSS! Stefano Mizzaro
Last modified: 2003-06-12