Почему «for(std::size_t i=2; i >= 0; --i)» не работает

Я был удивлен, когда этот цикл for не работал должным образом:

for (std::size_t i=2; i >= 0; --i)

Я подумал, ладно, возможно, последняя проверка — это если -1 >= 0, а поскольку i не может быть отрицательным, у нас проблема. Предположительно i зацикливается на (264 - 1).

Однако этот цикл for выполняется:

for (std::size_t i=2; i+1 > 0; --i)

Ненадолго игнорируя std::size_t; это не имеет смысла для меня с логической точки зрения. И (i+1 > 0), и (i >= 0) будут либо истинными, либо ложными для одних и тех же значений i.

Оба будут истинными, если i = {0, 1, 2, ...}, и ложными, если i = {-1, -2, -3, ...}.

Что здесь происходит?

Это как-то связано с реализацией std::size_t или компилятором, или я просто упускаю что-то очень очевидное?

Вам просто нужно применить те же рассуждения ко второму примеру, что и ко второму. -1 + 1 равно 0 независимо от того, находится ли оно в signed или unsigned целочисленной арифметике.

François Andrieux 22.03.2022 21:45
и ложь, если я = {-1, -2, -3, ...} ... за исключением того, что i (то есть неподписанный) не может быть ни одним из этих значений, потому что все эти значения отрицательные.
Eljay 22.03.2022 21:48

Этот вопрос может потребовать большей ясности. Вы упоминаете, что «я не может быть отрицательным», а затем описываете «если я = {-1, -2, -3, ...}». Разве эти утверждения не противоречат друг другу? Что значит "не удалось запустить должным образом"?

Drew Dormann 22.03.2022 21:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

size_t — беззнаковый тип. В таких типах отрицательных значений не существует, но 0-1 определяется как значение, к которому добавление 1 даст 0 — максимальное представимое целочисленное значение size_t.

Так да:

I figured, okay, probably the final check is if -1 >= 0, and since i is not allowed to be negative, we got a problem. Presumably i is looping around to 2^64 - 1.

точно.

for (std::size_t i=2; i+1 > 0; --i)

Итак, i достигает 2⁶⁴-1, и вы добавляете 1, так что вы получаете 0, что равно нет>0, и ваш цикл завершается.

Здесь все в порядке!

Ответ принят как подходящий

What is going on here?

std::size_t — целочисленный тип без знака.

i >= 0

Все беззнаковые целые числа больше или равны 0. Не существует значения, для которого это отношение было бы ложным, и, следовательно, цикл не может закончиться.

i+1 > 0

Целое число без знака могу равно 0. Следовательно, это отношение может быть ложным, и цикл может закончиться. Пример:

std::size_t i = 0;
i -= 1;
assert(i+1 == 0);

Значение i, которое завершает цикл, соответствует -1 по модулю M, где M — количество представляемых значений, равное 2b, где b — ширина целочисленного типа в битах. Это число является наибольшим представимым значением, то есть 2b-1.

Ваш вывод работает с целыми числами, но не с модульной арифметикой.


В какой-то степени это дело вкуса, но я рекомендую следующий код для циклического перебора чисел (n..0]. Он корректно работает как с подписанными, так и с беззнаковыми типами:

for (std::size_t i=n; i-- > 0;)

Ах да, неуловимый оператор C стрелкаi --> 0!

chux - Reinstate Monica 23.03.2022 03:46

@chux-ReinstateMonica На этот раз это замаскировано;)

eerorika 23.03.2022 09:01

Другие вопросы по теме