2013-06-26 4 views
10

Рассмотрим типичную абсолютную функцию значения (где для аргумента интеграла типа максимального размера в длину):Есть ли безопасный способ получить абсолютное значение без знака целого числа со знаком, без запуска переполнения?

unsigned long abs(long input); 

наивная реализация этого может выглядеть примерно так:

unsigned long abs(long input) 
{ 
    if (input >= 0) 
    { 
     // input is positive 
     // We know this is safe, because the maximum positive signed 
     // integer is always less than the maximum positive unsigned one 
     return static_cast<unsigned long>(input); 
    } 
    else 
    { 
     return static_cast<unsigned long>(-input); // ut oh... 
    } 
} 

Этом код вызывает неопределенное поведение, потому что отрицание input может переполняться, а инициирование целочисленного переполнения со знаком является неопределенным поведением. Например, на машинах с дополнением 2s абсолютное значение std::numeric_limits<long>::min() будет 1 больше, чем std::numeric_limits<long>::max().

Что может сделать автор библиотеки для решения этой проблемы?

ответ

16

Сначала можно использовать для неподписанного варианта. Это обеспечивает четкое поведение. Если вместо этого код выглядит так:

unsigned long abs(long input) 
{ 
    if (input >= 0) 
    { 
     // input is positive 
     return static_cast<unsigned long>(input); 
    } 
    else 
    { 
     return -static_cast<unsigned long>(input); // read on... 
    } 
} 

мы вызываем две четко определенные операции. Преобразование целое число без знака одного хорошо определяется N3485 4.7 [conv.integral]/2:

Если тип назначения без знака, полученное значение является наименьшим целым числом без знака конгруэнтны к исходному числу (по модулю 2^n, где n - количество бит, используемых для представления неподписанного типа). [Примечание. В представлении дополнений двух это преобразование является концептуальным и нет изменений в битовой схеме (если нет усечения). - примечание окончания)

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

Отрицания целого числа без знака хорошо определяются 5.3.1 [expr.unary.op]/8:

Отрицательные беззнакового количество вычисляется путем вычитания его значения от 2^N, где n - количество бит в продвинутом операнде.

Эти два требования эффективно заставляют реализации работать как машина с дополнением 2s, даже если базовая машина является 1s-дополнением или сигнальной машиной.

+1

Хороший ответ, хотя на свой вопрос, но +1. – Bathsheba