Если ваша версия с int lowerLimit
фактически заканчивается, это потому, что она переполняется, и то, что происходит, является неопределенным поведением (для целых чисел со знаком). С таким же успехом он может обернуться вокруг 2^31-1
до -2^31
и продолжить цикл навсегда - или сделать что-то совершенно другое (посмотрите « носовые демоны »).
Если вы попытаетесьэто внутри вашей int lowerLimit
версии:
auto threes = lowerLimit + 3;
for(; threes <= limit; threes += 3) {
sum += threes;
}
std::cout << threes << " " << limit << "\n";
Один возможный вывод, если вам случится скомпилировать с опцией g++
-fsanitize=undefined
:
runtime error: signed integer overflow: 2147483646 + 3 cannot be represented in type 'int'
-2147483647 99999999999999
Он фактически завершил цикл с threes
, являющимся отрицательным числом, которое, конечно, меньше, чем limit
. Это выглядит невозможным, но компилятор может делать все, что захочет - поведение не определено. Это носовой демон своего рода.
Если I скомпилировать то же самое без -fsanitize=undefined
- он будет работать вечно. Это все еще неопределенное поведение, так что это может не произойти для вас.
Если вы переключитесь на unsigned int
, то, что происходит в 2^32-1
, на самом деле хорошо определено. Для 32-битного unsigned int
результата 2^32-1 + 1 == 0
.
Такая программа должна выполняться вечно (поскольку threes
никогда не достигнет 99999999999999
), пока она имеет некоторыепобочные эффекты. Бесконечный цикл без побочных эффектов также имеет неопределенное поведение - поэтому, даже если каждая отдельная операция в функции имеет определенное поведение, реализация, способная понять, что цикл бесконечный и не имеет побочных эффектов, может привести к чему-либо.
Решение состоит в том, чтобы использовать тот же тип для threes
, fives
и fifteens
, что и limit
- но с limit
, установленным на 99999999999999
, будьте готовы ждать действительно действительнодолгое время.