- •Київський національний університет імені Тараса Шевченка
- •Гриф надано Міністерством освіти і науки України (лист № 1.4/18-г-1523 від 20.09.07)
- •Основи алгоритмізації
- •1.1. Поняття алгоритму
- •1.2. Класифікація внутрішніх структур алгоритмів
- •1. Ввести а,b.
- •3. Вивести значення s.
- •4. Кінець.
- •6. Закінчити роботу.
- •1. Ввести число n.
- •6. Перехід до п.3.
- •7. Друк к.
- •8. Кінець.
- •1.3. Складність алгоритмів
- •1.4. Складність задач
- •Завдання для самостійної роботи
- •Форма Бекуса – Наура
- •Завдання для самостійної роботи
- •Void main(){
- •3.2. Структура с-програми
- •3.3. Описувачі
- •3.4. Основні операції мови с
- •If(!inword)
- •Void main()
- •Int rozmir;
- •3.5. Оператори мови с
- •3.5.1. Прості оператори
- •3.5.2. Умовний оператор
- •3.5.3. Оператор циклу for
- •3.5.4. Оператори do-while, while
- •3.5.5. Оператор continue
- •3.5.6. Оператор-перемикач switch
- •3.5.7. Оператор break
- •3.5.8. Оператор goto
- •If(error(I,j,k)) goto exit;
- •3.5.9. Оператор return
- •3.6. Директиви препроцесору та вказівки компілятору
- •3.6.1. Директива препроцесору #define
- •1. Макровизначення:
- •3.6.3. Директива #include
- •3.6.4. Директиви умовної компіляції #if, #elif, #else, #endif
- •3.6.5. Директива #line
- •If(!cond)
- •3.7. Описувачі з модифікаторами
- •3.7.1. Моделі пам'яті
- •3.7.2. Модифікатори типу доступу в пам'яті
- •Int huge*near X;
- •3.7.3. Модифікатори const, volatile, cdecl, pascal, interrupt
- •Volatile int t;
- •Void interrupt timer()
- •Void wait(int interval)
- •Завдання для самостійної роботи
- •Принципи типізації даних
- •4.1. Прості типи даних
- •4.2. Похідні типи
- •4.3. Еквівалентність типів
- •4.4. Успадкування атрибутів
- •4.5. Перераховні типи
- •4.6. Логічні типи
- •4.7. Символьні типи
- •4.8. Числові типи
- •4.9. Структурні типи даних
- •4.9.1. Масиви
- •4.9.2. Структури
- •Int year;
- •4.10. Деякі особливості типів даних c
- •4.10.1. Базові типи даних
- •4.10.2. Перетворення типів
- •Int atoi(char s[]) /*char* s*/
- •4.10.3. Засіб typedef
- •Int curs;
- •4.10.4. Покажчики та масиви
- •Void * p;
- •Int array[12];
- •Void f(int a[])
- •Int f(char * s)
- •Наведемо деякі приклади розв'язання задач.
- •Int shift; /*відступ*/
- •Int count[n]; /*кількість монет даного типу (коефіцієнти ai)*/
- •Int coin;
- •Int sum; /*монета, яку міняємо*/
- •Int maxcoin; /*індекс по масиву cost[] монети максимальної вартості, допустимої при даному розміні.*/
- •If(count[I])
- •If(maxcoin)
- •Int* ctranspon (int *a,int n,int m)
- •Void dobutok(int* a, int* b, int** c, int n, int m)
- •Int n,m,I,size;
- •Int main()
- •4.10.5. Структури та об'єднання
- •Розглянемо деякі приклади розв'язання задач.
- •Int hashfunc(key); int eqkey(key, key);
- •Void freeval(val); void setval(val, val);
- •Void freekey(key); void setkey(key, key);
- •Int hashfunc(key key){
- •Val val; /*значення*/
- •Void set(key key, val val){
- •Void printcell(struct cell *ptr){
- •Void main(void)
- •Завдання для самостійної роботи
- •Зображення чисел у комп'ютері
- •Int main(void)
- •5.1. Системи числення
- •5.2. Правила переведення чисел з однієї системи числення в іншу
- •5.3. Правило визначення точності зображення
- •5.4. Двійкова арифметика
- •5.4.1. Додавання двійкових чисел
- •5.4.2. Зображення від'ємних чисел
- •XXXXXXXX 00000001 00000000.
- •5.4.3. Віднімання двійкових чисел
- •5.4.4. Множення двійкових чисел
- •5.4.5. Ділення двійкових чисел
- •5.5. Ознака переповнення розрядної сітки при арифметичних операціях
- •5.6. Зображення цілих чисел
- •5.7. Зображення дійсних чисел
- •5.8. Керування машинним зображенням чисел та особливості виконання арифметичних операцій
- •Завдання для самостійної роботи
- •Реалізація концепції структурного програмування
- •6.1. Оголошення та визначення функцій
- •Int d;} people;
- •6.2. Формальні та фактичні параметри
- •Void swap(int a,int b)
- •Void swap(int a,int*b)
- •6.3. Функції зі змінною кількістю параметрів
- •Void sum(char *msg,...)
- •6.5. Параметри функції main
- •6.6. Лiтернi покажчики та функцiї
- •Void strcpy(char*s,char*t)
- •Void f(void)
- •6.8. Класи пам'яті
- •Розглянемо деякі приклади розв'язання задач.
- •I, power(2,I),power(-3,I));
- •Void main() { choturukyt b; tochka *a; float s; long n,in; srand(time(null));
- •6.9. Введення–виведення с. Файли та потоки
- •6.9.1. Функції введення–виведення верхнього рівня
- •6.9.2. Функції введення–виведення консольного термінала та порту
- •Int main(void)
- •6.9.3. Функції введення–виведення нижнього рівня
- •Int main(void)
- •Int handle;
- •Розглянемо приклади розв'язання задач.
- •Void main(void)
- •Void main(argc,argv)
- •If(c& masks[I])
- •If (цей рядок довший за найдовший з попередніх)
- •Int max; /*максимальна довжина*/
- •Int len; /*довжиною цього рядка*/
- •Int nwords; /*кількість слів у рядку*/
- •If(!*s) /*рядок закінчився*/
- •Int ctr; /*кількість входжень слова*/
- •If(!strcmp(word,w[I].Wrd)){
- •If(alert){
- •Void main() { float X,y,z,t,s; int I,j,flag,n,k; m1: clrscr();
- •InitBase (void){
- •Int key, /*новий ключ*/
- •InitBase();
- •Завдання для самостійної роботи
- •7.1. Елементи концепції обєктно-орієнтованого програмування
- •Int year;
- •Int year;
- •7.3. Опис протоколу класу
- •7.4.1. Коментарі
- •7.4.2. Прототипи функцій
- •Void f();
- •7.4.5. Перевантаження функцій
- •Int Name (int first)
- •Int Name (unsigned first)
- •Int Name (int first,char*second)
- •7.4.6. Значення формальних параметрів за умовчанням
- •7.4.7. Посилання й покажчики
- •Void increment(int& X)
- •Int anotherint;
- •7.4.10. Покажчик на void
- •Void*void_ptr;
- •Void swap(void*&item1,void*&item2)
- •7.4.11. Зв'язування зі збереженням типів
- •7.4.12. Про структури та об'єднання
- •7.5. Функції-члени класу
- •X *this;
- •Int year;
- •7.6. Конструктори та деструктори
- •7.6.1. Поняття про конструктори
- •Int*data;
- •Int size;
- •7.6.3. Конструктор копіювання
- •Int data[large];
- •Inline Large1 Large1::fast(const Large1 & b)
- •7.7. Глобальні та локальні об'єкти
- •Void main(void)
- •7.8. Статична пам'ять і класи
- •Int statpol::I;
- •Vоid draw()
- •Int large;
- •Int bigwant;
- •Void f() {
- •Void g(int a)
- •7.9. Успадкування
- •7.9.1. Синтаксична реалізація успадкування
- •7.9.2. Правила доступу до полів даних
- •Void f(void)
- •Void g(void){}//...}
- •7.9.3. Конструктори та деструктори в похідних класах
- •7.9.4. Використання заміщуючих функцій-членів
- •Void Display (void); //замiщувальна функцiя
- •Void Region::Display(void)
- •Void Display(void);};
- •Void Population::Display(void)
- •7.9.5. Похідні класи й покажчики
- •7.9.6. Ієрархія типів
- •XyValue(int_x,int_y):X(_x),y(_y)
- •XyData(int_x,int_y)
- •7.9.7. Множинне успадкування
- •Void SetLoc(int_x,int_y);};
- •Int data;
- •7.10. Віртуальні функції та класи
- •7.10.1. Віртуальні функції
- •Int value;
- •Virtual int GetValue();
- •Int Value::GetValue(){return value;}
- •7.10.2. Чисті віртуальні функції. Абстрактні класи
- •Virtual void f1(void);
- •Virtual void f2(void);//...}
- •Int index;
- •7.10.3. Віртуальні деструктори
- •7.10.4. Посилання як засіб для реалізації поліморфізму
- •7.10.5. Дещо про механізм віртуальних функцій
- •Virtual int method1(float r);
- •Int data;
- •Void func(void){//тіло}};
- •Virtual public CocaCola {
- •Int size;
- •Void ShowValue(void)
- •Void ShowValues(void);};
- •Void Two::ShowValues(void)
- •7.11.2. Дружні функції
- •Void Show(One &c1,Two &c2)
- •Void Show(One &c1);
- •Void Two::Show(One &c1)
- •7.12. Перевантаження операцій
- •7.12.1. Загальний підхід
- •Void main()
- •7.12.2. Перетворення типів
- •X::operator т();
- •7.12.3. Перевантаження операції індексування масиву
- •Int znach;
- •7.12.4. Перевантаження операції виклику функції
- •Int operator()(void);
- •Int FuncClass::operator()(void)
- •Vidnosh*vec;
- •7.12.5. Перевантаження операції доступу до члена класу
- •7.12.6. Перевантаження операцій інкремента й декремента
- •Int index;
- •Void*operator new(size_t)
- •Void*operator new(size_t);
- •8.1. Функціональні шаблони
- •8.1.1. Визначення й використання шаблонів функцій
- •Void func(t t)
- •Int main(void)
- •8.1.2. Перевантаження шаблонів функції
- •Int main(void)
- •8.1.3. Cпецiалiзованi функцiї шаблона
- •Int main(void){
- •8.2. Шаблони класів
- •8.2.1. Визначення шаблонів класу
- •Void push(t t);
- •Int numitems;
- •8.2.2. Константи й типи як параметри шаблона
- •8.2.3. Використання шаблонних класів
- •Int main(void)
- •8.2.4. Спеціалізація шаблонів класу
- •Void add(t item);
- •Int main(void)
- •IArray.Add(i1);
- •Int main(void)
- •IList.Add(i1);
- •Завдання для самостійної роботи
- •Автоматна технологія програмування
- •If(!stop)printf("не входити");
- •Завдання для самостійної роботи
- •Список літератури
- •Передмова 3
5.7. Зображення дійсних чисел
На відміну від зображення цілих чисел, що відрізняється абсолютною точністю, з дійсними числами не все так просто. Для зображення дійсних чисел у мові С++ використовуються типи float, double, long double (у деяких реалізаціях мови long double відсутній).
Тип float займає 4 байти. З них 1 байт приділяється для знака, 8 бітів – для характеристики і 23 біти – для мантиси. Старший біт мантиси завжди дорівнює 1, тому він не заповнюється, у зв'язку з чим діапазон значень змінної із плаваючою точкою приблизно дорівнює від 3.14E – 38 до 3.14E 38 (див. табл. 5.5).
Таблиця 5.5
Тип |
Розмір типу, байт |
Розмір мантиси, біт |
Розмір порядку, біт |
Float |
4 |
23 |
8 |
Double |
8 |
52 |
11 |
Long double |
10 |
64 |
15 |
Тип double займає 8 байтів пам'яті. Його формат аналогічний формату float. Біти пам'яті розподіляються так: 1 біт для знака, 11 – для характеристики і 52 – для мантиси. Із врахуванням випущеного старшого біта мантиси діапазон значень становить від 1.7E – 308 до 1.7E 308. Дані типу long double займають 80 бітів, 15 – характеристика і 64 – мантиса. Діапазон значень – від 3.4 10 – 4932 до 1.1 10 4932.
У класичній математиці дійсні числа мають властивість повноти: між будь-якими двома різними числами завжди знайдеться відмінне від них третє. На комп'ютерне зображення дана властивість не поширюється.
Розглянемо два типи зображення дійсних чисел:
а) з порядком:
знак числа |
порядок |
знак порядку |
мантиса |
б) з характеристикою:
знак числа |
характеристика |
мантиса |
Введення характеристики не вимагає виділення одного біта для знака порядку і спрощує виконання операцій порівняння (<,>,<=,>=) та арифметичних операцій над дійсними числами.
Найрозповсюдженішим способом реалізації дійсних чисел у комп'ютері є використання зображення з характеристикою, що отримується з порядку додаванням такого зсуву, щоб характеристика була позитивною. Нехай, наприклад, на характеристику виділяється 8 бітів. У 8 розрядах вміщуються двійкові числа від 00000000 до 11111111 (від 0 до 255 – у десятковій системі). Усього маємо 256 значень. Розумно ці значення порівну розподілити між від'ємними й додатними значеннями порядку числа: від –127 до 128. Мінімальному значенню порядку має відповідати нульове значення характеристики. Отже, отримуємо зміщення, що дорівнює 127.
Для обчислення істинного порядку числа можна використовувати формулу деn – кількість бітів, відведених для характеристики; p – порядок числа; k – поправочний коефіцієнт фірми IBM, рівний –1 (табл. 5.6).
Таблиця 5.6
Тип |
Характеристика |
Кількість бітів на характеристику |
Float |
x 2^7 p – 1 |
8 |
Double |
x 2^10 p – 1 |
11 |
Long double |
2^14 p – 1 |
15 |
Для простоти розглянемо тип float, оскільки він найкоротший. Зображення інших типів відрізняються від нього тільки кількісно. Зауважимо, що в процесорах Intel байти у багатобайтових значеннях переставляються так, що молодший іде першим, а старший – останнім.
У мантисі зберігається двійкове ціле число. Щоб одержати істинне значення мантиси, до неї треба умовно додати ліворуч одиницю з крапкою. Таким чином, маючи 23 двійкових розряди, ми записуємо числа з точністю до 24 двійкових розрядів. Це пов'язано з тим, що використовується нормалізоване зображення дійсного числа. Нормалізація означає, що мантиса (для двійкового зображення), крім випадку, коли вона дорівнює 0, має знаходитися в інтервалі
Наведений метод нормалізації є класичним, коли її результат зображується у вигляді правильного дробу, тобто з одиницею після крапки й нулем у цілій частині числа. Тоді ненульова мантиса будь-якого числа з плаваючою точкою має починатися з двійкової одиниці. Ця одиниця враховується, однак не записується в мантису. Її часто називають прихованою одиницею.
У комп'ютерах на базі процесорів Intel нормалізована мантиса містить старший біт ліворуч від крапки. Іншими словами, нормалізована мантиса належить інтервалу У пам'яті машини для даних типуfloat,double цей біт не зберігається, він прихований і використовується для збільшення порядку. Для додатних і від'ємних чисел нормалізована мантиса в пам'яті зображена в прямому коді.
Старший біт у зображенні чисел у форматі з плаваючою точкою є знаковим. Зазвичай нуль позначає додатне число, а одиниця – від'ємне.
Якщо всі біти характеристики дорівнюють одиниці, а мантиси – нулю, то ми одержуємо комбінацію, відому як INF (від англійського Infinity – нескінченність). Ця комбінація використовується тоді, коли результат обчислень перевищує максимально припустиме форматом число. Залежно від значення знакового біта, нескінченність може бути додатною чи від'ємною. Якщо ж при такому порядку в мантисі принаймні один біт не дорівнює нулю, то така комбінація називається NAN (Not A Number – не число). Спроби використання комбінацій NAN чи INF приводять до помилки часу виконання.
Із врахуванням усіх цих правил комбінація, коли й у мантисі, і в порядку всі біти дорівнюють нулю, дає 00. З математичного погляду ця комбінація безглузда, але розробники формату домовилися вважати її нулем.
Тип double подібний типу float, різниця полягає лише в кількості розрядів і в тому, яке значення характеристики приймається за нуль. У double ми маємо 11 розрядів для характеристики, а за нуль приймається значення 1023.
Дещо іншим є тип long double. Крім різниці кількості байтів для зображення, існує ще якісна: у мантисі явно вказується перший розряд. Мантиса 1010… інтерпретується як 1.01, а не 1.10, як це було у float чи double. Тому, якщо 23-бітна мантиса типу float забезпечує 24-знакову точність, 52-бітна мантиса double – 53-бітну, то 64-бітна мантиса long double забезпечує 64-, а не 65-бітну точність.
Позначимо нормалізоване машинне зображення числа із плаваючою точкою :
де М – мантиса 2 – основа системи числення,р – цілочисельна характеристика.
Також позначимо 0 2рmin, 2рmax, де рmin, рmах – константи, що задають діапазон зміни характеристики. Тоді можна записати, що Кількість розрядів, які відводяться під мантису, обмежує відносну точність зображення чисел у машині. Як характеристику цієї точності використовують величину1, визначену як найменше машинне число, результат додавання якого до 1 буде машинним числом більше 1.
Нагадаємо, що для дійсних типів float, double кількості бітів, що відводяться під характеристику, дорівнюють 8, 11. При цьому зсув дорівнює відповідно 127 і 1023. Мантиса має сховану одиницю. Ці дані нам знадобляться для подальших обчислень. Величина порядку p 1...1 відведена під спеціальні (нечислові) значення.
Таким чином, найменші за модулем додатне й від'ємне числа мають вигляд (трикрапка зазначає, що подібне зображення має місце для двох розглянутих дійсних типів)
0 |
0...01 |
0...0 |
1 |
0...01 |
0...0 |
Відповідно 0 для дійсних типів float, double дорівнює 2–126, 2–1022.
Праворуч від 0 розташовується множина точок, що йдуть одна за одною з кроком деn – кількість бітів для зображення мантиси конкретного дійсного типу. Чим правіше числа, тим більше буде крок між ними. Наприкінці діапазону зображення відстань між двома сусідніми точками досягає При цьому максимальні за модулем додатне й від'ємне числа мають вигляд
0 |
1...10 |
1...1 |
1 |
1...10 |
1...1 |
Відповідно дорівнює 2–128, 2–1024.
Знайдемо значення 1. Зображення числа 1 має вигляд
Float |
0 |
01111111 |
0...0 |
Double |
0 |
01111111111 |
0...0 |
long double |
0 |
011111111111111 |
0...0 |
а найближче до 1 зверху машинне число –
Float |
0 |
01111111 |
0...01 |
Double |
0 |
01111111111 |
0...01 |
long double |
0 |
011111111111111 |
0...01 |
Відповідно 1 дорівнює 2–24, 2–53 та 2–64.
Важливою характеристикою комп'ютера є співвідношення
Означення 5.1. Характеристики точності називаються збалансованими, якщо виконуються нерівності . Якщо ці умови не виконані, то при реалізації обчислювальних задач необхідно використовувати спеціальні прийоми.
Описані особливості машинного зображення дійсних чисел приводять до того, що не для всіх його елементів вірні такі співвідношення:
1. ;
2. існує;
3. ;
4. .
Наведемо кілька прикладів.
1. Показати, що .
#include <stdio.h>
main()
{
double x,y,z;
x=1.0e-16;
y=1.+(x+x);
z=(1.+x)+x;
(y==z)?printf("\n!!Yes!!\n"): printf("\n!!No!!\n");
printf("y=%.16f",y);
printf("z=%.16f",z);
}
2. Написати програму для розв'язання квадратного рівняння для значень коефіцієнтів:,
#include <stdio.h>
#include <math.h>
main()
{
double a,b,c,d,x1,x2;
a=0.2e-45;
b=1.;
c=1.;
d=b*b-4*a*c;
if(d>0)
{
x1=(-b+sqrt(d))/(2*a);
x2=(-b-sqrt(d))/(2*a);
printf("x1=%e\nx2=%e\n",x1,x2);
printf("a*x1^2+b*x1+c=%e\n",a*x1*x1+b*x1+c);
printf("a*x2^2+b*x2+c=%e\n",a*x2*x2+b*x2+c);
}
else
if(d==0){
x1=-b/(2*a);
printf("x1=%e\n",x1);
}
else printf("no roots\n");
}
При завершенні роботи програми ми одержимо, що Підставивши ці значення до квадратного рівняння, у результаті дістанемо1.