Здравствуйте, netch80, Вы писали:
N>С этим оператором для N-битного числа ты не сможешь сделать, чтобы первая итерация была 2**N-1 (например, в 32-битке нельзя сделать, чтобы первая итерация была для i == 0xFFFF_FFFF)
Здравствуйте, T4r4sB, Вы писали:
EP>>while(n--) — стандартная идиома, встречается повсеместно. TB>Да, но тогда и надо писать цикл вайлом, а не фором.
Ну while в таких случаях обычно используют когда n пришло в виде аргумента, а for когда нужна инициализация на месте.
В чём разница-то? Почему считаешь что одно комильфо, а другое нет?
TB>И это всё равно не отменяет того факта, что такое решение — костыль.
Стандартная идиома, с вполне определённым поведением. Нужно знать хотя бы потому что встречается во многих проектах.
EP>>Следуя таким же рассуждениям, можно прийти к "на знаковых нормально корень из отрицательных не извлечь, надо переходить к гауссовым числам" TB>Дык и правда не извлечь. Но это редко когда надо.
Итерация вниз, мало того что редко встречается, так ещё и элементарно реализуется на беззнаковых.
И даже если бы не было нормальной реализации, то это не было бы основанием использовать знаковые повсеместно, ибо и у знаковых и у беззнаковых есть свои плюсы и минусы
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Не не не, Дэвид Блэйн, меня ты не проведёшь. EP>Там где проявляется закольцованность у безнаковых, у знаковых вообще случается undefined behaviour (речь же о C++?). Причём для индексов случается чаще, в силу меньшего положительного диапазона.
Хм, это таки надо постараться переполнить переменную индекса в сторону за его максимум.
Как нужно писать, чтобы это сделать?
EP>В одном случае имеем чёткую модель кольца, а в другом даже магмы нет, ибо операции не замкнуты
Модель кольца можно сделать через -fwrapv или overflow builtins. Но я бы предпочёл исключения по умолчанию.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, netch80, Вы писали:
N>>С этим оператором для N-битного числа ты не сможешь сделать, чтобы первая итерация была 2**N-1 (например, в 32-битке нельзя сделать, чтобы первая итерация была для i == 0xFFFF_FFFF)
EP>Лучше покажи реализацию на int32_t
Я и не претендовал — я показал недостаток предложенной схемы, который надо учитывать при подобном подходе.
В общем же случае надо, повторю в 5й раз, сначала разобраться с диапазонами и методами невыхода за них, и только после этого думать, в какой же тип оно уляжется.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В чём разница-то? Почему считаешь что одно комильфо, а другое нет?
Потому что это не является ожидаемым использование фора.
EP>Стандартная идиома, с вполне определённым поведением. Нужно знать хотя бы потому что встречается во многих проектах.
А почему на знаковых не надо какие-то идиомы сочинять?
EP>Итерация вниз, мало того что редко встречается, так ещё и элементарно реализуется на беззнаковых.
Элементарно костылится, ты хотел сказать.
EP>И даже если бы не было нормальной реализации, то это не было бы основанием использовать знаковые повсеместно
Знаковые не нужны пр битовых операциях, а ещё где?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, netch80, Вы писали:
EP>>Там где проявляется закольцованность у безнаковых, у знаковых вообще случается undefined behaviour (речь же о C++?). Причём для индексов случается чаще, в силу меньшего положительного диапазона. N>Хм, это таки надо постараться переполнить переменную индекса в сторону за его максимум. N>Как нужно писать, чтобы это сделать?
Например индекс int8_t итерируется по массиву в 200 элементов
EP>>В одном случае имеем чёткую модель кольца, а в другом даже магмы нет, ибо операции не замкнуты N>Модель кольца можно сделать через -fwrapv
. Найди комбинацию флагов печатающую числа, а потом не забудь всем пользователям кода сказать чтобы использовали такие же флажки, и ещё если вдруг угораздит перейти на другой компилятор, чтобы нашли эквивалент, так как автор беззнаковые не хотел использовать
Много чего написали в этом обсуждении, но никто кажется не вспомнил про KISS принцип, хотя и неявно сформулировали.
ЕМ>Откуда такое пристрастие, кроме как от лени?
Разумная лень — двигатель прогресса вообще-то Если чего-то можно не делать — его не следует делать.
Соответственно, если нет каких-то причин использовать беззнаковый тип, проще использовать знаковый и меньше думать о том может это привести к ошибке или нет.
Здравствуйте, netch80, Вы писали:
H>>>Во-вторых, иногда нужно не-валидное значение чего-то, что по смыслу неотрицательно. И для этого я лично использую «-1». И если переменная равна ему, то значит значение невалидное. Такая штука с unsigned не проканает, если не вводить всякие magic digits конечно. PJ>>std::optional<uint> N>И терять 4-8 байт вместо одного бита ;[
По корректности optional будет лучше чем int/unsigned с рукопашными сигнальными значениями и необходимостью проверок по всему коду.
Но да, у std::optional большие накладные расходы — для таких случаев легко пишется свой optional не уступающий рукопашному варианту по скорости/размеру.
Здравствуйте, T4r4sB, Вы писали:
EP>>В чём разница-то? Почему считаешь что одно комильфо, а другое нет? TB>Потому что это не является ожидаемым использование фора.
То же самое, только в профиль: for(;n--; ) vs while(n--)
EP>>Стандартная идиома, с вполне определённым поведением. Нужно знать хотя бы потому что встречается во многих проектах. TB>А почему на знаковых не надо какие-то идиомы сочинять?
Это идиома и на знаковых отлично работает: while(n--). Покажи свой вариант, сравним
Здравствуйте, Evgeny.Panasyuk, Вы писали:
V>>1. целые int32_t не являются подмножеством математических целых, так как они закольцованы
EP>Они не закольцованы, а за-ub'ешены: EP> for(int i=0; i>0; ++i) { EP> cout << i << " "; EP> }
Мнэээ...
Подготовка цикла: ставим i = 0.
Проверка на входе в цикл: i > 0 — не выполняется. Немедленно завершаем цикл.
Где UB? Код корректный для любого компилятора, ничего не делает. И, кстати, для unsigned был бы результат точно такой же — честные 0 итераций цикла.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Там где проявляется закольцованность у безнаковых, у знаковых вообще случается undefined behaviour (речь же о C++?). Причём для индексов случается чаще, в силу меньшего положительного диапазона. N>>Хм, это таки надо постараться переполнить переменную индекса в сторону за его максимум. N>>Как нужно писать, чтобы это сделать?
EP>Например индекс int8_t итерируется по массиву в 200 элементов
Ну и зачем кому-то потребовалось сужать такой индекс по сравнению с умолчательным int?
EP>>>В одном случае имеем чёткую модель кольца, а в другом даже магмы нет, ибо операции не замкнуты N>>Модель кольца можно сделать через -fwrapv EP>Я выше примерчик привёл
Здравствуйте, Evgeny.Panasyuk, Вы писали:
H>>>>Во-вторых, иногда нужно не-валидное значение чего-то, что по смыслу неотрицательно. И для этого я лично использую «-1». И если переменная равна ему, то значит значение невалидное. Такая штука с unsigned не проканает, если не вводить всякие magic digits конечно. PJ>>>std::optional<uint> N>>И терять 4-8 байт вместо одного бита ;[ EP>По корректности optional будет лучше чем int/unsigned с рукопашными сигнальными значениями и необходимостью проверок по всему коду.
Ну а почему сразу и рукопашными? Вполне можно сделать обёртку для типа, который принимает значения от 0 до INT_MAX, а отсутствие значения передаёт как -1.
Кстати, это ровно соответствует интерфейсу Linux syscalls (только там выделено в спецслучаи от -4096 до -1, как errno с минусом).
EP>Но да, у std::optional большие накладные расходы — для таких случаев легко пишется свой optional не уступающий рукопашному варианту по скорости/размеру.
Вот чтобы получить не уступающий по размеру — как раз и нужно урезать диапазон значений.
Здравствуйте, T4r4sB, Вы писали:
EP>>Покажи свой вариант, сравним TB>
TB>for (int i=a.size()-1; i>=0; --i);
TB>
TB>просто и в лоб, два пограничных значения и итерация
Ну то есть выбирая между:
for (int i=n-1; i>=0; --i)
и
while(n--)
Ты всё ещё предпочтёшь воротить нос от стандартной и лаконичной идиомы, в пользу более сложного выражения, в котором проще допустить ошибку, которое работает только со знаковыми, из-за субъективной "костыльности" стандартной идиомы?
Здравствуйте, netch80, Вы писали:
EP>>По корректности optional будет лучше чем int/unsigned с рукопашными сигнальными значениями и необходимостью проверок по всему коду. N>Ну а почему сразу и рукопашными? Вполне можно сделать обёртку для типа, который принимает значения от 0 до INT_MAX, а отсутствие значения передаёт как -1.
Я ровно это и имею в виду. Нужно не сравнивать вручную, а использовать optional-like обёртку, которая не будет уступать по скорости/размеру ручному варианту, и одинаково хорошо работать как со знаковыми, так и беззнаковыми.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
N>>Подготовка цикла: ставим i = 0. N>>Проверка на входе в цикл: i > 0 — не выполняется. Немедленно завершаем цикл. EP>Точно, ошибка. N>>Вы что доказать-то хотели? EP>Думал получилось триггернуть UB вроде этого
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ты всё ещё предпочтёшь воротить нос от стандартной и лаконичной идиомы, в пользу более сложного выражения, в котором проще допустить ошибку, которое работает только со знаковыми, из-за субъективной "костыльности" стандартной идиомы?
"Работает только со знаковыми" для меня не недостаток, потому что я отказался от шизы сувать беззнаковые в какую-то переменную лишь потому, что она по смысле не может быть отрицательной, взамен получая грабли на преобразованиях и корректности промежуточных результатов.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте