Зміст:
Зображення: http://pikabu.ru/
Вступ
У перші ж дні вивчення Java я натрапив на такий цікавий вид примітивів, як числа з плаваючою точкою. Мене одразу зацікавабо їх особливості та, тим більше, спосіб запису у двійковому коді (що взаємопов'язано). На відміну від будь-якого діапазону цілих чисел, навіть у дуже малому проміжку (наприклад від 1 до 2) їх безліч. І маючи кінцевий розмір пам'яті, неможливо висловити цю множину. То як вони виражені в двійковому коді і як працюють? На жаль, пояснення у
вікі і досить клювання статті на хабрі
тут не дали мені повного розуміння, хоча заклали базу. Усвідомлення прийшло лише після цієї
статті-розбору вранці після прочитання.
Екскурс в історію
(
Почерпнув з цієї статті на Хабре ) У 60-70 рр., коли комп'ютери були великими, а програми - маленькими, ще не було єдиного стандарту обчислень, як і стандарту виразу самого числа з плаваючою точкою. Кожен комп'ютер робив це по-своєму, і помилки були у кожного свої. Але в середині 70-х компанія Intel вирішила зробити нові процесори з підтримуваною "покращеною" арифметикою і заразом стандартизувати її. Для розробки залучабо професорів Вільяма Кехена та Джона Палмера (ні, не автора книг про пиво). Не обійшлося без драм, але все ж таки новий стандарт був розроблений. Нині цей стандарт називають IEEE754
Формат запису числа з плаваючою точкою
Ще у підручниках шкільного курсу всі стикалися з незвичним способом запису дуже великих чи дуже малих чисел виду
1,2×10 3 чи
1,2E3 , що дорівнює
1,2×1000 = 1200 . Це називається спосіб запису через експоненту. У разі ми маємо справу з виразом числа за такою формулою:
N=M×n p , де
- N = 1200 - отримуване число
- M = 1,2 - мантіса - дробова частина, без урахування порядків
- n = 10 - основа порядку. В даному випадку і коли не йдеться про комп'ютери, підставою виступає цифра 10
- p = 3 - ступінь основи
Досить часто підстава порядку мається на увазі, як і записують лише
мантису і значення ступеня підстави, розділяючи їх буквою
E . У нашому прикладі я навів рівнозначні записи
1,2×10 3 і
1,2E3 . ступенями двійки, а чи не десятки, тобто.
n = 2 , вся струнка формула
1,2E3 ламається і це здорово зламало мені мозок.
Знак та ступінь
І що ми маємо? У результаті ми також маємо двійкове число, яке складається з
мантиси — частина, яку зводитимемо в ступінь і саму ступінь. Крім цього, так само як прийнято і у цілих типів, у числах з плаваючою точкою є біт, який визначає знак - буде число позитивним або негативним. Як приклад пропоную розглянути тип
float
, що складається з 32 біт. З числами подвійної точності
double
логіка така сама, тільки вдвічі більше біт. З 32 біт, перший старший відводиться на знак, наступні 8 біт відводяться на експоненту - ступінь, на яку зводитимемо мантису, а решта 23 біти - на мантису. Для демонстрації давайте подивимося приклад:
З першим бітом все дуже просто. Якщо значення першого біта
0, Те число, яке ми отримаємо буде
позитивним . Якщо біт дорівнює
1 , то число буде
негативним . Наступний блок із 8 біт - блок з експонентою. Експонента записується як звичайне
восьмибітне число, а щоб отримати необхідну ступінь нам потрібно від отриманого числа відняти
127 У нашому випадку вісім біт експоненти - це
10000001 . Це відповідає числу
129 . Якщо є питання, як це порахувати, то на зображенні швидка відповідь. Розгорнутий можна отримати на будь-якому курсі булевої алгебри.
1×2 7 + 0×2 6 + 0×2 5 + 0×2 4 + 0×2 3+ 0×2 2 + 0×2 1 + 1×2 0 = 1×128 + 1×1 = 128+1=129 Не складно порахувати, що максимальне число, яке ми можемо отримати з цих 8 біт
11111111 2 = 255 10 (підрядкові
2 і
10 означають двійкову та десятирічну системи обчислення) Однак, якщо використовувати тільки позитивні значення ступеня (
від 0 і до 255 ), то отримані числа будуть мати багато чисел перед комою, але не після? Щоб отримувати негативні значення ступеня, із сформованої експоненти необхідно віднімати
127 . Таким чином, діапазон ступенів буде
від -127 до 128. Якщо використати наш приклад, то необхідний ступінь буде
129-127 = 2 . Поки що запам'ятовуємо це число.
Мантіса
Тепер про мантис. Вона складається з 23 біт, проте спочатку завжди мається на увазі ще одна одиниця, на яку біти не виділяються. Це зроблено з метою доцільності та економії. Те саме число можна виражати різними ступенями, додаючи до мантиси нулі перед або після коми. Найпростіше це зрозуміти з десятковою експонентою:
120 000 = 1,2 10 5 = 0,12 10 6 = 0,012 10 7 = 0,0012 10 8 і т.д. Однак, ввівши фіксоване число в голові мантиси, ми щоразу отримуватимемо нові числа. Приймемо як даність, що перед нашими 23 бітами буде ще одна з одиницею. Зазвичай цей біт від інших оброблять точкою, яка, втім, нічого не означає. Просто так зручніше 1 . 11100000000000000000000
Тепер отриману мантису потрібно зводити на ступінь зліва направо, зменшуючи з кожним кроком ступінь на одну. Стартуємо зі значення ступеня, який ми отримали в результаті обчислення, тобто
2 (Я спеціально вибрав простий приклад, щоб не писати кожне значення ступеня двійки та в наведеній таблиці не обчислював їх, коли відповідний біт дорівнює нулю)
1×2 2 + 1×2 1 + 1×2 0 + 1×2 -1 = 1×4 + 1×2 + 1×1 + 1×0,5 = 4+2+1+0,5 = 7,5 та отримали результат
7,5 , правильність можна перевірити, наприклад, за
цим посиланням
Підсумки
Стандартне число з плаваючою точкою типу
float
складається з 32 біт, перший біт – знак (+ або -), наступні вісім – експонента, наступні 23 – мантиса. По знаку – якщо біт 0 – число позитивне. Якщо біт 1 – негативне.
За експонентом — побітно переводимо в десяткове число (перший ліворуч біт —
128 , другий —
64 , третій —
32 , четвертий —
16 , п'ятий —
8 , шостий —
4 , сьомий —
2 , восьмий —
1 ), з отриманого отримуємо ступінь з якого стартуватимемо.
По мантисі- До наявних 23 біт спереду дописуємо ще один біт зі значенням 1 і з нього починаємо зводити в отриману нами ступінь, з кожним наступним бітом декрементуючи цей ступінь.
That's all folks, kids! PS: У вигляді домашнього завдання, використовуючи цю статтю, залиште в коментарях свої версії, чому при великій кількості арифметичних операцій з числами з точкою, що плаває, виникають помилки точності
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ