TB>Является валидным полностью рабочим кодом для знакового индекса. Но в Расте этот заголовок падает на пустом векторе. В С++ я бы получил ассерт при обращении по инвалидному индексу.
TB>Внимание вопрос: а какая мне нахрен разница, что программа упала не с дурацким старомодным отсталым ассертом, а с красивой модной прогрессивной молодёжной паникой?
TB>Так что нет, индексы и размеры должны быть знаковыми и только знаковыми.
Здравствуйте, T4r4sB, Вы писали:
N>>1. Там, где размер участвует в арифметике — почти всегда — естественно могут появляться отрицательные значения. Да, он это говорит.
N>>Но: проблемные последствия этого являются следствием устоявшейся кривости стандарта, который не предусматривает иного действия для беззнаковых, кроме как по модулю. Если бы s-10, где s как size() какого-то контейнера равно 4, вызывало бы исключение — проблемы бы не было (или было бы сильно меньше). Считаете невозможным такой результат? — ok, не конвертировать к знаковым, пусть выбивает. Возможно, отрабатывать? — явно конвертировать.
TB>Я пишу на Расте и проблема никуда не делась. TB>Обычный заголовок
TB>
TB>for i in 0 .. v.len()-1
TB>
TB>Является валидным полностью рабочим кодом для знакового индекса. Но в Расте этот заголовок падает на пустом векторе.
[UPDATED:] На C++ это переводится: for (unsigned i = 0; i < v.len()-1; ++i)
То есть, последний элемент не используется.
Вначале я прочёл это как закрытый интервал, поспешил.
Ну тогда это вообще некорректно, потому что подобная операция на пустом контейнере не должна рассматриваться, а обдумывание должно уйти на уровень выше (чего вообще хотели достичь).
Если же речь шла бы о полуоткрытом справа интервале по всем элементам:
for i in 0 ..< v.len() (".." и есть моё "..<" для Rust)
то и проверять его надо было бы через '<', а не '<='.
дискуссию, где топикстартер тянет одеяло в противоположную сторону там и Rust вспоминали, и проблемы, как при таком итерировании и где использовать цикл с предпроверкой, а где — с постпроверкой.
Вы там участвовали, и я как раз отвечал ссылкой на комментарий на Хабре. Но я оставлю ссылку для других.
TB> В С++ я бы получил ассерт при обращении по инвалидному индексу.
Кстати, если доступ к элементу по [], а не at(), то и ассерта бы не было — скорее всего был бы сегфолт.
TB>Внимание вопрос: а какая мне нахрен разница, что программа упала не с дурацким старомодным отсталым ассертом, а с красивой модной прогрессивной молодёжной паникой? TB>Так что нет, индексы и размеры должны быть знаковыми и только знаковыми.
Да, это общий вывод оппонентов EM в той дискуссии.
Я скорее поддерживаю, потому что польза от корректности перехода 0 <-> -1 налицо, а коллекция больше SSIZE_MAX маловероятна (рядом писал).
в целом это всё равно проблема кривости исходных средств (всех: и стандартных манер арифметики в C, и то, что у вас там в Rust оно не хочет из-за этого создавать просто пустое множество...)
Здравствуйте, cppguard, Вы писали:
N>>Отрицательные пиксельные координаты — повсюду.
C>Экранные? Это где, например? Графику мы не берём, там сразу floating-point.
Не экранные, а на картинке. Сдвигаешь что-нибудь и оно выходит за пределы кадра или карты. Объект детектируется нейросеткой у края, особенно если часть его уже вышла за пределы — сразу или в минус, или в плюс за кадр.
Картинку повернул н какой-то угол — края уже не поместились.
5M>>Signed и unsigned следуют разной арифметике: signed представляет обычные числа которые следуют обычной арифметике в которой x-1 < x всегда true (именно из-за этого signed underflow/overflow навсегда объявлено UB), unsigned представляет машинные слова которые следуют modulo-2^N арифметике, где x-1 может быть как меньше так и больше x (well-defined)
N>Нет, это вы приводите как раз позднюю _ре_интерпретацию подхода, которая возникла по сути из-за хакерского переиспользования недостаточно строгих правил предшествующих стандартов.
Поздняя — это когда? Предшествующие стандарты — это какие?
Здравствуйте, σ, Вы писали:
5M>>>Signed и unsigned следуют разной арифметике: signed представляет обычные числа которые следуют обычной арифметике в которой x-1 < x всегда true (именно из-за этого signed underflow/overflow навсегда объявлено UB), unsigned представляет машинные слова которые следуют modulo-2^N арифметике, где x-1 может быть как меньше так и больше x (well-defined)
N>>Нет, это вы приводите как раз позднюю _ре_интерпретацию подхода, которая возникла по сути из-за хакерского переиспользования недостаточно строгих правил предшествующих стандартов.
σ>Поздняя — это когда? Предшествующие стандарты — это какие?
1990-е и позже. Примерно тогда, когда начали использовать оптимизации, описанные Мучником (могут быть и другие источники, но его книга самая показательная).
Предшествующие это ANSI 1985-го года (первый который был вообще стандартом за пределами Bell Labs) и ISO 1989-го.
Здравствуйте, T4r4sB, Вы писали:
M>>Поэтому надо просто писать M>>
M>>for(auto i=0u; i!=v.size(); ++i)
M>>
TB>Это другой код. Для тех, кто не знает синтаксис Раста — интервалы вида a..b там полуоткрытые.
Я, получается, не знаю. То есть в вашем исходном примере for i in 0..v.len()-1 был перебор элементов не включая последний?
Ну тогда, извините, вы скорее всего ССЗБ, что не сделали проверку на непустоту массива, потому что такая операция на пустом массиве со всех точек зрения невозможна, и вместо неё должно выполняться что-то иное.
5M>>>>Signed и unsigned следуют разной арифметике: signed представляет обычные числа которые следуют обычной арифметике в которой x-1 < x всегда true (именно из-за этого signed underflow/overflow навсегда объявлено UB), unsigned представляет машинные слова которые следуют modulo-2^N арифметике, где x-1 может быть как меньше так и больше x (well-defined)
N>>>Нет, это вы приводите как раз позднюю _ре_интерпретацию подхода, которая возникла по сути из-за хакерского переиспользования недостаточно строгих правил предшествующих стандартов.
σ>>Поздняя — это когда? Предшествующие стандарты — это какие?
N>1990-е и позже. Примерно тогда, когда начали использовать оптимизации, описанные Мучником (могут быть и другие источники, но его книга самая показательная).
N>Предшествующие это ANSI 1985-го года (первый который был вообще стандартом за пределами Bell Labs) и ISO 1989-го.
В ANSI C89 Rationale написано, что unsigned это неудачное название для модульной арифметики. Не очень похоже на "более позднюю реинтерпретацию"
Здравствуйте, netch80, Вы писали:
N>Ну тогда, извините, вы скорее всего ССЗБ, что не сделали проверку на непустоту массива,
А зачем её делать-тоааа?! На знаковых индексах я получал бы 100% валидный код, который на пустом массиве бы ничего не делал, что тут плохого? Почему этот беззнаковый дебилизм вынуждает меня усложнять код?!
Здравствуйте, σ, Вы писали:
σ>>>Поздняя — это когда? Предшествующие стандарты — это какие?
N>>1990-е и позже. Примерно тогда, когда начали использовать оптимизации, описанные Мучником (могут быть и другие источники, но его книга самая показательная).
N>>Предшествующие это ANSI 1985-го года (первый который был вообще стандартом за пределами Bell Labs) и ISO 1989-го.
σ>В ANSI C89 Rationale написано, что unsigned это неудачное название для модульной арифметики. Не очень похоже на "более позднюю реинтерпретацию"
Скачал один похожий документ (от 1988). Вижу пассаж:
The keyword unsigned is something of a misnomer, suggesting as it does arith-
metic that is non-negative but capable of overflow. The semantics of the C type
unsigned is that of modulus, or wrap-around, arithmetic, for which overflow has
no meaning. The result of an unsigned arithmetic operation is thus always defined,
whereas the result of a signed operation may (in principle) be undefined. In prac-
tice, on twos-complement machines, both types often give the same result for all
operators except division, modulus, right shift, and comparisons. Hence there has
been a lack of sensitivity in the C community to the differences between signed and
unsigned arithmetic (see §3.2.1.1).
Вы про него?
OK, тогда хронологию надо чуть сдвинуть. К 85-му это ещё толком не поняли. Это Rationale, как видно, от 88-го. Разница в 4 года по сравнению со стартом C (1970-е) несущественна. Спасибо, документ сохраню — как-то я его пропустил.
Но вот последнее предложение цитаты показывает, что окончательного решения по поводу, что делать со знаковой арифметикой, не было. Это основное, на что я тут намекал. Именно в промежутке между C89 и C99 сформировалась идея абьюза предыдущей зависимости от представления отрицательных — совсем не под то, из чего она возникла.
Там ещё интересно про споры про вариант integral promotion (расширять до signed или unsigned?) на страницах 34-35.
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, netch80, Вы писали:
N>>Ну тогда, извините, вы скорее всего ССЗБ, что не сделали проверку на непустоту массива,
TB>А зачем её делать-тоааа?! На знаковых индексах я получал бы 100% валидный код, который на пустом массиве бы ничего не делал, что тут плохого? Почему этот беззнаковый дебилизм вынуждает меня усложнять код?!
Я полностью согласен, что был бы "100% валидный код, который на пустом массиве бы ничего не делал".
Я не согласен, что в этом случае вообще в этот код надо как-то входить. Задача, где пропускается последний элемент, при пустом массиве означает (практически наверняка) вообще некорректную постановку, если этот массив законный, или нарушение в данных. Мой комментарий был исключительно об этом.
И поэтому плохо приводить её как пример.
Пример с перебором назад, который я упоминал, и который обсуждался в прошлой дискуссии, тут лучше. Если у вас N элементов с нумерацией от 0 до N-1, то цикл вида
for (unsigned i = N-1; i >= 0; --i) {
...
}
некорректен — нужно или менять на пост-проверку, или постинкремент (знаменитый хак), или на знаковые. Сама же задача так пройтись по элементам не имеет никакой проблемы в постановке.