Следует ли использовать 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.