Подпись против неподписанных операций в C - PullRequest
9 голосов
/ 05 марта 2011

Очень простой вопрос:

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

Как ни странно, это дало мне прирост производительности на 15%, чтоЯ подтвердил, что просто делаю все длинное без знака.

Возможно ли это?Действительно ли математические операции быстрее с числами без знака?Я помню, что читал, что не будет никакой разницы, и компилятор автоматически выберет самый быстрый путь, будь то со знаком или без знака.Действительно ли это увеличение на 15% из-за того, что vars не подписан, или это может быть что-то еще затронуто в моем коде?

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

Ответы [ 4 ]

12 голосов
/ 05 марта 2011

В некоторых операциях целые числа со знаком быстрее, в других - быстрее без знака:

  • В C можно считать, что целочисленные операции со знаком не переносятся. Например, компилятор воспользуется этим при оптимизации цикла. Сравнения могут быть оптимизированы аналогично. (Это также может привести к незначительным ошибкам, если вы этого не ожидаете).

  • С другой стороны, целые числа без знака не имеют этого предположения. Однако отсутствие необходимости иметь дело со знаком является большим преимуществом для некоторых операций, например: деление. Беззнаковое деление на постоянную степень двойки - это простое смещение, но (в зависимости от ваших правил округления) есть условное смещение на 1 для отрицательных чисел.

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

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

2 голосов
/ 21 марта 2011

В трех случаях компилятор заботится о том, является ли переменная со знаком или без знака:

  1. Когда переменная преобразуется в более длинный тип
  2. Когда применяются операторы сравнения (больше, чем и т. Д.)
  3. Когда могут возникнуть переполнения

На некоторых машинах преобразование подписанных переменных в более длинные типы требует дополнительного кода; на других машинах преобразование может быть выполнено как часть команды 'load' или 'move'.

Некоторые машины (в основном небольшие встроенные микроконтроллеры) требуют большего количества инструкций для выполнения сравнения со знаком, чем без знака, без знака, но большинство машин имеют полный массив инструкций сравнения со знаком и без знака.

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

2 голосов
/ 05 марта 2011

На 32-битном процессоре эмулируются 64-битные целочисленные операции;использование unsigned вместо signed означает, что библиотеке эмуляции не нужно выполнять дополнительную работу для распространения битов переноса и т. д.

1 голос
/ 05 марта 2011

Компилятор не выбирает, будет ли он неподписанным или подписанным. Но, теоретически, unsigned with unsigned быстрее, чем signed with signed. Если вы действительно хотите замедлить ход событий, вы пойдете с signed with unsigned. И еще хуже: floats with integers.

Конечно, это зависит от процессора.

...