Навіщо вам потрібно поплавок / подвійний?


29

Я дивився http://www.joelonsoftware.com/items/2011/06/27.html і сміявся з жарту Джона Скета, що приблизно 0,3 не було 0,3. У мене особисто ніколи не було проблем з поплавцями / десятковими знаками / парними, але тоді я пам’ятаю, що я навчився 6502 дуже рано і ніколи не потребував плавців у більшості моїх програм. Єдиний раз, коли я використав це для графіки та математики, де неточні цифри були в порядку, а вихід був для екрана, а не для зберігання (у db, файлі) або залежно від цього.

Моє запитання: де ви зазвичай використовуєте floats / decimals / double? Тож я знаю, що слідкувати за цими ґетчами. З грошима я використовую longs і зберігаю значення на цент, для швидкості об'єкта в грі я додаю ints і ділю (або бітшвидкінг) значення, щоб знати, чи потрібно мені переміщувати піксель чи ні. (Я здійснив переміщення об'єкта за 6502 днів, у нас не було ні ділення, ні плавців, але були зрушення).

Тож я здебільшого був цікавим.


10
тому що дуже важливо, що відсотки, які я плачу за мою іпотеку, залишаються 12,6, а ставки стають 13 просто cos 13 - це хороший кругле число.
Чані

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

Добре, що комп’ютер розуміє міліменти.
tylermac

1
Або крім того, навіщо використовувати десяткові числа, коли ми можемо використовувати дроби?
tylermac

6
@Scrooge - за іронією долі ви не можете представити 0,6 в поплавці.
Мартін Бекетт

Відповіді:


28

Тому що вони, в більшості випадків, більш точні , ніж цілі.

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

Але потім ви також можете описати дуже повільні об'єкти, наприклад, годинниковий годинник. Оскільки це приблизно на 6 порядків повільніше, ніж об’єкти кулі, перший ld (10⁶) ≈ 20 біт дорівнює нулю, що виключає short intтипи з самого початку. Гаразд, сьогодні у нас є longскрізь, які залишають нам ще комфортні 12 біт. Але навіть тоді тактова частота буде точно до чотирьох знаків після коми. Це не дуже хороший годинник ... але це, звичайно, добре для гри. Просто ви не хотіли б зробити растр набагато більш грубим, ніж це є.

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

Що станеться, якщо ми обираємо тип поплавця? Той самий розмір - 32 біти, але тепер у вас є цілі 24 біти точності для всіх об'єктів. Це означає, що годинник має достатню точність, щоб роками синхронізувати синхронізацію. Кулі не мають вищої точності, але вони так само "живуть" частки секунди, так що було б абсолютно марно, якби вони були. І ви не потрапляєте у будь-які проблеми, якщо хочете описати навіть набагато швидші об’єкти (чому б не швидкість світла? Немає проблем) чи набагато повільніші. Вам, звичайно, не знадобляться такі речі в грі, але ви іноді займаєтесь фізичними симуляціями.

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


Цілі особи ідеально точні. Неточність залежить від неправильного розрахунку.
fjdumont

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

53

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


28

У вас тут справді два питання.

Навіщо комусь потрібна математика з плаваючою комою?

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

Я використовував математику з плаваючою комою в багатьох, багатьох областях в моїй кар’єрі програмування: хімія, робота над AutoCAD і навіть написання тренажера Монте-Карло, щоб робити фінансові прогнози. Насправді є хлопець на ім’я Девід Е. Шоу, який використовував застосовувані наукові методи моделювання з плаваючою комою на Уолл-Стріт, щоб отримати мільярди.

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

Навіщо комусь потрібен поплавок проти дубля ?

При стандартних поданнях IEEE 754 32-розрядний поплавок дає приблизно 7 десяткових цифр точності та показники в діапазоні від 10 -38 до 10 38 . 64-бітний подвійний дає приблизно 15 десяткових цифр точності та показники в діапазоні від 10 -307 до 10 307 .

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

Але більш тонким є проблема, розмовно називана "помилка обрізання". Двійкові подання з плаваючою точкою справедливі лише для значень, дробові частини яких мають знаменник потужністю 2, як 1/2, 1/4, 3/4 тощо. значення для найближчого двійкового дробу, але це трохи неправильно - це "помилка округлення". Тоді, коли ви робите математику на цих неточних числах, неточності в результатах можуть бути набагато гіршими, ніж з того, з чого ви почали - іноді відсотки помилок примножуються або навіть накопичуються експоненціально.

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

Насправді, 64-розрядні парні з їх десятковими цифрами недостатньо хороші для багатьох програм. У 1985 році я використовував 80-бітні номери з плаваючою комою, і тепер IEEE визначає 128-бітний (16-байтовий) тип з плаваючою точкою, для якого я можу уявити собі використання.


2
+1 Боб мій досвід роботи з системами керування високою роздільною здатністю, як телескоп для астрономії, - це те, що 64-розрядний пар не є надто хорошим, якщо ви не сортуєте свої умови. Дітто для управління вогнем та
дальньою

20

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

Наведемо приклад: розробник заробляє 100 000 доларів на рік. Яка його точна місячна зарплата? Використовуючи ціле число, ви отримуєте результат $ 8333,33 (¢ 833333), помножений на 12, становить 99,999,96 долара. Чи зберігала це як цілу допомогу? Ні, ні.

Чи завжди банки використовують десяткові / цілі значення? Ну, вони роблять для транзакційної частини. Але, наприклад, як тільки ви починаєте спілкуватися з інвестиційним банкінгом, за винятком відстеження фактичних транзакцій, все інше плаває. Оскільки це все внутрішній код, ви його не побачите, але ви можете досягти піку в QuantLib , який по суті такий же (за винятком набагато чистішого ;-).

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


1
@Job - десяткові знаки і поплавці дуже різні. Ви можете зберігати 0,1 точно в десятковій формі, але не в поплавці чи подвійному.
Скотт Вітлок

3
У мене було ще одне питання. Якщо ви платили $100,000/12і користувались плавцем. Чому результат отримав би рівно 100 000 доларів? Чому б не плавати (або десятковий) закруглюватися вгору або вниз щоразу, коли комусь платять? Я говорю про те, коли пишуть чек (ти не можеш робити 1/2 або 1/3 цента) або прямий депозит (я припускаю, що він має ті самі обмеження)

@acid: >>> x = 100000 / 12.0 >>> x * 12 100000.0
vartec

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

2
@acid: ви не можете використовувати прямий поділ, незалежно від того, якщо ви використовуєте ціле, десяткове чи ділене як плаваюче, а потім кругле. У цьому і вся суть, використання десяткових не допомагає цьому випадку.
vartec

4

Те, що ви описали, - це ідеально хороша робота в ситуаціях, коли ви керуєте всіма входами та виходами .

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

Насправді ви зіткнетеся з цими проблемами, навіть якщо будете використовувати перелічені трюки. Підраховуючи 17,5% податку за ціну, ви збираєтесь отримувати дробові центи, зберігаючи ви ціна як долари чи центи. Ви повинні отримати правильне округлення, оскільки податкова людина дуже засмучується, якщо ви не заплатите йому достатньо. Використання правильних moneyтипів (якими б вони не були мовою, якою ви користуєтесь) позбавить вас від світу болю.


Що таке гроші? (мова чи посилання), і чому це "правильний" тип? Це тому, що його ... 128 біт або більше щось? Мій інший, чому використання моїх трюків було б невірним? У вас ціле число на відсотки. Якщо ви помножите його на .175, ви отримаєте ціле число і використовуватимете його для чого завгодно. Думаючи про свій приклад, я думаю, що float міг би утримувати мою цінність з достатньою точністю, але мені не доведеться турбуватися про те, що 0,3f == 0,3d буде помилковим. -edit- і +1

1
@ acidzombie24 - Я не мав на увазі конкретний тип, але те, що коли-небудь вводиться вашою мовою для відображення грошових цінностей. Крім того, якщо у вас є 10 копійок і помножте на 0,175, у вас є 1,75 копійки - як ви вирішите це з арифметикою цілої кількості? Це 1 цент чи 2 копійки? Зроби це неправильно, і ваш клієнт може в кінцевому підсумку володіти податковою людиною багато грошей.
ChrisF

Ніколи не слід помножувати 10 (ціле число) на .175 (справжнє / плаваюче число), оскільки не слід змішувати точні числа з неточними числами; результат буде неточним. Іншими словами, в системі точних чисел таке значення, як .175, ніколи б не існувало, і це несенсольний розрахунок. Краще рішення - помножити 10000 на 175 і вручну вставити десяткові крапки, де це доречно.
Баррі Браун

8
@Barry - я знаю. Я намагався проілюструвати тип проблеми, яку ви отримуєте. Також таке значення, як 0,175, існує, якщо ставка податку становить 17,5% і вам потрібно обчислити податок на предмет, який коштує 10 центів.
ChrisF

1
@acidzombie: Правильний тип використання для грошей - це десятковий знак з фіксованою точкою з високою (принаймні 4 десятковою точкою) точністю. Немає ifs, ands або buts. Введення даних у грошей в якості центів НЕ достатньо, тому що на практиці це дає вам тільки дві точки точності.
Aaronaught

3

"Бог створив цілі числа, все інше - це робота людини". - Леопольд Кронекер (1886).

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

Питання таке доброчесне, оскільки вони вам не потрібні . Можливо, ви хочете місця, де це зручно, оптимально чи дешевше чи щось таке?


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

4
Також повнота Тюрінга стосується лише обчислень. Ні цілі числа, ні навіть раціональні не є математично повною, оскільки жодна з них не закрита для зближення послідовностей Коші. Отже, Кронекер був сповнений гарячого повітря: якщо ви хочете повний метричний простір, який включає цілі числа, ви повинні отримати реальні: xkcd.com/849
Боб Мерфі

1
@Bob Мерфі: "академічний редукціонізм до кінця". Точно. Питання є бідним і призводить до такої можливої ​​відповіді.
S.Lott

2

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

Відверто кажучи, сказати, що вам не потрібні поплавці, тому що ви знаєте, як робити десяткову математику за допомогою цілих чисел, це як сказати, що ви знаєте, як робити арифметичні з великої руки, так навіщо використовувати калькулятор? Так ви знаєте поняття; браво. Це не означає, що ви повинні постійно використовувати ці знання. Часто це швидше, дешевше і зрозуміліше небінарному свисту просто сказати 3,5 + 4,6 = 8,1, а не перетворювати сиг фіг в цілу величину.


1

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

Щоб мова програмування ефективно задовольняв 98% чисельних потреб додатків, він повинен містити десятки типів і забезпечувати операції визначення для тих, що можуть бути сотнями комбінацій; Крім того, навіть якщо мова програмування мала чудову підтримку з фіксованою точкою, деякі додатки все одно повинні підтримувати приблизно постійну відносну точність у достатньо великому діапазоні, щоб вимагати плаваючої точки. Зважаючи на те, що математика з плаваючою комою в будь-яких випадках буде необхідною, якщо постачальники апаратних засобів зосередитись на математичній продуктивності з двома або трьома форматами з плаваючою комою та мати код використовувати ці формати, коли вони працюють досить добре, як правило, досягнуть кращого результату "удар за долар", ніж намагатися оптимізувати поведінку математики з фіксованою точкою.

Між іншим, математика з фіксованою точкою була вигіднішою для 8-бітних та 16-бітних процесорів, ніж для 32-розрядних. У 8-бітовому процесорі, у випадку, коли 32 біта не буде достатньо, 40-бітний тип коштуватиме лише 25% більше місця та 25-50% більше часу, ніж 32-бітний тип, і вимагатиме 37,5% менше місця та 37,5-60% менше часу, ніж 64-бітний тип. На 32-розрядної платформі, якщо 32-розрядного типу для чогось не вистачить, часто є мало причин використовувати що-небудь менше 64 біт. Якщо тип 48-бітної фіксованої точки був би адекватним, 64-розрядний "подвійний" буде працювати так само добре, як і фіксований.


0

Як правило, ви повинні бути дуже обережними в їх використанні. Розуміння втрати точності, яка може виникнути навіть із простих обчислень, є складним завданням. Наприклад, усереднення списку таких чисел є дуже поганою ідеєю:

double average(List<Double> data) {
  double ans = 0;
  for(Double d : data) {
    ans += d;
  }
  return ans / data.size();
}

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

Особисто я вважаю, що використовувати їх слід лише тоді, коли: а) розрахунок дійсно повинен бути швидким; б) тобі не байдуже, що результат, ймовірно, може бути віддаленим (якщо ти справді не знаєш, що робиш)


-1

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

Сьогоднішні архітектури (приблизно) мають підписаний цілий діапазон +/- 2,147,483,647 (32 біт) або +/- 9,223,372,036,854,775,807 (64 біт). Непідписаний розширює це на коефіцієнт 2.

IEEE 754 поплавці (приблизно) переходять від +/- 1,4 × 10 ^ −45 до 3,4 × 10 ^ 38. Подвійний розширює цей діапазон до +/- 5 × 10−324 ± 2.225 × 10 ^ −308, тут пропущено безліч умов і особливостей.

Звичайно, найбільш приголомшливо зрозуміла причина полягає в тому, що вам може знадобитися представити -0 ;-)


Числа насамперед із статей вікіпедії і мають бути наочними. За винятком -0, це просто для задоволення.
Стівен

Проблема в тому, що в такому величезному діапазоні багато цілих чисел, які взагалі не представлені.
Баррі Браун

@BarryBrown Абсолютно правильно. Хоча "багато умов та специфіки пропущено".
Стівен

-1

Звичайна причина полягає в тому, що вони швидкі, оскільки JVM зазвичай використовує базову апаратну підтримку (якщо ви не використовуєте строгий fp).

Дивіться https://stackoverflow.com/questions/517915/when-to-use-strictfp-keyword-in-java про те, що передбачає строгий файл.


Математика з плаваючою комою швидша, ніж ціла математика? На якому процесорі обчислення з плаваючою комою займає менше циклів, ніж обчислення цілих чисел?
this.josh

1
@ this.josh, сильно залежить від кількості цифр у ваших номерах. Також цілі числа не можуть точно розділити, що може бути, а може і не важливо.

-2

Ось чому нам потрібні 256-бітні операційні системи.

Довжина Планка (найменша відстань, яку ви можете виміряти) = 10 ^ -35 м
. Спостерігається всесвіт 14Bn парсек поперек = 10 ^ 25 м.
Отже, ви можете виміряти що-небудь в одиницях довжини Планка як цілі числа, якщо у вас є лише 200 біт точності.


2
-1: що робити, якщо ви моделюєте речі в масштабі, більшому за спостережуваний Всесвіт?
amara

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