Eroare pe unitate

O eroare pe unitate sau o eroare a unei unități nesocotite ( în engleză  off-by-one error ) este o eroare logică în algoritm (sau în calcule matematice), inclusiv, în special, o versiune discretă a încălcării condițiilor la limită.

O eroare apare adesea în programare când numărul de iterații ale unei bucle pas cu pas este cu unul mai mic sau mai mult decât este necesar. De exemplu, la comparare, un programator indică „mai puțin decât sau egal” în loc de „mai puțin decât” sau face o greșeală, numărând începutul secvenței nu de la zero, ci de la unu ( indexarea matricei în multe limbaje de programare începe de la zero).

Iterarea peste elementele unui tablou

Luați în considerare o matrice de elemente în care sunt procesate elemente de la m -lea la n -a inclusiv. Câți membri ai matricei vor fi procesați? Răspunsul lui nm este o eroare una câte una și un exemplu de eroare „stap de gard”. Răspunsul corect este n-m+1 .

Pentru a reduce erorile datorate unităților necontabilizate, intervalul de indexare este adesea reprezentat ca intervale semideschise. Deci intervalul de la m la n (inclusiv) este reprezentat de intervalul de la m (inclusiv) la n+1 (fără a include ultima valoare). De exemplu, o buclă care trece prin cinci valori poate fi scrisă folosind un interval semideschis de la 0 la 5 ( limbaj C ):

pentru ( i = 0 ; i < 5 ; ++ i ) { /* corpul buclei */ }

Corpul buclei este executat pornind de la i egal cu 0; i devine apoi 1, 2, 3 și în final devine 4 în pasul următor. Când i devine 5, i<5 nu este satisfăcut și bucla se termină. Cu toate acestea, dacă condiția de comparație este <= (mai mică sau egală cu), bucla va rula de șase ori: i va prelua valorile 0, 1, 2, 3, 4 și 5. În mod similar, dacă i este inițializat la 1 în loc de 0, vor exista doar 4 iterații în buclă: voi lua valorile 1, 2, 3 și 4. Ambele alternative duc la o eroare de unu.

O eroare similară poate apărea dacă se folosește o buclă do-while în loc de o buclă while (sau invers). Bucla do-while garantează cel puțin o iterație, deoarece condiția este verificată după ce corpul buclei este executat.

Erorile legate de matrice pot fi, de asemenea, rezultatul diferențelor dintre limbajele de programare. Numărarea de la zero este tradițională, dar unele limbi numără de la 1. Pascal și Fortran pot defini indici [1] . Acest lucru vă permite să personalizați modelul de matrice în funcție de domeniul subiectului.

Eroare post gard

Eroarea stâlpului de gard (uneori numită eroare stâlp de telegraf sau eroare de lampă) este un caz special de eroare pe unitate. Următoarea sarcină ilustrează această eroare:

Pui un gard drept de 30 de metri lungime și pui stâlpi la fiecare 3 metri. De cati stalpi ai nevoie?

Răspunsul „evident” la prima vedere, 10, este greșit.
Gardul are 30 : 3 = 10 secțiuni. Dar sunt necesari 11 stâlpi, încă unul.

Eroarea inversă apare atunci când se cunoaște numărul de coloane și se presupune că numărul de secțiuni este egal cu numărul de coloane. În realitate, numărul de secțiuni este cu unul mai mic decât numărul de coloane.

Mai general, problema poate fi formulată astfel: dacă există n stâlpi telegrafici, câte goluri există între ei?

Răspunsul corect poate fi n-1 dacă linia de poli este deschisă la ambele capete; n dacă stâlpii formează un cerc; n + 1 - dacă spațiile libere de la ambele capete sunt considerate goluri. Definiția exactă a problemei trebuie studiată cu atenție, deoarece o soluție corectă într-o situație poate da un rezultat eronat în alta. Eroarea stâlpilor de gard apare din numărarea stâlpilor în loc de spații dintre ei sau invers și din neglijarea întrebării dacă unul sau ambele capete ale unui rând trebuie luate în considerare.

Eroarea stâlpilor de gard poate apărea și la numărarea elementelor, altele decât lungimile. Un exemplu este piramida timpului , care ar trebui să fie formată din 120 de blocuri, fiecare dintre ele plasat la locul său cu un interval de 10 ani. Este nevoie de 1190 de ani pentru a construi de la începutul primului bloc până la ultimul bloc, nu 1200. nu cu o excepție. Din această cauză, în calcul, anul bisect s-a repetat după 3 ani, și nu după 4.

Eroarea stâlpului de gard poate, în cazuri rare, să fie cauzată de o ordine neașteptată a datelor de intrare, care poate, de exemplu, să anuleze complet eficiența utilizării unui arbore binar sau a executării unei funcții hash . Această eroare are de-a face cu diferența dintre comportamentul așteptat și cel mai rău caz al algoritmului.

Pentru numere mari, eroarea pe unitate nu este adesea atât de importantă într-un anumit caz. Cu un număr mic, însă, și în unele cazuri specifice în care precizia este primordială, apariția unei erori una câte una poate fi catastrofală. Uneori, o greșeală poate fi repetată și, prin urmare, amplificată, de persoana care face un calcul greșit, dacă persoana următoare face din nou acea greșeală (desigur, această greșeală poate fi făcută și invers).

Ca exemplu de astfel de eroare, putem lua funcția linspace() [2] din limbajul de calcul Matlab , ai cărui parametri sunt: ​​cea mai mică valoare, cea mai mare valoare și numărul de valori, și nu: cea mai mică valoare, cea mai mare valoare și numărul de pași. Un programator care înțelege greșit care este al treilea parametru va presupune că linspace(0,10,5) va genera secvența [0,2,4,6,8,10], dar în schimb va obține [0, 2.5, 5, 7.5, 10 ].

Probleme de securitate

O eroare comună una câte una care duce la o problemă de securitate este utilizarea incorectă a funcției strncat() din biblioteca standard C. O neînțelegere comună asociată cu strncat() este că un octet nul [3] nu poate fi scris mai mult de lungimea șirului. De fapt, funcția scrie un octet nul dincolo de lungimea șirului specificată dacă al treilea parametru este egal sau mai mare decât acea lungime. Următorul cod conține doar o astfel de eroare:

void foo ( const char * s ) { charbuf [ 15 ] ; buf [ 0 ] = '\0' ; strncat ( buf , s , sizeof ( buf )); // EROARE - ultimul parametru trebuie să fie egal cu sizeof(buf)-1 }

O eroare este obișnuită atunci când se utilizează biblioteca standard C, deoarece nu are o abordare consecventă cu privire la scăderea sau nu a 1: funcții precum fgets() și strncpy() nu vor depăși niciodată lungimea specificată (fgets() însuși scade 1 și extrage (lungime-1) octeți), în timp ce alte funcții precum strncat() scriu peste lungimea specificată pentru șir. Din acest motiv, programatorul trebuie să-și amintească ce funcții necesită scăderea 1.

Pe unele sisteme (în special cele cu arhitectură endian endian) acest lucru poate duce la suprascrierea de octeți semnificativi pe stiva de procese, ceea ce poate crea o condiție în care un atacator obține date permițându-i să apeleze o procedură de proces [4] .

O abordare care poate fi folosită pentru a rezolva astfel de probleme este utilizarea unei modificări a acestor funcții care numără numărul de octeți scriși, ținând cont de lungimea bufferului, în loc să scrieți sau să citiți numărul maxim de octeți. Exemple sunt funcțiile strlcat() și strlcpy() , care sunt adesea considerate „sigure”, deoarece împiedică scrierile accidentale dincolo de sfârșitul bufferului (în codul de mai sus, apelarea strlcat(buf, s, sizeof(buf)) elimină un eroare de securitate).

Vezi și

Note

  1. În mod tradițional, în limbajul Pascal, se obișnuiește să se înceapă să se numere de la unu.
  2. un vector cu elemente uniform distanțate . Data accesului: 4 februarie 2015. Arhivat din original pe 4 februarie 2015.
  3. Un caracter al cărui cod de un octet este zero. Biblioteca C menține o regulă conform căreia un astfel de octet marchează sfârșitul unui șir
  4. Scrierea datelor peste granița unui buffer se numește eroare de depășire a tamponului .

Link -uri