Работа с отрицательными числами в дополнительном коде Печать
Добавил(а) microsin   

Как известно, для кодирования целого числа со знаком часто используется дополнительный код (two's-complement code, см. [1]). Самый старший бит при этом несет функцию знака, а диапазон кодируемых чисел равен -2(n-1) .. +2(n-1)-1, где n общее количество разрядов числа в дополнительном коде. Например, при n=8 число в дополнительном коде умещается в 1 байт, бит 7 будет знаковым, сам дополнительный код размещается в битах 6..0, а кодируемое число лежит в диапазоне от -128 до +127. В таблице приведен пример кодировки 8-битного числа в дополнительном коде (старший бит D7 несет информацию о знаке).

two-complement-8bit.PNG

Дополнительный код имеет недостаток в том, что абсолютное значение (модуль) минимального кодируемого числа (для байта это -128) не равно абсолютному значению максимального кодируемого числа (для байта это +127). Это вызывает проблему при получении модуля числа, которую часто игнорируют многие компиляторы. Например, компилятор IAR Embedded Workbench for ARM имеет функцию abs такого вида (эта функция определена в файле stdlib.h):

#pragma inline
int abs(int i)

    /* compute absolute value of int argument */
    return (i < 0 ? -i : i);
}

К сожалению, этот код работает некорректно, он не может перевести код числа -2147483648 (0x80000000) в число +2147483648, потому что такое число невозможно закодировать 32-мя битами в дополнительном коде. Код, который генерирует компилятор для функции abs, обходит проблему, оставляя число -2147483648 без изменений. Т. е. abs(-2147483648) возвращает -2147483648, хотя должно возвращаться положительное число. Полностью решить проблему можно, если не допускать попадания на вход функции abs числа -2147483648, т. е. делать на входе функции abs дополнительную проверку. Другой вариант - переделать функцию вычисления абсолютного значения, чтобы для числа -2147483648 возвращалось абсолютное значение на 1 меньше. Вот пример исправленной функции вычисления модуля для 32-битного числа в дополнительном коде:

int abs32 (signed int value)
{
    if (0x80000000==(unsigned int)value)
        return 0x7FFFFFFF;
    else if (0 > value)
        return -value;
    else
        return value;
}

Функция abs32 выходит из ситуации преобразования числа -2147483648 ценой ошибки на единицу, т. е. для числа -2147483648 она возвращает результат 2147483647 (0x7FFFFFFF).

[Ссылки]

1. Дополнительный код (представление числа) site:ru.wikipedia.org.