![](/user_photo/_userpic.png)
Программные преобразования числовой информации (96
..pdfций может возникать нарушение нормализации вправо или влево. Получившиеся числа необходимо нормализовать: в памяти они должны храниться в нормализованном виде.
Операция нормализации влево заключается в последовательном арифметическом сдвиге прямого кода мантиссы влево с одновременным вычитанием единицы при каждом сдвиге из порядка числа. Процесс продолжается до тех пор, пока мантисса не примет нормализованный вид. Чтобы нормализовать число X = 0,00001110 · 2110, имеющее нарушение нормализации вправо на четыре разряда, необходимо выполнить нормализацию влево, и число примет вид 0,11100000 · 2010.
Операция нормализации вправо осуществляется сдвигом мантиссы числа на один разряд вправо с одновременным увеличением порядка на единицу. Если имеющее нарушение нормализации влево число X = 1,1011001 · 2101, то после выполнения операции нормализации вправо число примет вид 0,1101100 · 2110.
В персональных ЭВМ используются два формата представления чисел с плавающей запятой: короткий и длинный, имеющие, соответственно, длину 32 и 64 разряда. Для представления смещенного порядка отведено 8 разрядов (смещение A = 128). В коротком формате двоичная мантисса имеет 23 разряда, а в длинном – 55. Числа в памяти всегда представляются в нормализованной форме, при которой старший разряд мантиссы всегда есть 1, и поэтому его значение не фиксируется, а подразумевается. Таким образом, на один разряд увеличивается точность представления мантиссы. Использование скрытого старшего разряда приводит к тому, что нулевая мантисса неотличима от мантиссы числа 0,5. Поэтому число с нулевой мантиссой имеет код, содержащий все нули в разрядной сетке.
5. ПРОГРАММНАЯ РЕАЛИЗАЦИЯ АЛГОРИТМОВ
Рассмотрим программную реализацию алгоритмов перевода чисел в различных системах счисления на примере перевода чисел с использованием арифметики исходной системы счисления.
Перевод целых чисел. Алгоритм перевода целых чисел с использованием арифметики исходной системы счисления можно реализовать «напрямую» или с использованием механизма рекурсии. Код во втором случае значительно проще:
11
Procedure BinInt (n:Word;var s:String); begin
If n>1 Then BinInt (n div 2,s); s := s+Chr(n Mod 2+Ord('0')); end;
Перевод правильной дроби. Данный алгоритм представим в виде функции:
Function BinFrac(n:real;p:Byte):String; Var
s:String;
i:Byte; Begin
s:='';
For i:=1 To p Do begin
n:= 2*n;
s :=s +Chr(Trunc(n)+Ord('0')); n:= Frac(n);
end; BinFrac :=s;
end;
Таким образом, программа перевода положительного вещественного числа в двоичную систему счисления будет иметь следующий вид:
program BinReal1; Var
x:real;
b:Byte;
sbin:string; begin
Write('Введите вещественное x - ');Readln(x); Write('Введите число двоичных разрядов -');
Readln(b);
BinInt(Trunc(x),sbin);
sbin := sbin+'.'+BinFrac(Frac(x),b);
12
Writeln('В двоичной системе счисления: ',sbin); Readln;
end.
Аналогичным образом можно выполнить перевод числа в любую позиционную систему счисления. Представим процедуру HexInt, в которой реализован рассмотренный алгоритм для преобразования числа в шестнадцатеричную систему счисления, и процедуру WriteHexInt, которая выводит полученный результат на экран, сопровождая его символом $:
Procedure HexInt (n:cardinal;var s:string); Var
nm:byte;
ch:char; begin
If n>15 Then HexInt (n div 16,s); nm:= n mod 16;
If nm <10 Then ch:=Chr(nm+Ord('0')) Else ch:= Chr(nm+Ord('A')-10);
s:=s+ch;
end;
Procedure WriteHexInt(s:string;n:cardinal); var
st:string; begin
HexInt(n,st); st:=s+'$'+st; Writeln(st);
end;
Рассмотрим теперь задачу вывода на экран целого числа в двоичной системе счисления. В данном случае речь идет не о переводе числа в двоичную систему счисления, а о том, в каком виде целые числа хранятся в памяти компьютера. Для этой цели используем операцию поразрядного сдвига:
Procedure BinaryInt (w:cardinal); var
mask : cardinal;
13
begin
mask := $80000000; While mask<>0 Do
begin
If w and mask =0 Then Write ('0') Else Write ('1');
mask := mask shr 1; end;
end;
Представленная процедура выводит на экран значения битов 32-разрядного целого числа (тип cardinal).
Во многих случаях необходимо знать значения бит в области, которая не допускает непосредственного исполнения битовых операторов. Например, расположение бит в вещественном числе типа single, real и т. п. Подобная задача решена выше для целых чисел (cardinal), поскольку целочисленные типы допускают применение операторов битовой логики. Кроме того, тип cardinal при логических сдвигах дополняется нулями, в то время как тип integer дополняется при сдвигах единицами. Один из способов представления вещественного числа в двоичном виде заключается в использовании целочисленного представления области, в которой находится вещественное число. Для этого можно использовать директиву absolute, по которой различные переменные располагаются по одному адресу в памяти, или же определить специальный комбинированный тип с соответствующими вариантными полями. Например, чтобы расположить 32-битовую переменную типа single по адресу переменной типа cardinal, можно объявить следующий комбинированный тип:
Type
rCardSingl = Record
case Byte of
0:(n : cardinal); // целочисленное представление области
1:(f : single); // вещественное представление
области
end;
Var g : rCardSingl;
14
![](/html/65386/468/html_BQJkksh6QO.mWnE/htmlconvd-oo8Df515x1.jpg)
Здесь идентификатор rCardSingl является именем объявляемого типа в венгерской нотации. Префикс r используется для обозначения комбинированного типа. Имя rCardSingl выбрано произвольно согласно обстоятельствам.
Переменная объявленного типа g занимает в памяти 4 байта, поскольку каждая из внутренних переменных занимает также по 4 байта. Особенность в том, что n и f находятся по одному адресу (рис. 1). В этом случае говорят, что это две возможности видения одной области. Доступ к варианту целого числа записывается как g.n, а доступ к варианту вещественного числа – как g.f.
g |
|
n:cardinal |
||
|
|
|
|
|
|
|
|
|
|
|
|
f:single |
Рис. 1. Объединенное расположение переменных n и f по одному адресу в переменной комбинированного типа g
Еще одним способом адресного совмещения переменных различных типов является применение директивы absolute:
Var
n: cardinal;
f : single absolute n;
При таком описании значение переменной f располагается по адресу переменной n. В дальнейшем будет использоваться первый вариант объединения.
6. БИТОВАЯ КОНСТРУКЦИЯ ПЕРЕМЕННОЙ ТИПА single
Ниже представлена программа Prog1, в которой тип rCardSingl использован для вывода на монитор бит переменной типа single. Чтобы понять особенности представления вещественных чисел в микропроцессоре, сделаем преобразования для чисел, например 6,25, 1,25, 0,25, и их отрицательных аналогов:
15
Program Prog1;
Type
rCardSingl = Record
Case Byte of
0:(n:cardinal);
1:(f:single);
end;
Procedure BinaryInt(w:cardinal); var
mask : cardinal; begin
mask := $80000000; While mask<>0 Do
begin
If w and mask =0 Then Write ('0') Else Write ('1');
mask := mask shr 1; end;
end;
var
x : Single;
g: rCardSingl; begin
Readln (x); g.f :=x;
BinaryInt(g.n);
Readln;
end.
В результате выполнения программы Prog1 на экран будет выведена следующая информация:
6.25
01000000110010000000000000000000 -6.25 11000000110010000000000000000000
0.25
00111110100000000000000000000000 -0.25 10111110100000000000000000000000
1.25
16
00111111101000000000000000000000 -1.25 10111111101000000000000000000000
В начале программного файла Prog1 находится объявление типа rCardSingl , в котором область из 4 байт можно рассматривать как формат типа cardinal или как формат single. По формату поля f вещественное число загружается в область типа, а по формату n применяются битовые конъюнкция и сдвиг.
Анализ битового представления числа в формате single требует пояснения. Начнем с мантиссы числа, например 6,25. Мантисса занимает биты 0 – 22 . В строке монитора это число имеет мантиссу, показанную на рис. 2.
|
22 |
|
21 |
|
20 |
|
19 |
18 |
17 |
16 |
15 |
14 |
13 |
12 |
11 |
|
||||||||||||||||||||||
|
1 |
|
0 |
|
0 |
|
1 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
||||||||||||||
|
10 |
9 |
8 |
|
|
7 |
|
6 |
|
5 |
|
4 |
|
3 |
|
2 |
|
1 |
|
0 |
|
|
||||||||||||||||
|
0 |
|
0 |
|
0 |
|
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
|
||||||||||||||
|
|
|
|
|
|
Рис. 2. Мантисса числа 6,25 в переменной типа single |
|
|
|
|
||||||||||||||||||||||||||||
Следует обратить внимание на то, что нормализованное двоич- |
||||||||||||||||||||||||||||||||||||||
ное представление числа 6,25 |
имеет вид |
|
0,11001 1032 . Казалось |
бы, на рис. 2 отсутствует старшая единица мантиссы. Но так как все нормализованные двоичные числа (за исключением нуля) обязательно содержат единицу в начале дробной части мантиссы, то можно не хранить эту единицу, тем самым увеличивая хранимую в памяти мантиссу на 1 бит. Так получаем небольшой выигрыш по точности производимых вычислений. Если число необходимо вывести на монитор, то эту «скрытую» единицу восстанавливают. Бит 31 содержит 0, если число положительное, 1 – если число отрицательное.
Теперь обратим внимание на порядок числа. В формате single он занимает биты 23 – 30. Порядок числа 6,25 показан на рис. 3.
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Рис. 3. Порядок числа 6,25 в переменной типа single
17
Чтобы получить истинное число, бит 30 можно интерпретировать как бит направления сдвига мантиссы. Если значение в этом бите равно 1, то имеем положительный порядок, и мантиссу следует сдвинуть влево. Если – 0, то порядок отрицательный, и мантиссу необходимо сдвигать вправо. Порядок хранимой мантиссы определяется после добавления 1 к битам 23 – 29. Это порядок 2 для числа 6,25.
Возможна другая интерпретация значения бита 30. Если значение бита 30 прибавить к битам 23 – 29, то получим порядок хранимой мантиссы. Так, для целой части 6 порядок хранимой мантиссы равен двум.
В любом случае к полученному результату необходимо приписать «скрытую» 1 перед началом числа. Для числа 6,25 хранимая мантисса – 1001. Истинная мантисса – это 11001.
Отрицательные порядки нормализованных чисел в формате single хранятся в обратном коде. Например, при выполнении
программы Prog1 число 0,2510 = 0,12 10−21 изображено на мони-
торе с нулевой мантиссой в битах 0 – 22. Это связано с тем, что старшая единица мантиссы скрыта. А поскольку в числе 0,25 находится только одна единица, то хранимая мантисса представляется как 0. Порядок числа 0,25 показан на рис. 4.
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
0 |
1 |
1 |
1 |
1 |
1 |
0 |
1 |
Рис. 4. Порядок числа 0,25 в переменной типа single
Биты 23 – 29 содержат обратный код числа 2. После инверсии бит 23 – 29 получаем число 0000010. Это ровно столько, сколь необходимо сделать одиночных сдвигов вправо, чтобы получить из «спрятанной» единицы число 0,012.
Особый интерес вызывает хранение чисел с единицей в целой части. По результатам программы видно, что хранимая мантисса числа 1,25 имеет вид, показанный на рис. 5.
Опять следует принять во внимание «спрятанную» единицу. Поэтому в мантиссе остается только «дробная часть» 012. Порядок числа 1,25 выглядит несколько своеобразно в «отрицательном» виде, хотя число 1,25 имеет явно положительный порядок (рис. 6).
18
22 |
21 |
20 |
|
19 |
18 |
|
17 |
|
|
16 |
|
15 |
14 |
|
13 |
|
12 |
|||||||||||||||||
0 |
|
|
1 |
|
|
|
0 |
|
|
0 |
0 |
|
0 |
|
|
|
0 |
|
|
|
0 |
0 |
|
0 |
|
|
0 |
|
||||||
|
|
11 |
|
10 |
|
9 |
8 |
7 |
|
6 |
|
5 |
4 |
3 |
2 |
|
1 |
|
0 |
|
||||||||||||||
|
|
0 |
|
|
0 |
|
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
0 |
|
|||||||
|
|
Рис. 5. Мантисса числа 1,25 в переменной типа single |
||||||||||||||||||||||||||||||||
|
|
30 |
|
29 |
|
|
28 |
27 |
|
|
|
26 |
|
|
|
25 |
24 |
|
23 |
|
|
|
||||||||||||
|
|
0 |
|
|
|
1 |
|
|
1 |
|
1 |
|
|
|
1 |
|
|
|
|
1 |
|
1 |
|
|
1 |
|
|
|
|
Рис. 6. Порядок числа 1,25 в переменной типа single
Инверсия бит 23 – 29 дает порядок 0 для хранимой мантиссы числа 1,25. При восстановлении истинного вида числа к хранимой мантиссе будет приписана единица слева, т. е. получаем
012 ~ 1,012 = 0,2510.
7. МОДЕЛИРОВАНИЕ ПРЕОБРАЗОВАНИЯ single - integer
В представляемой ниже программе Prog2 запрограммированы действия, которые рассматривались в разд. 6 для получения истинного кода целой части числа из порядка и хранимой мантиссы вещественного числа в формате single.
Чтобы понять, каким образом создается порядок целой части числа в формате single, напишем программу Prog2, в которой произвольное вещественное четырехбайтное число в формате single преобразуется в целое четырехбайтное число формата integer. Это равносильно определению целой части вещественного числа. Следует отметить, что возможности языков программирования позволяют решить задачу с помощью стандартных средств:
n := Trunc( 6.25 );
19
Однако за такой простотой одной инструкции скрывается выполнение действий, подобных функции FloatInt() из програм-
мы Prog2.
Program Prog2;
Type
rCardSingl = Record
Case Byte of
0:(n:cardinal);
1:(f:single);
end;
Procedure BinaryInt(s:string;w:integer;k:byte); var
mask : cardinal; begin
If k=32 Then mask := $80000000 Else If k=16 Then mask := $8000
Else If k=8 Then mask := $80 Else Exit;
Write (s); While mask<>0 Do
begin
If w and mask =0 Then Write ('0') Else Write ('1');
mask := mask shr 1; end;
Writeln;
end;
Function FloatInt (ff:single):integer; var
g: rCardSingl; t,z:integer; p:byte;
begin
g.f := ff;
If g.n=0 Then begin Result:=0; Exit;
end;
20