Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информационные преобразования числовых форматов (96

..pdf
Скачиваний:
1
Добавлен:
15.11.2022
Размер:
242.9 Кб
Скачать

1

10

1

0

2

10

2

1

2

3

0.1

0.001

0.101 .

(9)

2

 

2

 

 

2

2

 

2

2

2

2

 

Алгоритм перевода дробной части десятичного числа в двоичное число выглядит следующим образом:

1)представление десятичной дроби в виде суммы дробей степени 2;

2)замена десятичных чисел на двоичные числа;

3)выполнение арифметических действий с дробями в двоичной форме.

При ручном переводе используют операцию последовательного умножения исходной дроби и промежуточных результатов

на число 2, отбрасывая получающуюся целую часть. Затем результат записывают в прямом порядке, например: 0.687510 =

0.10112 .

6. НОРМАЛЬНАЯ ФОРМА ВЕЩЕСТВЕННОГО ЧИСЛА

Если речь идет о произвольных вещественных числах, то в позиционной форме (2) количество цифр в целой и дробной частях может произвольно возрастать. Это становится ограничением для компьютерной реализации, поскольку процессор имеет фиксированное количество инструкций для выполнения операций над числами. Выход из создавшейся ситуации дает вариант нормальной формы представления числа X в виде мантиссы M и

множителя – характеристики s p – в системе счисления s:

 

X M s p .

(10)

Число p называют порядком числа. Поскольку в мантиссе отсутствует целая часть числа, то количество цифр может произвольно увеличиваться только в дробной части – это главное свойство нормализации. Окончательно принимают, что мантисса должна

находиться в диапазоне s 1 M 1 . Следовательно,

мантисса

имеет следующую позиционную форму

 

0. x 1x 2 x 3 ... xm n ,

(11)

где n и m – количество цифр в целой и дробной частях числа в позиционной форме (2).

11

Примеры:

110 0.110 10110 ,

0.510 = 0.510 10100 , 0.510 = 0.12 = 0.12 1002 ,

5.2510 101.012 0.101012 1032 , 0.2510 0.012 0.12 1021 .

Нормализованные вещественные числа часто называют числами с плавающей точкой (запятой), поскольку реальный разделитель целой и дробной части в формате (2) перемещается в крайнюю левую позицию формата (11). Теперь процессор компьютера может иметь только несколько инструкций для выполнения арифметических действий над вещественными числами.

Четырехбайтовое представление вещественного числа в компьютере записывается по порядку: знак мантиссы, порядок, мантисса (рис. 2). Кроме того, заметим, что мантисса двоичного числа всегда начинается с 1 за исключением 0. Следовательно, эту цифру 1 можно не хранить, а лишь учитывать в арифметических инструкциях процессора (так называемая спрятанная цифра 1). Тогда мантисса может иметь длину на один бит больше, что является положительным фактором для округления чисел после выполнения вычислений и для вывода на монитор.

31

30

29

28

27

26

25

24

23 22 20 19 18 17 16 … 6

5

4

3

2

1

0

0

1

0

0

0

0

0

0

1

1

0

1

0

 

0

0

0

 

0

0

0

0

0

0

0

 

 

 

 

Порядок

 

 

 

 

 

 

 

Мантисса

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Знак числа (мантиссы)

Рис. 2. Расположение числа +6.25 в четырех байтах

Порядок находится в битах 23–30. Для примера число +6.25. в двоичном нормализованном виде записывается как 0.11001 1032 .

Однако на рис. 2 порядок записан не как 112 = 310, а как 10000001. Это соответствует электронным схемам процессора и имеет свой технический смысл, которого мы касаться не будем.

12

Учтем, что за исключением числа 0 все остальные нормализованные двоичные мантиссы содержат цифру 1 в первой дробной десятичной позиции. Следовательно, реальная мантисса получается из хранимой мантиссы путем приписывания перед ней одной единицы. В нашем примере это выглядит так:

0.1001000…0 0.11001000…0.

Тогда реальный порядок числа должен быть увеличен на 1:

102 + 12 = 112 = 310.

Окончательно получаем вещественное хранимое число с фиксированным расположением точки:

0.10012 1022 0.110012 1032 = 110.012 = 6.2510 .

Ниже представлена программа C2, в которой функция BinaryFloat( ) на мониторе дает битовое изображение четырехбайтового вещественного числа типа float.

//Program C2

//Битовое изображение вещественного числа типа float

//Объединение union

#include <stdio.h>

// printf

#include <conio.h>

// getch

void BinaryFloat( char* text, float ff )

 

{printf( "\n%s", text );// вывод текста на монитор union

{

float f;

 

n;

вещественное представление

}

unsigned int

// битовое представление

u;

//

 

 

// объект объединения

u.f = ff;

копирование в объект объединения

unsigned int b =

0x80000000;

// 1 в бите 31

while( b > 0 )

 

 

// цикл бит

{ ( u.n & b ) ==

0 ? printf( "0" ) : printf("1");

}

b >>= 1;

 

// сдвиг 1 в соседний бит справа

 

 

 

 

 

}

 

 

 

 

 

//---------------------------------------------------

 

 

 

 

 

void main ( void )

 

 

 

{ float f;

// 4-байтная вещественная переменная

13

printf( "f = " ); scanf( "%f", &f );//ввод числа

printf( "f = %f", f );

// монитор

BinaryFloat( "f = ", f );

// бинарный вид числа

getch();

// просмотр результата

}

Если при выполнении программы C2 ввести число 6.25, то следующие строки окажутся на мониторе:

f = 6.25

f = 6.250000

f = 01000000110010000000000000000000

Вывод в двоичном коде совпадает с рис. 2.

7.ПРЕОБРАЗОВАНИЕ ВЕЩЕСТВЕННОГО ЧИСЛА

ВЦЕЛОЕ ЧИСЛО

Математические действия тривиальны, поскольку необходимо только отбросить дробную часть вещественного числа. Число меньше 1 всегда имеет целую часть 0. Рассмотрим пример: программа C3, в которой функция FloatInt() анализирует порядок нормализованной вещественной переменной типа «float» и возвращает целую часть числа типа «int». Два подключаемых файла

(#include «BinaryInt.h» и #include «BinaryFloat.h») содержат функ-

ции вывода на монитор целых BinaryInt() и вещественных BinaryFloat() чисел, взятых соответственно из программ C1 и C2.

Программа С3:

//Program C3

//Преобразование float - int

#include <stdio.h>

// printf

#include <conio.h>

// getch

#include "BinaryInt.h"

// BinaryInt

#include "BinaryFloat.h"

// BinaryFloat

int FloatInt( float ff )

 

{ union

// поле целого типа

{ unsigned int n;

float f;

// поле вещественного типа

14

} u;

// объект объединения

u.f = ff;

// загрузить объединение

if( ( u.n << 1 ) == 0 ) return 0;

// число 0

unsigned int t = u.n << 1 >> 24; // порядок Intel

BinaryInt( "t = ", t );

// бинарный вид порядка

int p = t - 127;

// математический порядок -

1

printf( "\np = %d", p );

// монитор

if( p < 0 ) return 0;

// число <

1

 

 

// модуль мантиссы

unsigned int z = (

( u.n << 8 ) | 0x80000000 ) >>

(

31 – p );

BinaryInt( "z = ",

z );// бинарный вид результата

if( u.n & 0x80000000 ) z = ~z + 1;//отрицательное

BinaryInt( "z = ", z );// бинарный вид результата

return z;

 

// вернуть результат

}

 

 

 

//---------------------------------------------------

 

 

 

void main ( void )

 

переменная

{ float f;

// 4-байтная вещественная

printf( "f = " ); scanf( "%f", &f );//ввод числа

BinaryFloat( "f = ", f );

// бинарный вид числа

int k = FloatInt( f );//преобразование

float-int

printf( "\nk = %d", k );

// просмотр

// монитор

getch();

 

результата

}

 

 

 

Если при выполнении программы C3 ввести число –6.25, то на мониторе появляются следующие строки:

f = 6.25

f = 11000000110010000000000000000000 t = 00000000000000000000000010000001 p = 2

z = 00000000000000000000000000000110 z = 11111111111111111111111111111010 k = –6

15

8.ПРЕОБРАЗОВАНИЕ ЦЕЛОГО ЧИСЛА

ВВЕЩЕСТВЕННОЕ ЧИСЛО

Рассмотрим пример программы C4, в которой функция IntFloat() определяет порядок целого числа и формирует мантиссу и порядок числа типа float. В некотором смысле предстоит выполнить обратные действия программы C3 и ее функции FloatInt().

Программа С4:

// Program C4

//Преобразование целого типа в вещественный тип float

#include <stdio.h>

// printf

#include <conio.h>

// getch

#include "BinaryInt.h"

// BinaryInt

#include "BinaryFloat.h"

// BinaryFloat

float IntFloat( int n )

 

{unsigned int k = n & 0x80000000 ? ~n + 1 : n;

if( k == 0 )

return 0.0;

// число 0

BinaryInt( "k = ", k );

// бинарный вид k

unsigned int b = 0x80000000;

// 1 в бите 31

int p;

 

// порядок числа - 1

for( p = 31; p >= 0; p-- )

// цикл номеров бит

{ if( k & b ) break;

// старший бит найден

b >>= 1;

// сдвинуть 1 в соседний бит справа

}

 

// монитор

printf( "\np = %d", p );

unsigned int t = p + 127;// порядок в стиле Intel BinaryInt( "t = ", t ); // бинарный вид порядка unsigned int m = k << ( 32 - p ) >> 9;// мантисса

BinaryInt( "m = ", m );

// монитор

m |= t << 23;

// модуль вещественного числа

BinaryInt( "m = ", m );

// бинарный вид числа

m |= n & 0x80000000;

 

// знак числа

BinaryInt( "m = ", m );

// монитор

union

 

// целое поле

{ unsigned int d;

 

float f;

 

// вещественное поле

} u;

 

// объект объединения

16

u.d = m;

return u.f; // вернуть результат преобразования

}

 

 

//---------------------------------------------------

 

 

void main ( void )

// 4-байтная целая переменная

{ int n;

printf( "n = " );

scanf( "%d", &n );//ввод числа

BinaryInt( "n = ", n );

// бинарный вид числа

float f = IntFloat( n);//преобразование int-float

printf( "\nf = %f", f );

// монитор

BinaryFloat( "f = ", f );

// бинарный вид числа

getch();

 

// просмотр результата

}

 

 

Если при выполнении программы C4 ввести произвольное число, например, –6, то на мониторе появляются следующие строки:

n = –6

n = 11111111111111111111111111111010 k = 00000000000000000000000000000110 p = 2

t = 00000000000000000000000100000001 m = 00000000010000000000000000000000 m = 01000000110000000000000000000000 m = 11000000110000000000000000000000 f = –6.000000

f = 11000000110000000000000000000000

9. ФИКСИРОВАННЫЙ ВЕЩЕСТВЕННЫЙ ФОРМАТ

По отношению к компьютеру внешние устройства могут располагать информационные биты вещественных чисел по своему усмотрению, не затрачивая время на преобразования нормализации. Такая технология используется в контрольно-измеритель- ных и управляющих устройствах, когда компьютер выполняет главные вычислительные действия и принимает решения по со-

17

вокупности датчиков о воздействии на исполнительные органы машин и аппаратов. Тогда в контроллерах и микропроцессорах внешних устройств подразумевается расположение разделяющей точки целой и дробной частей числа между фиксированно заданными битами.

Например, если число имеет четыре бита в дробной части, то точка подразумевается между битами 3 и 4 (рис. 3). По экономическим и производственным причинам процессор компьютера, как правило, не имеет специальных инструкций для выполнения арифметических действий с фиксированными вещественными числами. В такой ситуации необходимы программы, позволяющие преобразовывать вещественные числа из фиксированного формата в нормализованный формат и наоборот.

1

 

10

9

8

7

6

5

4

3

2

 

1

0

 

1

 

0

0

 

0

0

1

 

1

0

0

 

1

 

0

0

 

 

 

 

 

Целая часть

 

 

 

 

 

Дробная часть

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Знак числа

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Разделяющая дробная точка

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 3. Фиксированное 12-битовое расположение вещественного числа –6.25 в прямом коде. Положение разделяющей дробной точки подразумевается между битами 3 и 4. Шестнадцатеричный код числа 0 × 864 = = –6.25

Рассмотрим пример программы C5, в которой функция FixedFloat() преобразует вещественное число из фиксированного формата с разделяющей точкой между битами 3 и 4 в нормализованный формат мантиссы и порядка типа float. Обратное преобразование float – fixed рассматривается далее в программе C6.

Программа С5:

//Program C5

//Преобразование fixed - float

#include <stdio.h>

// printf

#include <conio.h>

// getch

#include "BinaryInt.h"

// BinaryInt

#include "BinaryFloat.h"

// BinaryFloat

18

 

typedef unsigned int DWORD; // синоним целого типа float FixedFloat( DWORD x, DWORD size, DWORD r )

{if( ( x << ( 32 - (size-1) ) ) == 0 ) return 0.0;

DWORD b = 1 << ( size - 2 );

// бит начала числа

BinaryInt( "b = ", b );

// 1

 

// бинарный вид

DWORD s = b << 1;

напротив знака числа

BinaryInt( "s = ", s );

 

 

// бинарный вид

int i;

// позиция старшей

единицы в числе

for( i = size - 2; i >= 0; i-- )

// цикл позиций

{if( x & b ) break; // позиция старшей единицы b >>= 1; // сдвиг 1 в соседний бит справа

}

 

 

// монитор

printf( "\ni = %d", i );

 

int p = i - r;

// математический порядок - 1

printf( "\np = %d", p );

 

// монитор

DWORD t = p + 127;

 

// порядок в стиле Intel

BinaryInt( "t = ", t );

// бинарный вид порядка

DWORD m = x << ( 32 - i ) >> 9; // мантисса Intel

BinaryInt( "m = ", m );

// бинарный вид мантиссы

m |= t << 23;

// модуль вещественного числа

BinaryInt( "m = ", m);//бинарный вид модуля числа

if( x & s ) m |= 0x80000000;

// знак числа

BinaryInt( "m = ", m );// бинарный вид результата

union

 

 

// поле целого типа

{ DWORD d;

 

 

float f;

// поле вещественного типа

} u;

 

 

 

u.d = m;

 

 

// вернуть результат

return u.f;

 

 

}

 

 

 

//---------------------------------------------------

 

 

 

void main ( void )

// фиксированная переменная

{ unsigned int x;

printf( "x = " ); scanf( "%x", &x );// ввод числа

BinaryInt( "x = ", x );

 

// бинарный вид числа

float f = FixedFloat( x, 12, 4);// преобразование

printf( "\nf = %f", f );

 

// монитор

BinaryFloat( "f = ", f );

 

// бинарный вид числа

getch();

 

// просмотр результата

}

 

 

 

19

Если во время выполнения программы C5 ввести шестнадцатеричное число 864, которое в фиксированном вещественном формате с дробной частью 4 бит соответствует десятичному числу –6.25 (см. рис. 3), то на мониторе появляется следующая информация:

x = 864

x = 00000000000000000000100001100100 b = 00000000000000000000010000000000 s = 00000000000000000000100000000000 i = 6

p = 2

t = 00000000000000000000000010000001 m = 00000000010010000000000000000000 m = 01000000110010000000000000000000 m = 11000000110010000000000000000000 f = –6.25

f = 11000000110010000000000000000000

Ниже представлена программа C6, в которой функция «FloatFixed()» выполняет преобразование нормализованного вещественного числа типа «float» в число фиксированного формата с дробной точкой между битами 3 и 4 (см. рис. 3):

//Program C6

//Преобразование float - fixed

#include <stdio.h>

// printf

#include <conio.h>

// getch

#include "BinaryInt.h"

// BinaryInt

#include "BinaryFloat.h"

// BinaryFloat

typedef unsigned int DWORD;

// синоним целого типа

DWORD FloatFixed( float ff, DWORD size, DWORD r )

{ union

// поле целого типа

{ DWORD n;

float f;

// поле вещественного типа

} u;

// объект объединения

u.f = ff;

// загрузить число в объединение

if( ( u.n << 1 ) == 0 ) return 0;

// число 0

DWORD t = (u.n & 0x7F800000)

>>23;//порядок Intel

BinaryInt( "t = ", t ); //

бинарный вид порядка

20

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]