Помилка на одиницю (off-by-one error) — логічна помилка, яка полягає в отриманні числа, яке відрізняється від очікуваного значення на +1 або −1. Це часто трапляється при програмуванні, коли циклу повторюється на одну ітерацію більше або менше ніж потрібно.

Основні причини це:

використання нестрогої нерівності (≤) як умови виходу з циклу, тоді як потрібна строга нерівність (<), або навпаки; плутанина, пов'язана з використанням нумерації від нуля.

Приклади

Помилка парканного (або телеграфного) стовпа Помилка парканного стовпа (іноді її називають помилкою телеграфного стовпа, ліхтарного стовпа або паркана) — це окремий випадок помилки «на одиницю». Її описано дуже давно, наприклад, згадано в роботах Вітрувія..

Задачі можна сформулювати так :

Звісно відповідь залежить від конструкції паркана, і в нашому випадку, якщо ми вказуємо що паркан починається зі стовпа, потім йде секція паркану, далі стовп, і так далі, та в кінці паркан закінчується стовпом.

Швидкі інтуїтивні відповіді, що для прямої задачі потрібно 10 стовпів, а для оберненої — довжина 10 метрів, неправильні, оскільки довжина паркана дорівнює кількості секцій, а кількість секцій на одну менша ніж стовпів. Якщо паркан має 10 секцій то його довжина 10 метрів, але він має 11 стовпів. В оберненій задачі з 10 стовпів вийде 9 секцій тобто 9 метрів.

Помилки в подібних задачах виникають через підрахунок предметів, а не проміжків між ними, чи навпаки, або нехтування питанням про те, чи слід рахувати один чи обидва кінці ряду.

Подібні помилки можуть виникнути в мовах розрахунків MATLAB, а також numpy в функціях linspace() та arange().

Функція linspace має параметри linspace(lower_value, upper_value, number_of_values )

Програміст, який неправильно зрозуміє третій параметр, та захоче отримати масив, що починається з 0, закінчується 10, і має проміжки по 2 одиниці — , подумає що третій параметр повинен бути (10-0)/2 = 5.

Але linspace(0, 10, 5) повертає масив з 5 значеннями, розраховуючи однакові проміжки .

А інша функція numpy, arange(0, 10, 2) поверне значення що не включає останнього значення 10.

Така помилка може виникати не лише при вимірюванні довжини чи програмуванні. Наприклад, до Піраміди часу, що повинна складатись зі 120 блоків, заплановано кожні 10 років добудовувати новий блок. Автор конструкції хотів продемонструвати що таке 1200 років, але піраміду буде побудовано за 1190 років. Одна з найдавніших помилок на одиницю також пов'язана з часом, коли на початку впровадження юліанського календаря протягом 36 років обчислювали високосні роки неправильно, оскільки священики вирішили що високосний рік повинен бути кожні три роки, а не через кожні три роки.

Ітерація по масиву Розглянемо масив з елементами від m до n (включно) які потрібно обробити. Скільки там об'єктів? Інтуїтивно зрозумілою відповіддю може бути , але вона відрізняється на одиницю, демонструючи помилку парканного стовпа, оскільки правильна відповідь . Саме тому діапазони в програмуванні часто представлено напіввідкритими діапазонами. Діапазон [m, n] (включно) представляється [m, ) (від m включно до n виключно), щоб уникнути таких помилок.

Наприклад, цикл, який повторюється п'ять разів (від 0 до 4 включно), можна записати як напіввідкритий інтервал від 0 до 5: for (index = 0; index < 5; index++) { /* тіло циклу */ }

Перша ітерація циклу виконується вперше з = 0, потім = 1, = 2, = 3 і, нарешті = 4.

Тоді, коли зростає до 5, умова стає хибною, і цикл завершується. Однак, сама процедура перевірки умови, порівняння <= (менше або дорівнює) виконується шість разів. Якщо перевірка буде викликати якусь функцію або дію, то це дію буде виконано шість разів.

Подібна помилка може виникнути, якщо замість циклу while-do використовувати цикл do-while (або навпаки).

Див. також Принцип Діріхле Похибка округлення Нумерація від нуля

Примітки