Paola Magillo, Univestita' di Genova, Corso di Programmazione II per SMID, a.a. 2007-2008.

Soluzione al Laboratorio 02:

CRIVELLO DI ERATOSTENE E VARIANTI + ECCEZIONI

Vedere il l'testo del laboratorio 02.


Crivello

Vedere il'ultima parte della lezione 4 per l'algoritmo del Crivello di Eratostene in Java.

Diamo qui la soluzione all'esercizio che chiedeva:

Scrivere un programma che controlla se un numero assegnato e' primo oppure no.
IN PRATICA:
Sia k il numero da controllare (per es. dato come parametro da linea di comando).
E' sufficiente provare a generare tutti i numeri primi minori di k+1. Se a un certo punto si scopre che k e' primo, allora si termina e si risponde "si". Altrimenti si risponde "no".

Il numero da controllare va preso da command-line, quindi una prima modifica da apportare al main e' la seguente (in grassetto la parte modificata):

public static void main(String args)
{
  if (args.length<1)
     System.out.println("Errore: manca il parametro");
  else
  {
    int k = Integer.parseInt(args[0]);
    /* quella che segue e' la parte solita dove abbiamo fatto
       arrivare il ciclo fino a k compreso */
    Sieve first = new Sieve();
    int n;
    for (n=2; n<=k; n++) first.filter(n);
  }
}

Ma dobbiamo ancora modificarlo per riuscire a capire se durante il ciclo abbiamo trovato che k e' primo oppure no.

Ci sono almeno 3 varianti possibili, che vanno tutte bene.

Variante 1

Faccio conoscere a tutti i crivelli quale e' il numero da controllare. Quando un crivello sta setacciando un numero i (nella funzione filter) ed e arrivato a concludere che i e' primo oppure non e' primo, controlla se questo numero i e' uguale al numero da controllare. Se lo e' allora stampa, a seconda del caso, "il numero cercato e' primo" oppure "il numero cercato non e' primo". Negli altri casi non stampa nulla per non appesantire l'output.

In pratica:

Variante 2

Metto una variabile booleana condivisa da tutti i crivelli. In un generico momento del ciclo del main, quando eseguo first.filter(n), attaccata in coda al primo crivello first si trova una catena di crivelli, e il numero n viene fatto passare per questa catena di crivelli. Uno ed un solo crivello della catena trova che n e' primo oppure che n non e' primo. Se trova che n e' primo, gli facciamo mettere il booleano a true, se trova che non e' primo lo facciamo mettere a false. Quindi dopo ogni giro del ciclo sappiamo se n era primo o no, guardando il valore del booleano. A noi interessa guardarlo all'ultimo giro del ciclo, quello in cui n vale k.

In pratica:

Variante 3

Noto che alla fine del ciclo nel main, ho una catena di crivelli dei quali il primo contiene 2, il secondo 3, e i seguenti contengono tutti gli altri numeri primi, l'ultimo crivello della catena contiene il numero primo piu' grande che sia minore o uguale a k. Se k era primo, questo ultimo crivello contiene proprio k.
Percio' per sapere se k e' primo basta andare a prendere l'ultimo crivello e guardare che numero ha dentro.

In pratica:


Eccezioni

Partire dall'implementazione della classe "rettangolo" da voi scritta, quella con incapsulazione (le dimensioni del rettangolo come variabili private e i metodi pubblici "get" e "set" per leggerle e assegnarle).

    Modificare la classe facendo si' che i metodi "set" sollevino eccezione in caso di argomento negativo, e lo stesso faccia il costruttore del rettangolo

    Scrivere un "main" che legge le dimensioni del rettangolo da command-line, cerca di costruire il rettangolo. In caso di eccezione, ricovera l'errore sostituendo la dimensione negativa con il valore 1. Poi calcola l'area del rettangolo.

Il risultato si ottiene prendendo la classe RectangleExcp dalle dispense e cambiando tre cose:

  1. Mettere a 1 la dimensione dove si e' verificato il fallimento (il fallimento puo' darsi su setLength, su setWidth, o su entrambe)
  2. Calcolare l'area anche in caso di fallimento (dopo l'azione di ricovero che ha messo 1).

Vediamo ora il nuovo main:

  public static void main(String[] args)
  {
    /* legge da command line due numeri interi per le
       dimensioni del rettangolo */
    int input_l = 0;
    int input_w = 0;
    if (args.length!=2)
    {
      System.out.println("Necessari due interi come argomenti.");
      System.out.println("Per default: " + input_l + " " + input_w);
    }
    else
    {
      input_l = Integer.parseInt(args[0]);
      input_w = Integer.parseInt(args[1]);
      System.out.println("Argomenti: " + input_l + " " + input_w);
    }
    /* costruisce rettangolo finora di dimensioni zero */
    RectangleExcp r = new RectangleExcp();
    /* prova ad assegnare la lunghezza, se errore mette 1 */
    try
    {
      r.setLength(input_l);
    }
    catch (NegativeRectangleException excp)
    {
      System.out.println("Errore, lunghezza negativa " + input_l);
      try { r.setLength(1); } catch (NegativeRectangleException ee) {}
    }
    /* prova ad assegnare la lunghezza, se errore mette 1 */
    try
    {
      r.setWidth(input_w);
    }
    catch (NegativeRectangleException excp)
    {
      System.out.println("Errore, larghezza negativa " + input_l);
      try { r.setWidth(1); } catch (NegativeRectangleException ee) {}
    }
    /* ora stampa rettangolo, calcola area e la stampa */
    r.print();
    int a = r.area();
    System.out.println("Area = " + a);
  }