Чому десяткові числа не можуть бути представлені точно у двійковій формі?


284

До СО було поставлено кілька питань щодо представлення з плаваючою комою. Наприклад, десяткове число 0,1 не має точного двійкового зображення, тому для порівняння з іншим числом з плаваючою комою небезпечно використовувати оператор ==. Я розумію принципи, що стоять за поданням з плаваючою комою.

Що я не розумію, це те, чому з математичної точки зору цифри праворуч від десяткової крапки є більш «спеціальними», ніж ті, що ліворуч?

Наприклад, число 61.0 має точне двійкове подання, оскільки інтегральна частина будь-якого числа завжди є точною. Але число 6,10 не є точним. Все, що я зробив, - це перемістити десятковий на одне місце, і раптом я пішов з Екзактопії до Інекзактвіля. Математично не повинно бути суттєвої різниці між двома числами - вони просто числа.

Навпаки, якщо я переміщу десятковий на одне місце в інший бік, щоб отримати число 610, я все ще перебуваю в Екзактопії. Я можу продовжувати йти в цьому напрямку (6100, 610000000, 610000000000000), і вони все ще точні, точні, точні. Але як тільки десятковий перетинає якийсь поріг, числа вже не є точними.

Що відбувається?

Редагувати: щоб уточнити, я хочу осторонь дискусій щодо стандартних представлень, таких як IEEE, і дотримуватися того, що, на мою думку, є математично "чистим" способом. У базі 10 позиційні значення:

... 1000  100   10    1   1/10  1/100 ...

У двійковій формі вони будуть:

... 8    4    2    1    1/2  1/4  1/8 ...

Також на цих числах немає довільних обмежень. Позиції збільшуються нескінченно ліворуч та праворуч.


2
Це може бути вам корисним, щоб зрозуміти, що саме відбувається всередині числа плаваючої точки: Анатомія числа плаваючої точки .
Джон Д. Кук

57
У двійковій формі число 3 представлено у вигляді 2¹ + 2 ° = 2 + 1. Приємно і легко. Тепер погляньте на 1/3. Як би ви це представляли, використовуючи негативні сили 2? Експериментуйте трохи, і ви побачите, що 1/3 дорівнює сумі нескінченної послідовності 2 ^ -2 + 2 ^ -4 + 2 ^ -6 + 2 ^ -8 + ..., тобто. не так просто представити точне у двійковому.
Lars Haugseth

21
Джон Скіт дуже добре відповідає на питання у вашому тілі. Одне, чого не вистачає, це те, що ви насправді задаєте два різні питання. Заголовок питання "чому десяткові числа не можуть бути представлені точно у двійкових?" Відповідь - вони можуть бути. Між своїм заголовком і тілом ви пов'язуєте ідею "двійкового" та ідеї "подання з плаваючою точкою". Плаваюча точка - це спосіб вираження десяткових чисел у фіксованій кількості двійкових цифр ціною точності. Двійковий код - це лише інша база для підрахунку і може виражати будь-яке число десяткової банки, враховуючи нескінченну кількість цифр.
Кріс Блеквелл

3
Існує декілька систем, які мають точне десяткове подання. Це працює майже так, як ви описуєте. Деклараційний тип SQL - один із прикладів. Вбудовані мови LISP. Існує декілька комерційних бібліотек з відкритими джерелами для використання точних десяткових обчислень. Просто для цього немає апаратної підтримки, і лише більшість мов та апаратних засобів там реалізує стандарти IEEE для представлення нескінченної кількості чисел у 32 або 64 бітах.
нос

1
Це питання видається поза темою, оскільки мова йде про математику (навіть якщо це математика, пов’язана з програмуванням), і буде краще з математики
Коул Джонсон

Відповіді:


360

Десяткові числа можуть бути представлені точно, якщо у вас є достатньо місця - просто не шляхом плаваючих двійкових чисел. Якщо ви використовуєте плаваючий тип десятковою комою (наприклад, System.Decimalу .NET), то може бути точно представлено безліч значень, які неможливо точно представити у двійковій плаваючій точці.

Давайте подивимось на це іншим способом - у базі 10, з якою ви, ймовірно, вам буде комфортно, ви не можете точно виразити 1/3. Це 0,3333333 ... (повторюється). Причина, по якій ви не можете представити 0,1 як двійкове число з плаваючою точкою, саме з тієї ж причини. Ви можете представляти 3, і 9, і 27 точно - але не 1/3, 1/9 або 1/27.

Проблема полягає в тому, що 3 - це просте число, яке не є коефіцієнтом 10. Це не проблема, коли ви хочете помножити число на 3: ви завжди можете помножити на ціле число, не стикаючись з проблемами. Але коли ви поділите на число, яке є простим і не є фактором вашої бази, ви можете зіткнутися з проблемою (і буде робити це , якщо ви намагаєтеся розділити 1 на це число).

Хоча 0,1 зазвичай використовується як найпростіший приклад точного десяткового числа, яке неможливо точно представити у двійковій плаваючій точці, імовірно, 0,2 є більш простим прикладом, оскільки це 1/5 - і 5 є простим, що викликає проблеми між десятковим і двійковим .


Бічна примітка для вирішення проблеми кінцевих уявлень:

Деякі типи плаваючої десяткової крапки мають фіксований розмір, як System.Decimalінші, наприклад java.math.BigDecimal, "довільно великі", але вони досягатимуть межі в якийсь момент, будь то системна пам'ять або теоретичний максимальний розмір масиву. Це, однак, цілком окремий пункт головного з цієї відповіді. Навіть якщо у вас було справді довільно велика кількість бітів, з якими ви могли грати, ви все одно не могли представити десятковий 0,1 точно в поданні з плаваючою двійковою точкою. Порівняйте це з навпаки: задавши довільну кількість десяткових цифр, ви можете точно зобразити будь-яке число, яке точно представлено у вигляді плаваючої двійкової точки.


8
Це проклятий прекрасний приклад, сер!
Том Ріттер

5
... хотілося б, щоб я міг підтвердити це двічі. Мене про це повністю запитували занадто багато разів. Це майже як люди не можуть думати за межами бази 10. Хе-хе
Джастін Нісснер

38
Так, у світі є 10 видів людей - тих, хто розуміє бінарне та тих, хто цього не робить.
duffymo

83
@JonSkeet: Ctrl + Alt + Delete виглядатиме незручно лише двома пальцями.
Lars Haugseth

20
@muusbolla: Ні. Числа, представлені десятковим поданням 1та десятковим поданням 0.9...(нескінченно повторюються 9s після десяткової крапки), рівні. Мабуть, найпростіший спосіб це побачити наступний: Нехай x = 0.9.... Зауважте, що 10x = 9.9..... Тому 9x = 10x - x = 9.9... - 0.9... = 9так, що 9x = 9і x = 1. Є й інші способи бачити це, але я вважаю, що це найпростіший.
Jason

25

Наприклад, число 61.0 має точне двійкове подання, оскільки інтегральна частина будь-якого числа завжди є точною. Але число 6,10 не є точним. Все, що я зробив, - це перемістити десятковий на одне місце, і раптом я пішов з Екзактопії до Інекзактвіля. Математично не повинно бути суттєвої різниці між двома числами - вони просто числа .

Давайте на мить відійдемо від деталей основ 10 і 2. Давайте запитаємо - в основі b, які числа мають закінчувані подання, а які - ні? Миттєвий роздум говорить нам про те, що число xмає закінчення b-презентація, якщо і лише тоді, коли існує ціле число, nтаке x b^nціле число.

Так, наприклад, x = 11/500має закінчується 10-представлення, тому що ми можемо вибрати n = 3і потім x b^n = 22ціле число. Однак x = 1/3ні, бо як би там не булоn ми оберемо, ми не зможемо позбутися 3-х.

Цей другий приклад спонукає нас думати про фактори, і ми можемо це бачити для будь-яких раціонального x = p/q (який вважається найнижчим) ми можемо відповісти на питання, порівнюючи прості факторизації bта q. Якщо qякісь основні фактори не є в основній факторизації b, ми ніколи не зможемо знайти відповідногоn для позбавлення від цих факторів.

Таким чином, для бази 10 будь- p/q деq є інші , ніж 2 або 5 не матиме уявлення узгоджувального прості множники.

Отже, повертаючись до основ 10 і 2, ми бачимо, що будь-яке раціональне із закінчуючим поданням 10 буде мати вигляд p/q саме тоді, коли в основній факторизації qє лише 2s і 5s; і те саме число буде мати закінчувальне 2-представлення саме тоді, коли воно qмає лише 2s у своїй основній факторизації.

Але один із цих випадків є підмножиною іншого! Щоразу

qмає лише 2s у своїй основній факторизації

це, очевидно, є також вірно , що

q є лише 2 s і 5s у своїй основній факторизації

або, кажучи іншим чином, коли p/qмає кінцеве 2-представлення, p/qмає закінчувальне 10-представлення . Однак зворотне не має місце - коли qмає 5 основний чинник, воно матиме завершальне 10-представлення, але не закінчує 2-представлення. Це0.1 приклад, згаданий іншими відповідями.

Отже, ми маємо відповідь на ваше запитання - оскільки прості множники 2 є підмножиною простих факторів 10, всі 2-кінцеві числа - це 10-кінцеві числа, але не навпаки.Це не про 61 проти 6,1 - це приблизно 10 проти 2.

У заключній ноті, якщо воля людей використовували (скажу) підставами 17 , але наші комп'ютери , які використовуються базою 5, ваша інтуїція ніколи б не була відведена цим - не було б жодного (Не нуль, нецілого) чисел, припинених в обох випадках!


Тоді чому "попередження (0,15 * 0,15)" відображає "0,0225"?
Майкл Гейзер

5
@MichaelGeiser коротка відповідь: округлення у точці відображення. Те, що ви думаєте, 0.15є насправді (коли він зберігається як подвійний IEEE) `0.149999999999999994448884876874`. Дивіться jsfiddle .
AakashM

Добре зрозуміло на прикладі точкового коду! Я б хотів, щоб я міг дати вам голос за це! Мені належить грати з кількома функціями, щоб дослідити, де відбувається зріз. Я все ще просто вражений, що нам справді доводиться мати справу з цим сміттям; оскільки люди працюють в базі десяти майже 100% часу, і ми використовуємо не цілі числа стільки часу, що ви можете подумати, що реалізація математики з плаваючою комою за замовчуванням впорається з цією нісенітницею.
Майкл Гейзер

1
@MichaelGeiser схеми для роботи з базою 2 менші, швидші та енергоефективніші, ніж ті, що працюють з базою 10. Сьогодні ми могли б виправдати накладні витрати, але в 1970-х, коли встановлювали стандарти, це було велика справа. Намагаючись зробити це без прямої підтримки процесорних схем ще гірше, очікуйте накази різниці в швидкості.
Марк Рансом

Ця відповідь пояснює краще, ніж сам Джон Скіт!
goelakash

16

Основна (математична) причина полягає в тому, що коли ви маєте справу з цілими числами, вони незмінно нескінченні .

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

Однак реальні числа незліченно нескінченні . Ви не можете сказати "дайте мені справжнє число в положенні 610000000000000" і отримаєте відповідь. Причина полягає в тому, що, навіть коли 0і між ними 1, існує нескінченна кількість значень, коли ви розглядаєте значення з плаваючою комою. Те ж саме справедливо для будь-яких двох чисел з плаваючою точкою.

Більше інформації:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

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


6
На насправді, раціональні числа є рахунковими. Але не кожне дійсне число - це раціональне число. Я, безумовно, можу створити послідовність точних десяткових чисел, яка досягне будь-якого точного десяткового числа, яке ви хочете дати мені в підсумку. Це якщо вам потрібно мати справу з ірраціональними числами, і ви потрапляєте в незліченно безмежні множини.
Джон Скіт

Щоправда, я повинен говорити "справжній", а не "плаваюча точка". Буде уточнювати.
ТМ.

1
У цей момент логіка стає менш застосовною, ІМО - адже ми не тільки не можемо мати справу з усіма дійсними числами, використовуючи двійкову плаваючу крапку, але навіть не можемо мати справу з усіма раціональними числами (наприклад, 0,1). Іншими словами, я не думаю, що це взагалі пов'язане з підрахунком :)
Джон Скіт

@jonskeet Я знаю, що незгода з Джоном Скітом порушить фундаментальний закон природи, тому, звичайно, я цього не зроблю :) Однак я вважаю, що добре вважати внутрішнє представлення чисел як індексів набір значень, які ви хочете представити зовні. За допомогою цього напряму мислення ви можете бачити, що незалежно від того, наскільки великий ваш список індексів (навіть якби ви сказали, нескінченні шматочки точності), ви все одно не зможете представити всі реальні числа.
ТМ.

3
@TM: Але ОП не намагається представити всі реальні числа. Він намагається представити всі точні десяткові числа, що є підмножиною раціональних чисел, а тому лише незліченно безмежні. Якби він використовував нескінченний набір бітів як тип десяткової плаваючої крапки, тоді він би був добре. Це використання цих бітів як двійкового типу з плаваючою комою, що спричиняє проблеми з десятковими числами.
Джон Скіт

10

Повторюю те, що я сказав у своєму коментарі до містера Скіта: ми можемо представляти 1/3, 1/9, 1/27 або будь-яке раціональне в десятковій нотації. Ми робимо це, додаючи додатковий символ. Наприклад, рядок над цифрами, які повторюються в десятковому розширенні числа. Те, що нам потрібно представити десятковими числами як послідовність двійкових чисел, є 1) послідовність двійкових чисел, 2) точка радіації та 3) якийсь інший символ для позначення повторюваної частини послідовності.

Цитата цитування Генера - це спосіб зробити це. Він використовує символ цитати для зображення повторюваної частини послідовності. Стаття: http://www.cs.toronto.edu/~hehner/ratno.pdf та запис у Вікіпедії: http://en.wikipedia.org/wiki/Quote_notation .

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


Ця система позначень працює, якщо ми знаємо, де починається і закінчується цикл. Люди досить добре виявляють цикли. Але, загалом, комп’ютери - це не так. Щоб використовувати можливість ефективно використовувати символ повторення, комп’ютер повинен був би мати можливість з'ясувати, де знаходяться цикли після проведення обчислення. Наприклад, для числа 1/3, цикл починається відразу. Але для числа 1/97 цикл не показує себе, поки ви не відпрацювали відповідь принаймні на 96 цифр. (Насправді вам знадобиться 96 * 2 + 1 = 193 цифри, щоб бути впевненим.)
Баррі Браун,

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

3
Також питання полягало в тому, щоб точно представити числа. Іноді точне подання означає багато бітів. Краса позначень цитат полягає в тому, що Генер демонструє, що в середньому економія розміру представлення становить 31% порівняно зі стандартним 32-бітним поданням фіксованої довжини.
ntownsend

6

BCD - Двійкові десятичні коди - уявлення точні. Вони не дуже просторі, але це компроміс, який ви повинні зробити для точності в цьому випадку.


1
BCD не більш-менш точні, ніж будь-яка інша база. Приклад: як ви представляєте 1/3 саме в BCD? Ви не можете.
Йорг W Міттаг

12
BCD - це точне подання DECIMAL, таким чином, гм, "десяткової" частини його назви. Не існує точного десяткового подання 1/3.
Алан

4

Це та сама причина, що ви не можете представити 1/3 точно в базі 10, вам потрібно сказати 0,33333 (3). У двійковій системі це однотипні проблеми, але виникають просто для різних наборів чисел.


4

(Примітка. Я додаю "b", щоб вказати двійкові числа тут. Усі інші числа вказані у десятковій кількості)

Один із способів думати про речі - це через щось подібне до наукових позначень. Ми звикли бачити числа, виражені в наукових позначеннях, наприклад, 6.022141 * 10 ^ 23. Числа з плаваючою комою зберігаються всередині, використовуючи аналогічний формат - мантісу та експонент, але використовуючи потужність двох замість десяти.

Ваш 61.0 може бути переписаний як 1.90625 * 2 ^ 5, або 1.11101b * 2 ^ 101b з мантіссою та експонентами. Щоб помножити це на десять і (перемістити десяткову точку), ми можемо зробити:

(1.90625 * 2 ^ 5) * (1.25 * 2 ^ 3) = (2.3828125 * 2 ^ 8) = (1.19140625 * 2 ^ 9)

або в мантії та експонентах у двійковій формі:

(1.11101b * 2 ^ 101b) * (1.01b * 2 ^ 11b) = (10.0110001b * 2 ^ 1000b) = (1.00110001b * 2 ^ 1001b)

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

А тепер подумайте, як ми ділимо 61 на 10. Почнемо з ділення мантіс, 1.90625 та 1.25. У десятковій формі це дає 1,525, хороше коротке число. Але що це, якщо ми перетворимо його на бінарне? Ми зробимо це звичайним способом - віднімаємо найбільшу потужність двох, коли це можливо, як і перетворюємо цілі числа десяткових знаків у двійкові, але ми будемо використовувати негативні сили двох:

1,525 - 1 * 2 ^ 0 -> 1
0,525 - 1 * 2 ^ -1 -> 1
0,025 - 0 * 2 ^ -2 -> 0
0,025 - 0 * 2 ^ -3 -> 0
0,025 - 0 * 2 ^ -4 -> 0
0,025 - 0 * 2 ^ -5 -> 0
0,025 - 1 * 2 ^ -6 -> 1
0,009375 - 1 * 2 ^ -7 -> 1
0,0015625 - 0 * 2 ^ -8 -> 0
0,0015625 - 0 * 2 ^ -9 -> 0
0,0015625 - 1 * 2 ^ -10 -> 1
0.0005859375 - 1 * 2 ^ -11 -> 1
0,00009765625 ...

Ой-ой. Тепер ми в біді. Виявляється, що 1.90625 / 1.25 = 1.525 є повторюваною дробою, вираженою у двійковій формі: 1.11101b / 1.01b = 1.10000110011 ... b Наші машини мають стільки бітів, щоб утримувати цю мантісу, і тому вони просто округлить дріб і припустимо нулі понад певну точку. Помилка, яку ви бачите при поділі 61 на 10, є різницею між:

1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
і, скажімо:
1.100001100110011001100110b * 2 ^ 10b

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

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


4

Це гарне запитання.

Все ваше запитання засноване на "як ми представляємо число?"

ВСІ номери можуть бути представлені десятковою подачею або двійковим (доповнення 2). Усі !!

Але деякі (більшість з них) потребують нескінченної кількості елементів ("0" або "1" для двійкової позиції, або "0", "1" до "9" для десяткового подання).

Як і 1/3 у десятковому поданні (1/3 = 0,3333333 ... <- з нескінченним числом "3")

Як і 0,1 у двійковій (0,1 = 0,00011001100110011 .... <- з нескінченним числом "0011")

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

І, як сказав Джон, 3 є простим числом, яке не є коефіцієнтом 10, тому 1/3 не може бути представлено кінцевою кількістю елементів у базі 10.

Навіть при арифметиці з довільною точністю система позиціонування нумерації в базі 2 не в змозі повністю описати 6.1, хоча вона може представляти 61.

Для 6.1 ми повинні використовувати інше подання (наприклад, десяткове подання або IEEE 854, яке дозволяє базі 2 або 10 для подання значень з плаваючою комою)


Ви можете представляти 1/3 як саму дріб. Вам не потрібна нескінченна кількість біт, щоб представити його. Ви просто представляєте його як дріб 1/3, замість того, щоб взяти 1 і розділити його на 3. Кілька систем працює таким чином. Тоді вам знадобиться спосіб використання стандартних / * + - і подібних операторів для роботи над представленням дробів, але це досить просто - ви можете робити ці операції ручкою та папером, навчивши комп'ютер робити це не велика справа .
нос

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

3

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


3

Я здивований, поки ніхто цього не заявив: використовуйте тривалі дроби . Будь-яке раціональне число може бути представлене кінцевим чином у двійковій формі.

Деякі приклади:

1/3 (0,3333 ...)

0; 3

5/9 (0,5555 ...)

0; 1, 1, 4

10/43 (0,232558139534883720930 ...)

0; 4, 3, 3

9093/18478 (0.49209871198181621387596060179673 ...)

0; 2, 31, 7, 8, 5

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

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

Пі-тривала фракція:

3; 7, 15, 1, 292 ...

Закінчуючи послідовність на 1, це дає дріб:

355/113

що є відмінним раціональним наближенням.


Але як би ви це представляли у бінарному? Наприклад, 15 потрібно представити 4 біти, але 292 потрібно 9. Як апаратне забезпечення (або навіть програмне забезпечення) знає, де бітні межі між ними? Це компроміс ефективності та точності.
гарячий

2

У рівнянні

2^x = y ;  
x = log(y) / log(2)

Отже, мені було просто цікаво, чи може ми мати логарифмічну базову систему для бінарних,

 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........

Це могло б вирішити проблему, тож якби ви хотіли написати щось на кшталт 32.41 у двійковій формі, це було б

2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))

Або

2^5 + 2^(log(0.41) / log(2))

1

Проблема полягає в тому, що ви насправді не знаєте, чи дійсно це число - 61,0. Врахуйте це:


float a = 60;
float b = 0.1;
float c = a + b * 10;

Яке значення c? Це не точно 61, тому що b насправді не є .1, оскільки .1 не має точного бінарного подання.


1

Існує поріг, оскільки значення цифри перейшло від цілого до нецілого числа. Щоб представити 61, у вас є 6 * 10 ^ 1 + 1 * 10 ^ 0; 10 ^ 1 і 10 ^ 0 - це обидва цілих числа. 6.1 - 6 * 10 ^ 0 + 1 * 10 ^ -1, але 10 ^ -1 - 1/10, що, безумовно, не є цілим числом. Ось так ти опинишся в Інексактвілі.


1

Паралель може бути зроблена з дробів і цілих чисел. Деякі дроби, наприклад, 1/7, не можуть бути представлені у десятковій формі без лотів і партій десяткових знаків. Оскільки плаваюча точка є двійковою, то особливі випадки змінюються, але існують однакові проблеми з точністю.


0

Існує нескінченна кількість раціональних чисел і кінцева кількість біт, з якими їх можна представляти. Дивіться http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems .


Але навіть з нескінченною кількістю біт, якби ви використовували плаваючу двійкову точку, ви все одно не зможете представити 0,1 точно, як і ви не можете представляти 1/3 точно в десятковій частині навіть з нескінченною кількістю біт.
Джон Скіт

3
@ Джон Це НЕ відповідає дійсності: з нескінченним числом знаків після коми, я можу , наприклад , висловити «одна третина» точно . Проблема в реальному світі полягає в тому, що фізично неможливо мати "нескінченну кількість" десяткових знаків або біт.
ChrisW

0

Число 61.0 дійсно має точну операцію з плаваючою комою, але це не вірно для всіх цілих чисел. Якщо ви написали цикл, який додав його до числа плаваючої крапки з подвійною точністю та до 64-бітного цілого числа, врешті-решт ви досягнете точки, коли 64-бітове ціле число ідеально представляє число, але плаваюча точка не… тому що недостатньо значущих бітів.

Просто набагато простіше досягти точки наближення в правій частині десяткової крапки. Якщо ви почали виписувати всі числа у двійковій плаваючій точці, це матиме більше сенсу.

Інший спосіб думати про це полягає в тому, що коли ви зазначаєте, що 61.0 є ідеально представним у базі 10, а зміщення десяткової крапки навколо цього не змінюється, ви виконуєте множення на потужність десять (10 ^ 1, 10 ^ -1 ). У плаваючій крапці множення на дві сили не впливає на точність числа. Спробуйте взяти 61.0 і розділити його на три рази для ілюстрації того, як ідеально точне число може втратити своє точне зображення.


0

ви знаєте цілі числа чи не так? кожен біт представляє 2 ^ n


2 ^ 4 = 16
2 ^ 3 = 8
2 ^ 2 = 4
2 ^ 1 = 2
2 ^ 0 = 1

ну це те ж саме для плаваючої точки (з деякими відмінностями), але біти представляють 2 ^ -n 2 ^ -1 = 1/2 = 0,5
2 ^ -2 = 1 / (2 * 2) = 0,25
2 ^ -3 = 0,125
2 ^ -4 = 0,0625

Двійкове представлення з плаваючою комою:

знак Експонент дробу (я думаю, невидимий 1 додається до дроби)
B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0


0

Висока оцінка відповіді вище прибила його.

Спочатку ви змішували базу 2 та основу 10 у своєму питанні, потім, коли ви поставили число з правого боку, яке не ділиться на базу, у вас виникають проблеми. Як і 1/3 у десятковій формі, оскільки 3 не переходять у потужність 10 або 1/5 у двійковій, що не переходить у потужність 2.

Ще один коментар, хоча НІКОЛИ не використовуйте рівний чисел з плаваючою комою, період. Навіть якщо це точне подання, в деяких системах з плаваючою точкою є деякі цифри, які можна точно представити більш ніж одним способом (IEEE погано з цього приводу, для цього слід жахливо специфіку з плаваючою точкою, тому очікуйте головних болів). Нічим не відрізняється тут 1/3 - це НЕ РІВНЕ числом на вашому калькуляторі 0,3333333, скільки б не було праворуч від десяткової коми. Він є або може бути досить близьким, але не є рівним. тож можна очікувати, що 2 * 1/3 не дорівнює 2/3 залежно від округлення. Ніколи не використовуйте рівну з плаваючою точкою.


0

Як ми вже обговорювали, в арифметиці з плаваючою комою десятковий 0,1 не може бути ідеально представлений у двійковій формі.

Представлення з плаваючою точкою і цілими числами представляють сітки або решітки для представлених чисел. Коли арифметика виконується, результати випадають з сітки і їх потрібно повернути на сітку шляхом округлення. Приклад - 1/10 на двійковій сітці.

Якщо ми використовуємо двійкове кодоване десяткове представлення, як запропонував один джентльмен, чи зможемо ми зберегти числа в сітці?


1
Десяткові числа, звичайно. Але це лише за визначенням. Ви не можете представляти 1/3 у десятковій формі, не більше ніж 0,1 у двійковій формі. Будь-яка схема квантування не вдається для нескінченно великого набору чисел.
Килотан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.