- •Выполнение операций над числами,представленными с плавающей точкой (говорят- в плавающей арифметике).
- •Достоинства формы представления чисел с плавающей точкой.
- •Недостатки формы представления чисел с плавающей точкой:
- •2. Объединения.
- •Void binkod (tip n, char s[])
- •Void binkod (tip n,char s[])
- •Void hexkod(tip n,char s[])
- •Int main ()
Лекция 2.
Замечание. typedef и #define
=typedef позволяет пользователю дать новое имя некоторому типу:
typedef тип новое_имя [размерность];
Введенное новое имя можно использовать также, как имена стандартных типов. typedef unsigned int Uint;
Uint k, I, j;
=Директива #define является директивой препроцессора и определяет некоторую подстановку в тексте программы, выполняемую препроцессором. #define используется для определения:
символических констант: #define имя текст_подстановки
Каждое вхождение имени заменяется на текст_подстановки.
#define VER 1 {в С++ лучше писпользовать const ….}
символов, управляющих условной компиляцией: #define имя
#define HEADER_INCLUDED
Используется вместе с директивами #ifdef и #ifndef .
Представление вещественных чисел в памяти ПК
В дальнейшем будем рассматривать тип double
Пример. X=3.5 = 11.12 = (-1)0 *1.11*21
P’=P+1023 P’ = 1+1023 =1024
p’=1024 f=0.11
01000000 |
0000 |
1100 |
00000000 |
00000000 |
00000000 |
… |
00000000 |
7 6 5 4 3 0
16-ый код: 40 0С 00 00 00 00 00 00
Число –3.5: С0 0С 00 00 00 00 00 00
Диапазон чисел, представимых в формате с плавающей точкой (тип double): |X|min<=|X|<=|X|max и X=0 1<=P’<=2046 (для чисел X ≠0)
|M|min*2pmin <=|X| <=|M|max*2pmax и X=0
1*2-1022<=|X| <=(2-2-52)*21023 и X=0
10k<=|X| <=10L lg2=0.30103
k= –1022*lg 2= –307.65266= -308+0.34734
L= 1024* lg 2=1024*0.30103=308.25472
2.2*10-308<=|X| <=1.7*10308 и X=0
__[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\] _____|_____[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]______
–Xmax -Xmin 0 Xmin Xmax
Точность чисел, представленных в формате с плавающей точкой: часто вместо числа Х в МС хранится его приближение Х*. Погрешность вносится из-за хранения приближенного значения мантиссы.
Абсолютная погрешность числа Х*:
|X – X*| = ∆( Х*) = |MX –MX*|*2px = 2-52*2px
т.е. абсолютная погрешность числа зависит от порядка числа. Обычно для формата с плавающей точкой определяют относительную погрешность Х* : (Х*)
Для пользователя более важным является практический вопрос: сколько значащих цифр десятичного представления числа гарантированно сохраняются при таком формате хранения числа. Есть приближенное правило для определения этого количества К цифр при q=2:
m двоичных разрядов мантиссы соответствуют К десятичным цифрам:
К[m / 3.32]; Для типа double К=[53/3.32]=15.96, т.е. для значения типа
double сохраняется в памяти 15-16 десятичных знаков.
Выполнение операций над числами,представленными с плавающей точкой (говорят- в плавающей арифметике).
Пусть X = Mx2Px ,а Y = My2Py
a)Сложение (вычитание) чисел:
Z = X Y = Mx2Px My2Py
={1шаг–выравнивание порядков к большему; пусть Px >Py}
= 2Px(Mx My2Py–Px)
={2 шаг–сдвиг мантиссы My на |Py–Px| разрядов}
= 2Pxmz
= {3шаг–сложение(вычитание) мантисс, получается мантисса mz}.
= Mz 2Pz
Возможны случаи:
1 |mz| < 2 операция закончена, Mz = mz ; Pz = Px ;
2 |mz|, но |mz| <4
выполняется нормализация результата сдвигом мантиссы вправо на 1 разряд с коррекцией порядка (+1);
|mz| <1 выполняется нормализация результата сдвигом мантиссы влево на t разрядов с коррекцией порядка (–t).
з pх 1.ххххх
– з py 1.xxyyy пусть pх == py
з pх 0.00zzz При вычитании близких чисел
з pz 1.zz??? происходит потеря точности
б)Умножение :
Z = X Y = Mx2Px My2Py = MxMy2Px+Py == Mz 2Pz , где Mz = MxMy ; Pz = Px+Py; т.е. при умножении чисел их мантиссы перемножаются, а порядки складываются. При умножении двух мантисс может получиться результат такой, что потребуется сдвиг мантиссы вправо, но не более, чем на один разряд, тогда нужна коррекция порядка (+1).
в)Деление :
т.е. при делении чисел их мантиссы делятся, а порядки вычитаются. При делении двух мантисс может потребоваться для полученной мантиссы сдвиг влево, но не более, чем на один разряд с коррекцией порядка (–1).
Особые ситуации плавающей арифметики.
Переполнение порядка при выполнении операций плавающей арифметики;
некорректность деления в плавающей арифметике: деление на число с нулевой мантиссой;
потеря значимости: Pz 0, а Mz = 0;
исчезновение порядка: Pz < Pmin , а Mz 0.
Две последние ситуации не являются аварийными, они обычно приводят к тому, что результат Z заменяется нулём – это машинный нуль.
Достоинства формы представления чисел с плавающей точкой.
Сравнительно широкий диапазон чисел;
Хранение только значащих цифр числа. Представление обеспечивает для числа максимальную точность при фиксированной разрядной сетке.
Недостатки формы представления чисел с плавающей точкой:
более сложная конструкция схем, выполняющих операции над числами в процессоре: необходимы отдельные схемы для обработки мантисс, порядков, знаков.
Замечание. Арифметика для формы представления с плавающей точкой имеет некоторые "нехорошие " свойства:
результаты операций получаются, как правило, с погрешностью, поэтому сравнивать два вещественных значения a и b на точное совпадение (a == b) не имеет смысла; проверяют обычно их близость с некоторой точностью : | a – b| < ;
вычитание близких чисел приводит к потере точности, поэтому рекомендуется его избегать;
если a >> b, то их сложение может дать результат a + b = a, а следовательно значение суммы
a + b1 + b2 + … + bn , где bi << a при всех i = 1, 2, …, n, может зависеть от порядка действий.
2. Объединения.
Объединение (union) – частный случай структуры, включает данные разных типов. Особенность объединения состоит в том, что все поля его располагаются по одному и тому же адресу, т.е. все элементы объединения при размещении в памяти имеют одно и тоже нулевое смещение от начала.
Размер объединения равен максимальной из длин его полей.
Описание объединения напоминает описание структуры:
union [имя типа] {описание полей} [список имён] ;
Список имён может содержать имена переменных, указатели,массивы.
Имя типа указывать необязательно,тогда надо указать элемент(ы) в списке имён. Можно указать и то и другое.
Пример.
union ch // ch - имя типа {double x; сhar s[8]; };
|
union // имени типа нет {double x; сhar s[8]; }q; //переменная q-объединение
|
Если введён тип, то можно определять (аналогично структурам):
ch v,w[4]; //переменные, массивы
ch *pch; //указатели
Обращение к элементу объединения:
Имя_объединения . имя_элемента
Указатель на объединение -> имя_элемента
*( Указатель на объединение). имя элемента
Примеры: v.x v.s[i] pch->x *(pch).x
Занести значение в объединение можно присвоив его элементу это значение: q.x=1.57E-2;
Назначение объединения-обеспечить возможность доступа к одному и тому же участку памяти с помощью разных типов. Это позволяет, например, задав значение вещественного числа x, посмотреть (и вывести) содержимое его отдельных байтов s[i], и таким образом получить внутреннее представление вещественного x. Для вещественного данного такой доступ к отдельным байтам невозможен.
//Внутреннее представление вещественных данных
#include <iostream>
#include <iomanip>
using namespace std;
typedef double tip; // рассматриваемый тип обозначим tip
const int L=sizeof(tip); // размер типа в байтах
union {
tip a;
unsigned char u[L];
}q; // q- включает вещ.данное и массив
//байтов размера, равного размеру типа tip
// здесь необходимо учитывать, что значение a в памяти хранится
//в перевёрнутом виде: от младшего байта к старшему,
//внутренность байта не переворачивается.
//Байты строки u в памяти хранятся в порядке u[0],u[1],…u[L-1]
//т.е. u[0]наложится на младший байт a,…u[L-1] на старший байт
//a, поэтому вывод надо начинать с u[L-1], затем u[L-2],… ,u[0], либо строку S формировать с конца.