Що викликає помилки округлення плаваючої точки?


62

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

Однак я не знаю, які причини цієї неточності. Чому існує так багато проблем із округленням з плаваючими числами?


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

12
Моя спроба вияснити найпоширеніші плутанини: floating-point-gui.de
Майкл Боргвардт

Я думаю, що означає @DanielPryden: "Перехід на представлення [фіксованої точки] може змусити округлення вести себе більш інтуїтивно ..." . те, що спричиняє проблеми із округленням, будь то фіксовані чи цифри з плаваючою комою, є кінцевою шириною слова будь-якого. просто з плаваючою точкою величина помилки округлення зазвичай залишається приблизно пропорційною величині числа, що округляється. (за винятком випадків, коли ви дійсно малі та "денормалізовані" числа.)
Роберт Брістоу-Джонсон

@robert: Це не зовсім те, про що я мав на увазі. "Помилка", з якою стикається більшість людей з плаваючою точкою, не має нічого спільного з плаваючою точкою сама по собі, це основа. IEEE-754 поплавці та подвійні використовують показник у базі 2, а це означає, що дробові числа округляються до негативних потужностей двох (1/2, 1/16, 1/1024 тощо), а не від'ємних потужностей 10 (1 / 10, 1/1000 тощо) Це призводить до неінтуїтивних результатів, таких як округлення 0,1 до 0,1000001 та подібні проблеми.
Даніель Приден

Ви можете робити номери з плаваючою комою в базі 10 - саме так decimalпрацює тип .NET . Фіксована точка, з іншого боку, різна. Поки ваш діапазон обмежений, фіксована точка - це чудова відповідь. Але обмежувальний діапазон робить фіксовану точку непридатною для багатьох математичних застосувань, а реалізація номерів з фіксованою точкою часто недостатньо оптимізована в апаратному забезпеченні.
Даніель Приден

Відповіді:


82

Це пояснюється тим, що деяким дробам потрібно виразити дуже велику (або навіть нескінченну) кількість місць, щоб виразити без округлення. Це справедливо для десяткових позначень настільки ж, як і для двійкових чи будь-яких інших. Якщо ви обмежите кількість десяткових знаків, які слід використовувати для своїх обчислень (і уникати обчислень у дробових позначеннях), вам доведеться округлити навіть простий вираз як 1/3 + 1/3. Замість того, щоб записати 2/3, у результаті вам доведеться написати 0,33333 + 0,33333 = 0,66666, що не ідентично 2/3.

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

Що повинен знати кожен вчений-комп’ютер про арифметику з плаваючою комою


12
Пляма на. Але я також зазначу, що деякі числа, які закінчуються в десятковій формі, не закінчуються двійковими. Зокрема, 0,1 є повторюваним числом у двійковій формі, тому жодне двійкове число з плаваючою комою не може точно представляти 0,1.
Джек Едлі

4
Плаваючі точки не просто корисні для багатьох десяткових знаків. 32-бітні цілі числа можуть нараховувати лише до 4 мільярдів, але 32-бітний поплавок може бути майже нескінченно великим.
Абхі Беккерт

7
Зокрема, дроби, які ми можемо виразити як кінцеві десяткові знаки, - це ті, чий основний множник знаменників містить лише 2 та 5 (наприклад, ми можемо виразити 3/10 та 7/25, але не 11/18). Коли ми переходимо до двійкового, ми втрачаємо коефіцієнт 5, так що тільки діадіальні раціонали (наприклад, 1/4, 3/128) можуть бути виражені точно.
Девід Чжан

70

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

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

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


На додаток до Девіда Голдберга , що має знати кожен комп'ютерний арифметичний з арифметикою з плаваючою комою (перепублікована Sun / Oracle як додаток до їх посібника з чисельних обчислень ), про який згадував thorsten , журнал ACCU Overload виявився чудовим серія статей Річарда Гарріса про блюз плаваючої точки .

Серія розпочалася з

Числові обчислення мають багато підводних каменів. Річард Харріс починає шукати срібну кулю.

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

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

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

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

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

Якщо ви хочете дізнатися більше, він продовжує

Потім він переходить до спроби допомогти вам вилікувати блюз Calculus

і останнє, але не менш важливе, є

Цілу серію статей заслуговує уваги, і загалом на 66 сторінках вони все ж менші, ніж на 77 сторінках паперу Голдберга .

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


Як таким чином говорив ак, згаданий у коментарях:

Як автор цих статей, я хотів би зазначити, що я створив інтерактивні версії їх у своєму блозі www.thusspakeak.com, починаючи з daklespakeak.com/ak/2013/06 .


1
Як автор цих статей, я хотів би зазначити, що я створив інтерактивні версії їх у своєму блозі www.thusspakeak.com, починаючи з daklespakeak.com/ak/2013/06 .
таким чином говорив ак

Дякую @ такимspakea.k. Я додав замітку до своєї відповіді, і ці інтерактивні елементи дуже добре працюють.
Марк Бут

12

Ну, у Thorsten є остаточне посилання . Я додам:

Будь-яка форма подання буде мати деяку помилку округлення для деякого числа. Спробуйте виразити 1/3 у плаваючій точці IEEE або у десятковій формі. Ні це не може зробити це точно. Це виходить за рамки відповіді на ваше запитання, але я успішно використав це правило:

  • Зберігайте введені користувачем значення у десятковій частині (оскільки вони майже напевно ввели їх у десятковому поданні - дуже мало користувачів використовуватимуть двійкові чи шістнадцяткові). Таким чином, у вас завжди є точне представлення користувача.
  • Якщо вам потрібно зберегти введені користувачем дроби, збережіть чисельник та знаменник (також у десятковій кількості)
  • Якщо у вас є система з декількома одиницями вимірювання для однієї кількості (наприклад, Цельсій / Фаренгейт), і користувач може вводити і те, і інше, зберігати введене їм значення та одиниці, в які вони ввели. Не намагайтеся перетворити і зберегти як єдине представлення, якщо ви не зможете це зробити без втрати точності / точності. Використовуйте збережене значення та одиниці у всіх розрахунках.
  • Зберігайте створені машиною значення в плаваючій точці IEEE (це можуть бути числа, згенеровані електронним вимірювальним приладом, як аналоговий датчик з A / D перетворювачем, або необгрунтований результат обчислення). Зауважте, що це не застосовується, якщо ви читаєте датчик через послідовне з'єднання, і воно вже дає значення у десятковому форматі (наприклад, 18,2 С).
  • Зберігайте підсумки, які бачать користувач, тощо у десятковій формі (як баланс банківського рахунку). Округлюйте відповідним чином, але використовуйте це значення як остаточне значення для всіх майбутніх розрахунків.

Я додам: Подумайте про використання математичного пакету довільної точності на зразок ARPREC або decNumber.
Blrfl

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

10

Те, що, здається, досі не згадувалося, - це концепції нестабільного алгоритму та необґрунтована проблема . Я звернуся до першого, оскільки це, здається, є частішим підводним каменем для початківців чисельників.

Розглянемо обчислення потужностей (зворотного) золотого відношення φ=0.61803…; один із можливих способів зробити це - використовувати формулу рекурсії φ^n=φ^(n-2)-φ^(n-1), починаючи з φ^0=1і φ^1=φ. Якщо запустити цю рекурсію в улюбленому обчислювальному середовищі та порівняти результати з точно оціненими потужностями, ви побачите повільну ерозію значущих цифр. Ось що відбувається, наприклад, у Mathematica :

ph = N[1/GoldenRatio];  
Nest[Append[#1, #1[[-2]] - #1[[-1]]] & , {1, ph}, 50] - ph^Range[0, 51]  
{0., 0., 1.1102230246251565*^-16, -5.551115123125783*^-17, 2.220446049250313*^-16, 
-2.3592239273284576*^-16, 4.85722573273506*^-16, -7.147060721024445*^-16, 
1.2073675392798577*^-15, -1.916869440954372*^-15, 3.1259717037102064*^-15, 
-5.0411064211886014*^-15, 8.16837916750579*^-15, -1.3209051907825398*^-14, 
2.1377864756200182*^-14, -3.458669982359108*^-14, 5.596472721011714*^-14, 
-9.055131861349097*^-14, 1.465160458236081*^-13, -2.370673237795176*^-13, 
3.835834102607072*^-13, -6.206507137114341*^-13, 1.004234127360273*^-12, 
-1.6248848342954435*^-12, 2.6291189633497825*^-12, -4.254003796798193*^-12, 
6.883122762265558*^-12, -1.1137126558640235*^-11, 1.8020249321541067*^-11, 
-2.9157375879969544*^-11, 4.717762520172237*^-11, -7.633500108148015*^-11, 
1.23512626283229*^-10, -1.9984762736468268*^-10, 3.233602536479646*^-10, 
-5.232078810126407*^-10, 8.465681346606119*^-10, -1.3697760156732426*^-9, 
2.216344150333856*^-9, -3.5861201660070964*^-9, 5.802464316340953*^-9, 
-9.388584482348049*^-9, 1.5191048798689004*^-8, -2.457963328103705*^-8, 
3.9770682079726053*^-8, -6.43503153607631*^-8, 1.0412099744048916*^-7, 
-1.6847131280125227*^-7, 2.725923102417414*^-7, -4.4106362304299367*^-7, 
7.136559332847351*^-7, -1.1547195563277288*^-6}

Стверджуваний результат для φ^41має неправильний знак, і навіть раніше обчислені та фактичні значення для φ^39поділу не мають загальних цифр ( 3.484899258054952* ^ - 9 for the computed version against the true value7.071019424062048 *^-9). Таким чином, алгоритм нестабільний, і не слід використовувати цю формулу рекурсії у неточній арифметиці. Це пов'язано з притаманною сутністю формулою рекурсії: для цієї рекурсії існує "занепадаюче" та "зростаюче" рішення, а спроба обчислити рішення "занепадаючого" рішення шляхом прямого рішення, коли існує альтернативне "зростаюче" рішення - благання за числове горе. Таким чином, слід забезпечити стабільність його чисельних алгоритмів.

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

Матриця Гільберта

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

Ось демонстрація Mathematica : порівняйте результати точної арифметики

Table[LinearSolve[HilbertMatrix[n], HilbertMatrix[n].ConstantArray[1, n]], {n, 2, 12}]
{{1, 1}, {1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 
  1}, {1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1,
   1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}

і неточна арифметика

Table[LinearSolve[N[HilbertMatrix[n]], N[HilbertMatrix[n].ConstantArray[1, n]]], {n, 2, 12}]
{{1., 1.}, {1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1., 1.},  
  {1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1.}, 
  {1., 1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1., 1., 1.},  
  {1., 1., 1., 0.99997, 1.00014, 0.999618, 1.00062, 0.9994, 1.00031, 
  0.999931}, {1., 1., 0.999995, 1.00006, 0.999658, 1.00122, 0.997327, 
  1.00367, 0.996932, 1.00143, 0.999717}, {1., 1., 0.999986, 1.00022, 
  0.998241, 1.00831, 0.975462, 1.0466, 0.94311, 1.04312, 0.981529, 
  1.00342}}

(Якщо ви все-таки спробували це в Mathematica , ви помітите кілька повідомлень про помилки, що попереджають про недобре кондиціонування.)

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

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


Я залишу вас із цитатою Діанні О'Лірі:

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


9

тому що базові 10 десяткових чисел не можуть бути виражені в базі 2

або інакше кажучи, 1/10 не може бути перетворений на дроби в знаменнику потужністю 2 (що по суті є числа з плаваючою комою)


11
Не зовсім вірно: 0,5 і 0,25 можна виразити в базі 2. Я думаю, ви маєте на увазі "не всі базові 10 десяткових чисел".
Скотт Вітлок

3
Більш точно. Не всі дробові числа можна точно представити, використовуючи позначення з плаваючою точкою (тобто з базою 2 і базою 10 є така точна проблема). Спробуйте зробити це 9*3.3333333у десятковій формі та зменшіть його до9*3 1/3
Мартін Йорк

1
Це найпоширеніше джерело плутанини з плаваючою комою. .1 + .1 != .2тому що використовується двійкове кодування з плаваючою комою, а не десяткове.
Шон Макміллан

@SeanMcMillan: І 1.0/3.0*3.0 != 1.0тому, що використовується двійкове кодування з плаваючою комою, а не потрійне.
Кіт Томпсон

8

У математиці існує нескінченно багато раціональних чисел. 32-бітова змінна може мати лише 2 32 різних значення, а 64-бітна змінна лише 2 64 значення. Тому існує нескінченно багато раціональних чисел, які не мають точного подання.

Ми могли б придумати схеми, які дозволять нам представляти 1/3 ідеально, або 1/100. Виявляється, для багатьох практичних цілей це не дуже корисно. Є один великий виняток: у фінансах десяткові дроби часто спливають. Це здебільшого тому, що фінанси - це по суті людська діяльність, а не фізична.

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


2
Ще гірше, хоча нескінченний (незліченно нескінченний) об'єм пам'яті дасть змогу представляти всіх раціональних, цього не вистачить для представлення реальних дій. Ще гірше, що майже всі реальні числа не є обчислюваними числами. Найкраще, що ми можемо зробити з обмеженою кількістю пам’яті, це наблизити підмножину кінцевого діапазону до реальної кількості.
Девід Хаммен

4
@Kevin: Ви говорите про обчислювані числа, що є крихітним підмножиною (підмножиною з мірою нуля) реалів.
Девід Хаммен

1
+1 для найосновнішого пояснення: Ви намагаєтесь представляти нескінченну кількість чисел з кінцевою кількістю біт.
Раку

1
@DavidHammen: Обчислювані числа - це крихітний підмножина (міра нуль) дійсних цифр - але кожне число, з яким ви коли-небудь працюватимете в програмі, за визначенням обчислюється.
Кіт Томпсон

3
@Giorgio: Якщо ви обрали правильне подання, квадратний корінь з 2 може бути представлений, наприклад, як рядок "√2". (Мій старий калькулятор HP-48 зміг зробити саме це, і квадратування цього значення призвело до точно 2.0.) Існує лише незліченна нескінченність репрезентативних реальних чисел для будь-якого кінцевого представлення - але жодне обчислення не може дати число, яке не є, в принципі представницький. На практиці двійкова плаваюча крапка різко обмежує набір репрезентативних чисел, виграючи швидкість запалювання та крихітне зберігання відносно символічних зображень.
Кіт Томпсон

-2

Єдина дійсно очевидна "проблема округлення" з числами з плаваючою комою, про які я думаю, - це фільтри з ковзними середніми:

$$ \ початок {вирівняти} y [n] & = \ frac {1} {N} \ сума \ обмеження_ {i = 0} ^ {N-1} x [ni] \ & = y [n-1] + \ frac {1} {N} (x [n] - x [nN]) \ \ end {align} $$

щоб зробити цю роботу без накопичення шуму, ви хочете переконатися, що $ x [n] $, який ви додаєте в поточні вибірки, точно такий же, як і $ x [nN] $, які ви віднімете зразки $ N $ в майбутнє якщо це не так, то те, що відрізняється, це маленький косичок, який застрягне у вашій лінії затримки і ніколи не вийде. це тому, що цей фільтр ковзних середніх дійсно побудований з IIR, який має гранично стійкий полюс при $ z = 1 $ і нуль, який скасовує його всередині. але, це інтегратор і будь-яке лайно, яке інтегрується і не повністю видаляється, буде існувати в сумі інтегратора назавжди. саме тут фіксована точка не має тієї самої проблеми, що і номери з плаваючою комою.


ей, чи не працює розмітка $ математики $ LaTeX на форумі prog.SE ??? це справді кульгаво, якщо цього немає.
Роберт Брістоу-Джонсон

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