Результат абс (-2147483648) равен -2147483648, не так ли? это кажется неприемлемым.
printf("abs(-2147483648): %d\n", abs(-2147483648));
выход:
abs(-2147483648): -2147483648
Результат абс (-2147483648) равен -2147483648, не так ли? это кажется неприемлемым.
printf("abs(-2147483648): %d\n", abs(-2147483648));
выход:
abs(-2147483648): -2147483648
В стандарте говорится о abs()
:
Функции
abs
,labs
иllabs
вычисляют абсолютное значение целого числаj
. Если результат не может быть представлен, поведение undefined.
И результат действительно не может быть представлен, поскольку представление с двумя дополнениями целых чисел со знаком не является симметричным. Подумайте об этом... Если у вас есть 32 бита в int
, это дает вам 2 32 различные значения от INT_MIN
до INT_MAX
. Это четное число значений. Итак, если есть только один 0, число значений больше 0 не может быть таким же, как число значений меньше 0. И поэтому нет никакого положительного аналога INT_MIN
со значением - INT_MIN
.
Итак, что неприемлемо вызывает abs(INT_MIN)
на вашей платформе.
Так как 2147483648 больше, чем INT_MAX
для вашей реализации, то abs(-2147483648)
- undefined.
Отрицательные числа обычно представляются без двоичного дополнения.
Чтобы преобразовать положительный в отрицательный, используется логика
x -> not(x)+1
Для 8-битовой арифметики
01111111b - 127, а -127 - 10000000b + 1 = 10000001b
и в противоположном направлении -127
10000001b станет
01111110b + 1 = 01111111b
Как насчет -128?
-128 равен 10000000b, и нет никакого положительного его аналога, поскольку нет 128-битной арифметики, подписанной в 8 бит.
10000000 → 01111111 + 1 = 10000000 и -128 снова
То же самое относится к оригинальному вопросу
Это код в abs.c в исходном коде GNU glibc.
/* Return the absolute value of I. */
int
DEFUN(abs, (i), int i)
{
return(i < 0 ? -i : i);
}
Итак, abs (-2147483648) return - (- 2147483648). В x86 он реализуется с помощью этой двух команд
movl $-2147483648, %eax
negl %eax
Negl-инструкция реализуется следующим образом: Num = 0-Num; sbb реализуется следующим образом: Вычитает источник из адресата и вычитает 1 дополнительный, если установлен флаг переноса. Таким образом, abs (-2147483648) (hex - 0x80000000) → - (- 2147483648) → 0 - (- 2147483648), наконец, становится (0x80000000).
подробности инструкции negl, пожалуйста посетите http://zsmith.co/intel_n.html#neg
подробности инструкции sbb, пожалуйста, посетите http://web.itu.edu.tr/kesgin/mul06/intel/instr/sbb.html
Попробуйте это
printf("abs(-2147483648): %u\n", abs(-2147483648));