Следует ли использовать unsigned ints, если это необходимо?

Следует ли объявлять переменную как unsigned int, если они не требуют дополнительного диапазона значений? Например, при объявлении переменной в цикле for, если вы знаете, что это не будет отрицательным, имеет ли это значение? Быстрее, чем другой? Неправильно ли объявлять unsigned int как unsigned в С++?

Чтобы перезаписать, следует ли это сделать , даже если дополнительный диапазон не требуется? Я слышал, что их следует избегать, потому что они вызывают путаницу (IIRC, почему Java не имеет их).

Ответы

Ответ 1

Причиной использования uints является то, что он дает компилятору более широкий спектр оптимизаций. Например, он может заменить экземпляр "abs (x)" на "x", если он знает, что x положителен. Он также открывает множество поразрядных "сокращений силы", которые работают только для положительных чисел. Если вы всегда мультиделите/делите int на мощность в два, то компилятор может заменить операцию с помощью сдвига бит (т.е. x * 8 == x < 3), который имеет тенденцию работать намного быстрее. К сожалению, это отношение справедливо только в том случае, если "х" положительно, потому что отрицательные числа кодируются таким образом, который исключает это. С помощью ints компилятор может применить этот трюк, если он может доказать, что значение всегда положительно (или может быть изменено ранее в коде, который должен быть таким). В случае с uint этот атрибут является тривиальным для доказательства, что значительно увеличивает вероятность его применения.

Другим примером может быть уравнение y = 16 * x + 12. Если x может быть отрицательным, тогда потребуется умножить и добавить. Тем не менее, если x всегда положительно, то не только заменить x x 16 на x < 4, но поскольку этот термин всегда будет заканчиваться четырьмя нулями, это откроет замену "+ 12" двоичным OR (as поскольку термин "12" меньше 16). Результатом будет y = (x<<4) | 12.

В общем, "unsigned" квалификатор дает компилятору больше информации об этой переменной, что, в свою очередь, позволяет сжимать больше оптимизаций.

Ответ 2

Вы должны использовать целые числа без знака, если для них нет смысла иметь отрицательные значения. Это полностью не зависит от проблемы диапазона. Поэтому да, вы должны использовать unsigned integer типы , даже если дополнительный диапазон не требуется, и нет, вы не должны использовать unsigned int (или что-то еще), если это не необходимо, но вам нужно пересмотреть ваше определение того, что необходимо.

Ответ 3

Чаще всего вам следует использовать целые числа без знака.

Они более предсказуемы с точки зрения undefined поведения при переполнении и т.д.
Это огромный вопрос, поэтому я больше не буду говорить об этом. Это очень хорошая причина, чтобы избежать целых чисел со знаком, если вам действительно не нужны подписанные значения.

Кроме того, они проще работать с проверкой диапазона - вам не нужно проверять отрицательные значения.

Типичные эмпирические правила:

  • Если вы пишете прямой цикл for с индексом в качестве управляющей переменной, вы почти всегда хотите беззнаковые целые числа. Фактически, вы почти всегда хотите size_t.

  • Если вы пишете обратный цикл for с индексом в качестве управляющей переменной, по очевидным причинам вы, вероятно, должны использовать целые числа со знаком. Вероятно, ptrdiff_t сделал бы.

Единственное, с чем нужно быть осторожным, - это отличать между подписанными и неподписанными значениями разных размеров.
Вероятно, вы захотите дважды проверить (или выполнить тройную проверку), чтобы убедиться, что бросок работает так, как вы ожидаете.

Ответ 4

int - это целочисленный тип общего назначения. Если вам нужно целое число, а int соответствует вашим требованиям (диапазон [-32767,32767]), используйте его.

Если у вас есть более специализированные цели, вы можете выбрать что-то еще. Если вам нужен индекс в массив, используйте size_t. Если вам нужен индекс в вектор, используйте std::vector<T>::size_type. Если вам нужны конкретные размеры, выберите что-то из <cstdint>. Если вам нужно что-то большее, чем 64 бит, найдите библиотеку, например gmp.

Я не могу придумать никаких веских причин использовать unsigned int. По крайней мере, не напрямую (size_t, а некоторые из типов определенного размера из <cstdint> могут быть typedefs unsigned int).

Ответ 5

Проблема с систематическим использованием unsigned, когда значения не могут быть отрицательными, заключается не в том, что у Java нет unsigned, это означает, что выражения с неподписанными значениями, особенно когда они смешаны с подписанными, иногда дают путают результаты, если вы думаете о unsigned как целочисленный тип со сдвинутым диапазоном. Unsigned - это модульный тип, а не ограничение целых чисел на положительный или нулевой.

Таким образом, традиционное представление состоит в том, что unsigned следует использовать, когда вам нужен модульный тип или побитовая манипуляция. Это мнение подразумевается в K & R - смотрите, как используются int и unsigned, и более явным образом в TС++ PL (2nd edition, стр. 50):

Целочисленные типы unsigned идеальны для использования, которые рассматривают хранилище как бит-массив. Использование unsigned вместо int для получения еще одного бита для представления положительных целых чисел почти никогда не является хорошей идеей. Попытки убедиться, что некоторые значения положительны, объявив переменные unsigned, как правило, будут побеждены правилами неявного преобразования.

Ответ 6

Почти во всех архитектурах стоимость подписанной операции и неподписанной операции одинакова. Таким образом, эффективность разумна, вы не получите никакого преимущества для использования unsigned за подписью. Но, как вы указали, если вы используете unsigned, у вас будет больший диапазон

Ответ 7

Даже если у вас есть переменные, которые должны принимать только отрицательные значения без знака, может быть проблемой. Вот пример. Предположим, что программисту предлагается написать код для печати всех пар целых чисел (a, b) с 0 <= a < b <= n, где n - заданный вход. Неверный код

for (unsigned b = 0; b <= n; b++)
   for (unsigned a=0; a <=b-1; b++)
       cout << a << ',' << b << n ;

Это легко исправить, но мышление с unsigned немного менее естественно, чем мышление с int.