Ciclo Do While in C#
- Il ciclo
do-while
in C# esegue il corpo del ciclo almeno una volta e poi continua a ripeterlo finché la condizione specificata è vera. - La condizione del ciclo viene controllata alla fine di ogni iterazione, garantendo che il corpo del ciclo venga eseguito almeno una volta.
- Il ciclo
do-while
è utile quando si desidera eseguire un blocco di codice almeno una volta, indipendentemente dalla condizione iniziale. - È importante gestire correttamente le condizioni per evitare cicli infiniti, assicurandosi che la condizione diventi falsa ad un certo punto.
Ciclo do-while
Il ciclo do-while
è simile al ciclo while
.
La differenza principale è che controlla la condizione dopo ogni esecuzione del suo corpo del ciclo. Questo tipo di cicli è chiamato cicli con condizione alla fine (post-test loop). Un ciclo do-while
appare così:
do
{
// corpo del ciclo
// eseguito almeno una volta
// anche se la condizione è falsa
} while (condizione);
Il diagramma di flusso di un tipico ciclo do-while
è riportato nella figura che segue:
Inizialmente il corpo del ciclo viene eseguito. Poi la sua condizione viene controllata. Se è vera, il corpo del ciclo viene ripetuto, altrimenti il ciclo termina. Questa logica viene ripetuta finché la condizione del ciclo non diviene falsa.
La caratteristica principale del ciclo do-while
è che il corpo del ciclo viene eseguito almeno una volta.
Analogamente al ciclo while
, se la condizione del ciclo è sempre vera, il ciclo non termina mai ottenendo così un ciclo infinito. Per evitare questo, dobbiamo assicurarci che la condizione del ciclo diventi falsa ad un certo punto.
Il ciclo do-while
viene utilizzato quando vogliamo garantire che la sequenza di operazioni al suo interno venga eseguita ripetutamente e almeno una volta all'inizio del ciclo.
Vediamo qualche esempio di utilizzo del ciclo do-while
.
Esempio: Calcolo del Fattoriale di un Numero
In questo esempio calcoleremo nuovamente il fattoriale di un numero dato while
infinito useremo un do-while
.
La logica è simile a quella dell'esempio visto nella lezione precedente:
Console.Write("n = ");
int n = int.Parse(Console.ReadLine());
decimal fattoriale = 1;
do
{
fattoriale *= n;
n--;
} while (n > 0);
Console.WriteLine("n! = " + fattoriale);
All'inizio partiamo con un risultato di 1 e moltiplichiamo consecutivamente il risultato ad ogni iterazione per n
, e riduciamo n
di un'unità, finché n
raggiunge 0
.
Questo ci dà il prodotto:
Infine, stampiamo il risultato sulla console. Questo algoritmo esegue sempre almeno una moltiplicazione ed è per questo che non funzionerà correttamente quando n
è minore o uguale a zero.
Ecco il risultato dell'esecuzione dell'esempio sopra per n=7
:
n = 7
n! = 5040
Esempio: Fattoriale con Overflow
Ci si potrebbe chiedere cosa accade se impostiamo un valore grande per il numero n
nell'esempio precedente, diciamo n=100
.
Quando calcoliamo n!
andremo in overflow del tipo decimal
e il risultato sarà un'eccezione di tipo System.OverflowException
:
n = 100
Unhandled exception. System.OverflowException: Value was either too large or too small for a Decimal.
at System.Number.ThrowOverflowException(String message)
at System.Decimal.DecCalc.ScaleResult(Buf24* bufRes, UInt32 hiRes, Int32 scale)
at System.Decimal.DecCalc.VarDecMul(DecCalc& d1, DecCalc& d2)
at System.Decimal.op_Multiply(Decimal d1, Decimal d2)
at Program.<Main>$(String[] args) in Program.cs:line 8
Se vogliamo calcolare BigInteger
(che è stato introdotto a partire da .NET Framework 4.0 ed è mancante nelle versioni .NET più vecchie). Questo tipo rappresenta un intero, che può essere molto grande (ad esempio 100.000 cifre). Non c'è limite sulla dimensione dei numeri registrati nella classe BigInteger
(purché, ovviamente, si abbia abbastanza RAM).
Quindi dobbiamo aggiungere using System.Numerics;
prima dell'inizio della classe del nostro programma e sostituire decimal
con BigInteger
. Il programma ottiene la seguente forma:
using System.Numerics;
Console.Write("n = ");
int n = int.Parse(Console.ReadLine());
BigInteger fattoriale = 1;
do
{
fattoriale *= n;
n--;
} while (n > 0);
Console.WriteLine("n! = " + fattoriale);
Se ora eseguiamo il programma per n=100
, otterremo il valore di
n = 100
n! =
9332621544394415268169923885626670049071596826438162146859296389
5217599993229915608941463976156518286253697920827223758251185210
916864000000000000000000000000
Con BigInteger
si possono calcolare fattoriali dal risultato gigantesco come OverflowException
non si verificherà. La classe BigInteger
è molto potente ma funziona molte volte più lentamente di int
e long
. Purtroppo, il dotnet framework non ha un tipo di dato per i numeri in virgola mobile che può contenere numeri così grandi. Tuttavia, possiamo sfruttare la classe BigInteger
per effettuare calcoli con numeri interi molto grandi suddividendo i numeri in parte intera e parte decimale, ma questo è un argomento per una lezione futura.
Esempio: Prodotto di Numeri in un Intervallo
Diamo un altro esempio più interessante di lavoro con i cicli do-while
.
L'obiettivo è trovare il prodotto di tutti i numeri compresi nell'intervallo
Ecco una soluzione di esempio per questo problema:
Console.Write("n = ");
int n = int.Parse(Console.ReadLine());
Console.Write("m = ");
int m = int.Parse(Console.ReadLine());
int numero = n;
long prodotto = 1;
do
{
prodotto *= numero;
numero++;
} while (numero <= m);
Console.WriteLine("prodotto[n...m] = " + prodotto);
Nel codice di esempio assegniamo consecutivamente a numero
ad ogni iterazione i valori prodotto
accumuliamo il prodotto di questi valori. Richiediamo all'utente di inserire n
, che dovrebbe essere minore di m
. Altrimenti riceveremo come risultato il numero n
.
Se eseguiamo il programma per n=2
e m=6
otterremo il seguente risultato:
n = 2
m = 6
prodotto[n...m] = 720
Attenzione: il prodotto cresce molto rapidamente, quindi si potrebbe aver bisogno di usare BigInteger
invece di long
per il risultato calcolato. Inoltre si faccia attenzione all'overflow di interi nascosto. Il codice non controllato andrà silenziosamente in overflow e il codice sopra produrrà un output errato invece di mostrare un errore. Per superare questo problema, si può inserire la parola chiave checked
prima del ciclo:
checked
{
do
{
prodotto *= numero;
numero++;
} while (numero <= m);
}
In questo modo, se il prodotto supera il limite del tipo di dato (ossia se si verifica un overflow), il programma lancerà un'eccezione System.OverflowException
e non continuerà a eseguire il codice successivo.