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