Modulo preferito per il rilevamento degli errori e le condizioni di terminazione del loop?

1

In questo anwer Stackoverflow Ricordo vagamente che mi viene insegnato che è meglio usare come condizione "ampia" il più possibile Termina un ciclo, piuttosto che testare per una condizione esatta di terminazione.

vale a dire. utilizzare:

while (x < 10) 

anziché

while (x != 10)

tuttavia non riesco a ricordare (o trovare) alcuna base formale o logica per questo.

In realtà questo è scritto ovunque come migliore pratica corrente?

    
posta Alnitak 16.04.2012 - 16:46
fonte

4 risposte

3

Edsger Dijkstra ha fatto una nota su != rispetto a < nel capitolo 8 della sua "Disciplina della programmazione" , pagina 56:

Prior to my getting used to these formal developments I would always have used "j < n" as the guard for this repetitive construct, a habit I still have to unlearn, for in case like this, the guard "j != n" is certainly to be preferred. The reason for the preference is twofold. The guard "j != n"allows us to conclude "j = n" upon termination without an appeal to the invariant relation P and thus simplifies the argument about what the whole construct achieves for us compared with the guard "j < n". Much more important, however, is that the guard "j != n" makes termination dependent upon (part of) the invariant relation, viz. "j <= n", and is therefore to be preferred for reasons of robustness. If the addition "j := j + 1" would erroneously increase j too much and would establish "j > n", then the guard "j < n" would give no alarm, while the guard "j != n" would at least prevent proper termination. Even without taking machine malfunctioning into account, this argument seems valid.

Ho prontamente smesso di usare < nelle condizioni di terminazione del loop dopo aver letto questa nota circa 25 anni fa.

EDIT questa nota segue una discussione di un programma che trova un massimo di una funzione f(k) nell'intervallo [0..n) :

k, j := 0, 1;
do j != n --> if f(k) >= f(j) --> j := j + 1
              [] f(k) <= f(j) --> k, j := j, j + 1 fi od

Questa notazione insolita adottata nel suo libro corrisponde grosso modo a questo programma:

int k = 0, j = 1;
while (j != n) {
    if (f(k) <= f(j)) k = j;
    j++;
}
    
risposta data 16.04.2012 - 21:03
fonte
2

La logica potrebbe essere, che nella seconda versione in caso di qualche bug (diciamo che x è incrementato di 3 invece di 1) il ciclo non terminerà mai, una volta x saltato da 9 a 12. La prima versione si fermerà almeno in tutti i casi in cui x viene incrementato del tutto (sebbene continui a fallire in molti altri casi).

    
risposta data 16.04.2012 - 16:57
fonte
1

se usi variabili in virgola mobile è probabile che non avrai mai x==10 a causa dell'arrotondamento

per esempio (se le costanti non sono piegate) 0.3!=0.1+0.1+0.1 om maggior parte delle macchine

    
risposta data 16.04.2012 - 17:33
fonte
0

Ecco una domanda StackOverflow che illustra perfettamente il ragionamento. Aveva i != bytes_read come condizione del ciclo, ma aveva più di un punto all'interno del ciclo che incrementava i , che creava un ciclo infinito in determinate condizioni. L'utilizzo di <= rende invece il ciclo infinito finito. Questo è tutto ciò che c'è da fare, niente di così coinvolto che qualcuno scriverà un articolo su di esso.

Rende anche più chiaro a qualcuno che legge il programma quali valori sono validi per quella variabile. i != bytes_read di per sé implica che i valori superiori a bytes_read sono validi. Devi leggere diverse altre righe di codice per sapere che non lo sono. Questo particolare esempio potrebbe essere apparentemente ovvio, ma aggiunge ancora chiarezza al codice. Da una prospettiva più formale, ti solleva dalla necessità di dimostrare che le altre dichiarazioni limitano ulteriormente i a essere inferiore a bytes_read .

Se si qualifica come "best practice" o non dipende realmente da un modo migliore per farlo. Ad esempio, dovresti utilizzare un iteratore per scorrere gli elementi in un contenitore anziché un contatore intero in base alle dimensioni del contenitore. Aggiungere un assert per catturare valori al di fuori di un intervallo valido potrebbe essere più utile se è una possibilità reale.

    
risposta data 16.04.2012 - 17:38
fonte

Leggi altre domande sui tag