Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да, конечно, написал с ошибками. Писал прямо здесь. Увы, у меня не установлен сейчас С++ компилятор на машине, давно с ним не работал. Раньше я перед постингом обычно проверял работу кода.
А я думал, что это намеренно — тест на то, какие ошибки сможет найти ИИ, ничего не зная о программе.
Ошибку с неверным количеством параметров ещё может найти компилятор (и то не всякий — в K&R, емнип, не было сигнатур функций, как таковых. Параметры перечислялись
внутри тела, а не в заголовке).
А вот ошибку несоответствия типов аргументов форматной строке традиционный компилятор не найдёт — потому что для него семантика форматной строки скрыта. Просто какая-то строка, просто какие-то адреса в параметрах.
Тут уже нужно какое-то средство анализа, в которое заранее загрузили семантику функций стандартной библиотеки.
PD>Остальное skipped, потому что относится к ошибкам в коде, а не к основному вопросу про переполнение.
Ну так это у вас этот вопрос — основной. А в реальности, как видим, сделано больше ошибок, чем планировалось
PD>Это не учебная задача, а пример ad hoc, сделанный для иллюстрации вопроса.
Это и есть учебная задача.
PD>Я ничего против того, что он на это указал, не имею. Пусть напомнит, верно. Но меня-то иное интересовало — может ли оно быть при тех данных, которые меня интересуют. А на этот вопрос у него ответа нет.
Потому что он не знает, какие данные вас интересуют.
Вот вы только что сказали, что
ничего, кроме этой программы, у вас нет.
PD>Если эти длина и ширина — размеры дисплея обычной машины в пикселях, то совершенно спокойно можно остаться с unit — пока что дисплеев с размерами, при которых переполнение возможно, в природе нет.
И вдруг появляется контекст — оказывается, речь о длине и ширине экрана в пикселях. Если бы мы дали ИИ это как вводную, его ответ был бы другим. А так вы соврали исполнителю работ, скрыв важные детали.
Это примерно то же самое, что врать адвокату или врачу. Искусственный интеллект точно так же, как и естественный, дополнит вашу постановку недостающими деталями, подобрав самую правдоподобную для него картинку.
Если он угадал — то всё хорошо. Если нет — вы обманули сами себя.
PD>Если это что-то другое — надо знать, какие могут быть значения у этих величин. Вот я приводил 100000 как пример. Допустим, я не знаю, каков maxint. Делаю несколько простейших тестов — работает. Делаю тест 100000 на 100000 — проваливается. Все. Действительно, надо переходить к ulong.
Это очень наивный подход. Тестируем функцию
is_prime(uint n) { return n&1==1;}: для 1 — корректно, для 3 — корректно, для 4 — корректно, для 5 — корректно, для 6 — корректно, для 7 — корректно, для 10 — корректно, для 11 — корректно, для 13 — корректно.
Действительно, можно переходить к реализации следующей функции. Ведь branch coverage у нас 100%, и все тесты зелёные.
PD>Ну а если это размеры дисплея — ну сделаю тест 10000 на 10000, все будет в порядке, можно так и оставить.
Если бы вы коммитили такой код в любом моём проекте, то он не прошёл бы review.
Потому что нет никакой гарантии, что пользователь не соберётся его использовать за пределами неявно подразумеваемых вами ограничений.
Завтра кто-то захочет использовать вашу библиотеку для рисования на виртуальном экране размером в 100000*200000 пикселов, и код начнёт делать фигню.
Если вы заложились на такое ограничение, будьте любезны
а) явно это задокументировать
б) выразить в коде.
А после этого мы посмотрим, нужно ли писать тесты и какие именно тесты.
PD>Так что тест мне ошибку найти сможет, а этот анализ лишь говорит, что она в принципе возможна. Это и без него ясно.
Ещё раз:
1. Тест может и не найти ошибку. От того, что ваши тесты зелены, уверенности в корректности кода не прибавляется.
2. Статический анализ ошибку совершенно точно найдёт, но для него нужны формальные критерии. То есть надо сесть и написать
спецификацию для вашего кода на
формальном языке. И вот после этого верифицирующий компилятор вам сможет (иногда) сказать "ошибок точно нет".
3. ИИ, как видим, не ограничен ни наличием тестов, ни наличием формальных спецификаций. Если бы вы снабдили ваш код хотя бы
комментарием на естественном языке об ожидаемом диапазоне параметров, то ИИ смог бы точно сказать, есть ли в коде ошибка или нет.
PD>unsigned int population;
PD>Это корректно или нет ?
Это примерно такой же вопрос, как и "как правильно писать — Ирак или Иран". Не бывает никакой правильности
PD>Если это население страны, то я нелестно выскажусь в адрес того, кто мне скажет, что может не хватить. Нет таких стран с населением 4 млрд. человек и скорее всего не будет. А если когда-то и будет, то моей программы уже точно не будет 
Да-да. Именно так и думали все авторы программ, у которых под номер года отводили 2 цифры.
PD>Если это население Земли, то не годится. Не хватит. Сейчас. А были бы компьютеры в 15 веке, сказали бы, что вполне хватит. И несколько веков бы вполне хватило.
PD>Что мне тут статический анализ скажет ? Про потенциальную возможность переполнения при суммировании любых чисел ?
Статический анализ скажет ровно то, чего мы от него потребуем.
Вот простой пример:
есть распределённая стейт машина, состоящая из N узлов. Каждый узел может находиться в одном из 4*K состояний, которые устроены как 1_A, 1_B, 1_C, 1_D, 2_A, 2_B.... K_A, K_B, K_C, K_D.
Все узлы стартуют в состоянии 1_A. При каждом изменении состояния узел рассылает всем остальным узлам сообщение "я перешёл в состояние Х".
У нас есть следующий алгоритм:
1. Если узел "видит", что все узлы (включая его) находятся в состоянях X_A или X_B, то он должен перейти в состояние X_B.
2. Если узел "видит", что все узлы (включая его) находятся в состоянях X_B или X_C, то он должен перейти в состояние X_C.
3. Если узел "видит", что все узлы (включая его) находятся в состоянях X_C или X_D, то он должен перейти в состояние X_D.
4. Если узел находится в состоянии X_D, то может перейти в состояние Y_A для любого Y.
5. Если узел находится в состоянии X_A или X_D, и видит любой другой узел в состоянии Y_A, где Y < X, он обязан перейти в состояние Y_A.
Обмен сообщениями делается по попарным однонаправленным FIFO-каналам с потерями. То есть любое сообщение может не дойти, может быть задержано, но не может прийти раньше, чем сообщение, отправленное до него.
Требований к алгоритму — два:
1. Ни один узел не должен увидеть "одновременно" пару узлов в состояниях X_B и X_D
2. Ни один узел не должен увидеть "одновременно" пару узлов в состояниях X_D и Y_D для X!=Y.
Удовлетворяет ли алгоритм этим требованиям? Если нет, то каким тестом мы это "поймаем"? Если да, то как мы это докажем?
PD>Спасибо. Без него я бы не догадался 
Ну вы — может быть, и догадались бы. А среднестатистическому большинству С++ программистов вот такой код кажется вполне нормальным:
int avg(int a, int b) {return (a+b)>>2;}
PD>А тест скажет. Найдем население Земли как сумму населений стран — и все. Приехали. Сейчас. А в 15 веке все было бы в порядке.
Это просто означает, что вы пытаетесь описать спецификацию вашей программы в терминах тестов. Типа "программа должна корректно работать с population в пределах 2 миллиардов" вы записываете в виде теста, который запихивает в неё 2 миллиарда и проверяете результат.
Это — один из самых неудачных способов написания спецификаций, если что

Потому, что
покрывающий набор тестов очень быстро становится непрактично большим.
То есть вы проверили работу программы в нескольких случайно выбранных точках, и на этом почему-то успокоились.
Один "специалист" написал функцию вычисления площади вот так:
short area(short w, short h) { return w * h }.
Второй "специалист" почитал спецификацию:
Максимальное значение ширины экрана — 10000
Максимальное значение высоты экрана — 10000
написал к ней тесты:
expect(area(10000, 1), 10000);
expect(area(1, 10000), 10000);
Вроде и по спеке всё, и тесты зелёные. Тут, конечно, можно возразить, что такие тесты напишет только полный идиот, а реальный разработчик конечно же и тест напишет на (10000, 10000), и код не будет в шортах писать.
Но этот аргумент работает только для самых примитивных случаев. Чуть шире задача — всё, приплызд. Может оказаться наоборот — что если все параметры на максимуме, то работает, а если один не в максимуме — то не работает.
Это сильно затрудняет написание тестов
баз заглядывания в код. А с заглядыванием — вы тестируете не соответствие требованиям, а соответствие кода самому себе.
Для учебных проектов и развлечения — нормальный подход.
И для примитивных задач с прямолинейной логикой тоже норм.
А вот для сложных проектов, в которых цена ошибки велика — нет, неприемлемый.