Отрицательные числа. Внутри компьютера все числа, хранятся в двоичном виде. Как представлять отрицательные числа, если двоичный разряд может быть только в двух состояниях?
Способ представления, в котором один из битов обозначает знак числа, означает то, что "знаковый" бит должен обрабатываться особым способом, в отличие от "числовых" бит. Например, если 000000002 – соответствует нулю, а 000000012 – плюс единице, то число 100000012 должно обозначать минус единицу [1]. Каким образом компьютер будет вычитать от нуля единицу, чтобы получить такое представление?
К тому же в такой системе записи есть два нуля: 00000000 (+0) и 10000000 (-0), отсюда следует, что в восьми битах можно записать 255 чисел от –127 до +127.
Исходя из вышеперечисленных недостатков, в компьютере отрицательные числа хранятся другим способом. Число –1 представлено в двоичном виде так: 111111112, и вычисление разницы между нулём и единицей не вызывает таких сложностей. Достаточно занять единицу из старшего разряда:
Таким образом, восьмибитовой последовательностью разрядов можно закодировать 256 чисел от –128 до +127 (см. Табл. 5.1.). Такая система записи отрицательных чисел называется дополнением до двух и является наиболее распространённой системой.
|
|
Таблица 5.1. Представление отрицательных чисел в одном байте.
Код числа | Значение |
+127 | |
… | … |
+1 | |
-1 | |
-2 | |
… | … |
-128 |
Для того чтобы узнать, как будет выглядеть отрицательное число в двоичном виде, нужно воспользоваться следующей последовательностью действий:
1) модуль числа преобразовать в двоичный вид;
2) инвертировать полученное двоичное число;
3) к результату прибавить 1, соблюдая правила заёма и переноса битов.
Например, число –12 будет выглядеть так:
1) 00001100 (+12)
2) 11110011 (после инверсии всех бит)
(–12 в системе "дополнение до двух")
Чтобы проверить, правильно ли получился перевод отрицательного числа в двоичный вид, достаточно сложить исходный положительный модуль и полученное отрицательное число. В результате должен получиться нуль.
– получился результат, отличный от нуля, но, в связи с тем, что мы получали двоичное отрицательное число, длиной в один байт, то и результат должен быть длиной в один байт. Единица старшего разряда отбрасывается и получается искомый нуль.
Какое отрицательное число соответствует последовательности битов можно определить, совершая действия в обратном порядке:
1) от последовательности бит отнять единицу, соблюдая правила заёма и переноса битов;
2) инвертировать последовательность битов;
3) преобразовать в десятичное число.
Например, число 111001102 означает следующее:
|
|
(отнимаем единицу)
2) 0001 1010 (инвертируем все биты)
3) 0x1A = 26 (модуль отрицательного числа)
Результат: 111001102 = –26.
Шестнадцатибитовое представление отрицательных чисел аналогично восьмибитовому, минус единица представлена цепочкой шестнадцати единичных разрядов: 11111111111111112. Соответственно самое большое число, которое можно записать в слово (два байта) равно 01111111111111112 (), а самое маленькое – 10000000000000002 ()
Мы узнали, как будет выглядеть отрицательное число в компьютере. Убедиться в справедливости этих слов можно с помощью короткой программы.
Пример 5.1. Вывод отрицательных чисел в шестнадцатеричном виде.
#include <conio.h>
#include <stdio.h>
void main()
{ int a;
clrscr();
printf("Введите отрицательное число:");
scanf("%d",&a);
printf("В компьютере число хранится так:%X",a);
getch(); }
Десятичные числа. Хотя десятичная система счисления является более удобной для восприятия человеком, в компьютере числа хранятся в двоичном виде. Это связано с двумя состояниями транзистора – элементарной единицы любого электронного вычислителя. Но некоторые контроллеры используют десятичные числа для обмена данными с устройствами. Этот факт никак не означает, что в контроллерах данные хранятся в десятичном виде. На самом деле применяется двоично-десятичный код (BCD – Binary-Coded Decimal) [1], который удобен при отладке для человека, контролирующего процесс передачи данных.
Для хранения одного десятичного разряда в двоично-десятичном коде требуется 4 бита. Эти четыре бита дают 16 комбинаций () для размещения 10 различных значений (от 0 до 9). При этом 6 оставшихся комбинаций не используются.
Микропроцессор Intel хранит BCD-числа в двух форматах (см. Рис. 5.1.):
· Упакованный двоично-десятичный тип (Packed BCD) – каждый байт содержит две десятичные цифры. Десятичная цифра представляет собой двоичное значение в диапазоне от 0 до 9. При этом двоичное представление старшей цифры занимает старшие 4 бита. Следовательно, диапазон представления десятичного упакованного числа в одном байте составляет от 0 до 99;
· Неупакованный двоично-десятичный тип (Unpacked BCD) – каждый байт содержит одну десятичную цифру в четырёх младших битах. Старшие четыре бита имеют нулевое значение. Диапазон представления десятичного неупакованного числа в одном байте составляет от 0 до 9.
Рис. 5.1. Представление BCD-чисел
Рис. 5.2. Пример представления числа 3917
Второе применение двоично-десятичного кода – финансовые программы, использующие точные вычисления десятичных чисел с большим количеством значащих разрядов. В данном случае применение BCD-чисел оправдано потому, что у них практически нет ограничений по длине – BCD-число может быть представлено цепочкой байт.
Для арифметических вычислений BCD-чисел в микропроцессоре Intel предусмотрены определённые команды, которые работают в основном с неупакованными BCD-числами, т.к. этот формат является байт-ориентированным (каждый разряд десятичного числа кодируется байтом). Упакованные BCD-числа представляют собой бит-ориентированный формат (каждый разряд десятичного числа кодируется четырьмя битами, т.е. не целым байтом).
Стандартные двоично-десятичные арифметические команды работают только с одним байтом или словом BCD-числа, поэтому программисту, если он хочет делать операции с числами, большими 9999, необходимо самостоятельно осуществлять арифметические операции с байтами цепочек двоично-десятичного кода чисел, исправляя переносы и заёмы десятичных разрядов.
Пример 5.2. Преобразование введённого числа в неупакованный двоично-десятичный формат.
#include <stdio.h>
#include <conio.h>
void main ()
{ unsigned char x [20], xx[20];
int c,ext,i,jj,max;
clrscr();
printf("Введите X -->");
jj=0;
do
{ char c=getch(); if (!c) ext = getch();
if (c==13) break;
if (c==27) { textcolor(15);
cprintf(" Esc!!!");
|
|
break; };
if ((c==8)&&(jj>0))
{ cprintf("\b \b");
jj--;
continue; }
cprintf("%c",c);
x[jj]=c;
jj++;
if (jj>9) break;
} while (1);
max=jj;
for (i=0;i<max;i++) xx[i]=x[i]-0x30;
xx[max]=0;
printf("\n\r BCD число=");
for (i=0;i<max;i++) printf("%c",xx[i]+0x30);
getch(); }