Как известно, для кодирования целого числа со знаком часто используется дополнительный код (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. Дополнительный код (представление числа) site:ru.wikipedia.org. |