Зображення дійсних чисел

На відміну від зображення цілих чисел, що відрізняється абсолютною точністю, з дійсними числами не все так просто. Для зображення дійсних чисел у мові С++ використовуються типи float, double, long double (у деяких реалізаціях мови long double відсутній).

Тип float займає 4 байти. З них 1 байт приділяється для знака, 8 бітів – для характеристики і 23 біти – для мантиси. Старший біт мантиси завжди дорівнює 1, тому він не заповнюється, у зв'язку з чим діапазон значень змінної із плаваючою точкою приблизно дорівнює від 3.14E – 38 до 3.14E + 38 (див. табл. 5.5).

Таблиця 5.5

Тип Розмір типу, байт Розмір мантиси, біт Розмір порядку, біт
Float      
Double      
Long double      

Тип 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  
Double x = 2^10 + p – 1  
Long double + = 2^14 + p – 1  

Для простоти розглянемо тип 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 – основа системи числення, р – цілочисельна характеристика.

Також позначимо e0 = 2 р min,e¥ = 2 р max,де р min, р mах– константи, що задають діапазон зміни характеристики. Тоді можна записати, що Кількість розрядів, які відводяться під мантису, обмежує відносну точність зображення чисел у машині. Як характеристику цієї точності використовують величину e1, визначену як найменше машинне число, результат додавання якого до 1 буде машинним числом більше 1.

Нагадаємо, що для дійсних типів float, double кількості бітів, що відводяться під характеристику, дорівнюють 8, 11. При цьому зсув дорівнює відповідно 127 і 1023. Мантиса має сховану одиницю. Ці дані нам знадобляться для подальших обчислень. Величина порядку
p = 1...1 відведена під спеціальні (нечислові) значення.

Таким чином, найменші за модулем додатне й від'ємне числа мають вигляд (трикрапка зазначає, що подібне зображення має місце для двох розглянутих дійсних типів)

  0...01 0...0
  0...01 0...0

Відповідно e0 для дійсних типів float, double дорівнює 2–126, 2–1022.

Праворуч від e0 розташовується множина точок, що йдуть одна за одною з кроком де n – кількість бітів для зображення мантиси конкретного дійсного типу. Чим правіше числа, тим більше буде крок між ними. Наприкінці діапазону зображення відстань між двома сусідніми точками досягає При цьому максимальні за модулем додатне й від'ємне числа мають вигляд

  1...10 1...1
  1...10 1...1

Відповідно e¥ дорівнює 2–128, 2–1024.

Знайдемо значення e1. Зображення числа 1 має вигляд

Float     0...0
Double     0...0
long double     0...0

а найближче до 1 зверху машинне число –

Float     0...01
Double     0...01
long double     0...01

Відповідно e1 дорівнює 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.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: