Чому комп'ютери не зберігають десяткові числа як друге ціле число?


24

Комп'ютери мають проблеми зі зберіганням дробових чисел, де знаменник - це щось інше, ніж рішення для 2 ^ x. Це тому, що перша цифра після десяткової варто 1/2, друга 1/4 (або 1 / (2 ^ 1) і 1 / (2 ^ 2)) і т.д.

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

Єдине, що я можу придумати, - це мати повторення десяткових знаків (у базі 10), але це могло бути кращим рішенням для цього (як у нас зараз з нескінченністю).


8
Ви повинні подивитися, як зберігаються десяткові типи, на відміну від типів float / double.
Одід

9
Не знаю, наскільки це точніше. Перша цифра після десяткової дорівнює 1/10, друга 1/100 і т. Д. Яким чином у вас є більш точні проблеми з округленням (як ви представляєте 1/3)? Різниця полягає лише в тому, які значення можна точно представити.
Мартін Йорк

17
Десяткова плаваюча точка (про що ви маєте на увазі дві, просто в більш незграбному поданні) не є більш неточною, ніж двійкова плаваюча точка. Різниця полягає лише в тому, які значення не можуть бути представлені, і оскільки ми звикли до десяткової системи, ми не помічаємо помилок десяткової версії. І ні, і не можуть представляти всі раціональні та ірраціональні числа.

1
Зрештою, це знижується до ефективності. Комп'ютери є двійковими, а схеми роботи з цим бінарним поданням набагато менш складні. Важливість цього може бути дещо зменшена сьогодні, але це був дуже важкий час. Крім того, будь-яке представлення, яке ви вирішите зберігати на вашому номері (у обмеженому просторі), матиме кінцевий набір значень, який він може представляти, і всі вони матимуть помилки округлення з деякими входами. Типовий формат з плаваючою точкою з Mantissa та Exponent пропонує набагато більший діапазон, ніж це було б можливо за допомогою двох цілих чисел.
Містер Міндор

1
Я настійно рекомендую ознайомитися з деякими статтями, на які посилається у моїй відповіді на запитання Що викликає помилки округлення плаваючої точки? яку я щойно оновив деталями останньої статті згаданої серії. Зокрема, погляньте на те, чому фіксована точка не вилікує блюз плаваючої точки .
Марк Бут

Відповіді:


35

Насправді існують режими чисел, які роблять це.

Двозначна кодована десятична арифметика (BCD) має роботу комп'ютера в базі 10. Причина, з якою ви стикаєтеся з цим рідко, полягає в тому, що він витрачає простір: кожна окрема цифра числа займає мінімум чотири біти, тоді як комп'ютер може інакше зберігати до 16 значень у цьому просторі. (Це також може бути повільніше, але можливо мати прискорену апаратною формою BCD математику, яка працює чудово.) Насправді це саме те, що робить більшість калькуляторів, саме тому існують певні класи проблем округлення, з якими ви ніколи не потрапите на Casio $ 5, який з'їсть ваш обід на настільному комп’ютері.

Інший маршрут, який ви можете пройти, - це використовувати раціональні числа - тобто чисельник і знаменник, що зберігаються як цілі числа. Це фактично доступно майже на всіх мовах, є точним і дозволяє зберігати все у рідних бінарних форматах. Проблема полягає в тому, що, нарешті, користувачі, ймовірно, не хочуть бачити дробів, як 463/13, ані навіть 35 та 8/13. Вони хочуть побачити 35.615 ..., і як тільки ти потрапиш туди, ти стикаєшся з усіма типовими проблемами. Додайте, що цей формат займає ще більше місця і може бути значно повільнішим за арифметику з плаваючою комою, і ви не знайдете, що жоден комп'ютер не використовує цей формат за замовчуванням.

Отже: комп'ютери можуть робити все, що завгодно, але це повільно, і він витрачає простір, тому вони роблять це лише тоді, коли дійсно повинні. Решта часу, швидкість та економія місця плаваючої точки - це краща компромісна ситуація.


Ви не маєте на увазі чотири біти (не байти) в абзаці BCD?

3
Інший варіант - це арифметика з фіксованою точкою, де ціле число представляє десятковий дріб, якщо число - наприклад, Зберігання значень грошей (без розрахунків, що включають десяткові знаки або відсоток), де 1 становить 0,01 дол.
mattnz

1
@mattnz: Правда, фіксовані точки - це особливий випадок раціональності.
Джон Перді

Дивовижно, не знав, що калькулятори це роблять.
SomeKittens

3
Є третій варіант. Плаваюча точка з десятковою ознакою, як, наприклад, як decimalреалізується C # : stackoverflow.com/a/5019178/174335 Це не BCD, оскільки немає індивідуального представлення десяткових цифр, і це не фіксована точка.
Жорен

38

Існує численні способи зберігання дробових чисел, і кожен з них має свої переваги та недоліки.

Плаваюча точка - це, безумовно, найпопулярніший формат. Він працює, кодуючи знак, мантісу та підписаний показник бази-2 у цілі числа, і упаковуючи їх у купу біт. Наприклад, у вас може бути 32-розрядна мантіса 0.5(закодована як 0x88888888) та 32-розрядний підписаний експонент +3( 0x00000003), який би декодувався до 4.0(0.5 * 2 ^ 3). Числа з плаваючою комою швидкі, оскільки вони реалізовані апаратно, а їхні шкали точності з абсолютним розміром, тобто чим менше число, тим краща ваша абсолютна точність, тому відносна похибка округлення залишається постійною з абсолютним розміром. Поплавці відмінно підходять для значень, відібраних з безперервної області, таких як довжини, рівні звукового тиску, рівні освітленості тощо, і тому вони зазвичай використовуються для обробки звуку та зображень, а також для статистичного аналізу та фізичного моделювання. Їх найбільшим недоліком є ​​те, що вони не точні, тобто схильні до помилок округлення, і вони не можуть точно представити всі десяткові дроби. Усі основні мови програмування мають певну точку з плаваючою точкою.

Фіксована точкапрацює, використовуючи досить великі цілі числа та неявно резервуючи частину їхніх бітів для дробової частини. Наприклад, 24,8-бітове число з фіксованою точкою резервує 24 біти для цілої частини (включаючи знак) і 8 біт для дробової частини. Праворучне зміщення цього числа на 8 біт дає нам цілу частину. Номери з фіксованою точкою, які раніше були популярними, коли апаратні одиниці з плаваючою комою були рідкісними або принаймні набагато повільнішими, ніж їхні цілі аналоги. Хоча цифри з фіксованою точкою дещо простіше в обробці з точки зору точності (хоча б тому, що про них легше обґрунтувати), вони поступаються плаванню в майже будь-якому іншому відношенні - вони мають меншу точність, менший діапазон і тому, що додаткові операції, необхідні для виправлення розрахунків для неявного зсуву, математика з фіксованою точкою сьогодні часто повільніше, ніж математика з плаваючою комою.

Десяткові типи працюють так само, як числа з плаваючою чи фіксованою точкою, але вони припускають десяткову систему, тобто їхній показник (неявний або явний) кодує потужність 10, а не потужність-2. Десяткове число може, наприклад, кодувати мантісу 23456та показник -2, і це пошириться на234.56. Десяткові знаки, оскільки арифметика не є провідним в процесорі, повільніше, ніж плаваючі, але вони ідеальні для всього, що включає десяткові числа і потребує цих чисел, щоб бути точними, а округлення відбувається в чітко визначених місцях - фінансові розрахунки, табло тощо. У деяких мовах програмування вбудовані десятичні типи (наприклад, C #), для інших потрібні бібліотеки для їх реалізації. Зауважимо, що хоча десяткові знаки можуть точно представляти десяткові дроби, що не повторюються, їх точність не краща, ніж цифри з плаваючою комою; вибір десяткових знаків означає, що ви отримуєте точні подання чисел, які можна точно представити у десятковій системі (подібно до того, як поплавці можуть точно представляти двійкові дроби).

Раціональні числа зберігають чисельник і чисельник, як правило, використовуючи якийсь тип цілого чисел bignum (числовий тип, який може зростати настільки, наскільки дозволяють обмеження пам'яті комп'ютера). Це єдиний тип даних із групи, який може точно моделювати числа, як-от 1/3або 3/17, а також операції над ними - раціональні, на відміну від інших типів даних, дадуть правильні результати для таких речей, як3 * 1/3. Математика досить проста, хоча придумати ефективний алгоритм факторингу є досить складним завданням. У деяких мовах програмування вбудовані раціональні типи (наприклад, Common Lisp). Недоліки раціоналів включають те, що вони повільні (багато операцій вимагають зменшення дробів та розподілення їх компонентів), а також, що багато загальних операцій важко або неможливо здійснити, і більшість реалізацій знизить раціональний до плаваючого, коли це станеться (наприклад, коли ви телефонуєте sin()на раціональне).

BCD (Binary Coded Decimal) використовує "nibbles" (групи по 4 біти) для кодування окремих цифр; Оскільки nibble може містити 16 різних значень, але десяткових чисел вимагає лише 10, то на nibble існує 6 "незаконних" значень. Як і десяткові знаки, цифри BCD є десятковими, тобто обчислення, проведені на десяткових числах, виходять так само, як і у випадку, коли ви робили їх за допомогою ручки та паперу. Арифметичні правила для BCD дещо незграбні, але перелом полягає в тому, що перетворити їх у рядки простіше, ніж у деяких інших форматах, що особливо цікаво для середовищ з низьким рівнем ресурсів, таких як вбудовані системи.

Рядки , так, звичайні старі рядки, також можна використовувати для представлення дробових чисел. Технічно це дуже схоже на BCD, тільки що є явна десяткова крапка, і ви використовуєте один повний байт на десяткову цифру. Як такий, формат марнотратний (використовується лише 11 з 256 можливих значень), але його простіше проаналізувати та генерувати, ніж BCD. Крім того, оскільки всі використовувані значення "неподозрілі", нешкідливі та нейтральні для платформи номери, кодовані рядками, можуть без проблем пересуватись по мережах. Нечасто знайти арифметику, що робиться на рядках безпосередньо, але можливо, і коли ви це зробите, вони настільки ж точні, як і в інших десяткових форматах (десяткових знаків і BCD).


Напевно, 32-бітова фіксована точка має більшу точність, ніж 32-бітова плаваюча точка, оскільки представлення нерухомих точок не включають мантісу.
Хан

4
@han: Залежить від розміру номера, яке потрібно зберегти. Поплавці (приблизно) дадуть вам таку саму точність, незалежно від того, наскільки велика чи мала цифра, тоді як фіксована точка дасть вам повну точність лише в тому випадку, якщо число, яке ви хочете зберегти, ідеально вписується в її діапазон.
Лев

@han Не обов'язково, обидва досі можуть представляти 2 ^ 32 різних значення. Кількість перенесеної інформації однакова, незалежно від презентації. Дальність і точність йдуть рука об руку, тому в цьому відношенні арифметика з фіксованою точкою може бути точнішою в певних діапазонах. І уникає неприємних проблем випадкового округлення, якщо ви знаєте межі, в яких ви можете працювати.
zxcdw

@han: вони мають однакову точність (або майже). Різниця полягає в тому, що для чисел з фіксованою точкою точність (як у розмірі дискретного кроку від одного числа до його наступника) є постійною, як і з цілими числами, тоді як при плавцях вона зростає приблизно лінійно з абсолютним значенням - поплавок число 1.0 має більшу точність до нього, ніж число 10 000 000,0 (в мільйон разів більше, приблизно).
tdammers

6

Числа з плаваючою комою представляють широкий діапазон значень, що дуже корисно, коли ви не знаєте заздалегідь, якими можуть бути ці значення, але це компроміс. Представлення 1/10 ^ 100 з другим цілим числом не працює.

Деякі мови (і деякі бібліотеки) мають інші характеристики. Лісп традиційно має нескінченні цілі числа. Кобол має обчислення з десятковими числами з фіксованою точкою.

Потрібно вибрати представлення номера, яке відповідає проблемному домену.


1

Це здається, що ви описуєте числа з фіксованою точкою .

Майте на увазі, що зберігання дробової частини числа в окремому місці точно ідентично створенню єдиного простору вдвічі довше та збереженню всієї та дробової частини у двох окремих половинах. Іншими словами, це ідентично збереженню числа як ціле число, але просто припускає фіксовану кількість десяткових пробілів.

Зазвичай номери з плаваючою комою зберігаються, використовуючи двійкову варіацію наукової нотації, тому що, як правило, важливі цифри. Однак існує багато інших методів. Десяткові числа з фіксованою точкою зазвичай використовуються, наприклад, для зберігання значень валюти, де точність є критичною до певного цілого числа десяткових знаків, але кількість необхідних десяткових цифр ніколи не змінюється.


1

Це називалося б BCD, я думаю, ви все ще можете використовувати його, якщо дуже хочете. Однак насправді цього не варто:

  1. Ви дуже рідко натрапите на помилку округлення з 64-бітовою плаваючою точкою
  2. Це робить арифматичний складним і неефективним
  3. Він витрачає 6 значень кожні 4 біти

Математика BCD багато використовувалася в ранніх 8-бітових мікропроцесорних системах; Дійсно, на одному популярному мікропроцесорі (6502) додавання і віднімання з BCD так само швидко, як і у двійковому. У відеоіграх часто використовується математика BCD для ведення рахунків. Немає спеціальної обробки для підбиття балів у 1 000 000 балів. Натомість додавання 1 до "99 99 99" дає "00 00 00" з перенесенням, яке ігнорується. Додаткові накладні витрати на додавання балів у BCD невеликі порівняно з витратами на перетворення двійкового значення у формат, що відображається.
supercat

1

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

Це, як правило, підтримується в апаратному забезпеченні значною мірою тому, що наукові розрахунки, як правило, ті, що отримали найбільше користь від апаратної підтримки. Наприклад, фінансові розрахунки часто проводяться в інших форматах, але фінансове програмне забезпечення зазвичай робить недостатньо реальний розрахунок, що, хоча необхідні формати підтримуються лише в програмному забезпеченні, продуктивність залишається цілком достатньою для більшості фінансових програм.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.