Що можна зробити з мовами програмування, щоб уникнути підводних каменів з плаваючою точкою?


28

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


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

4
Ось для чого «Числовий аналіз». Дізнайтеся, як мінімізувати втрати точності - він же підводні камені з плаваючою точкою.

Хороший приклад проблеми з плаваючою комою: stackoverflow.com/questions/10303762/0-0-0-0-0
Остін Генлі

Відповіді:


47

Ви кажете "особливо для фінансового програмного забезпечення", яке виховує одного з моїх вихованців: гроші - це не поплавок, це int .

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

Отже, коли ви кажете 1,23 долара, це дійсно 123 копійки. Завжди, завжди, завжди займайся математикою в цих умовах, і ти будеш добре. Для отримання додаткової інформації див:

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

оновлення

Гаразд, я повинен був сказати "завжди" двічі, а не три рази. Гроші справді завжди є int; ті, хто думає про інше, можете спробувати надіслати мені 0,3 копійки та показати результат у вашій банківській виписці. Але як зазначають коментатори, трапляються рідкісні винятки, коли потрібно робити математику з плаваючою комою на грошових числах. Наприклад, певні види цін або розрахунки відсотків. Вже тоді до них слід ставитися як до винятків. Гроші надходять і виходять як цілі кількості, тож чим ближче ваша система прислухається до цього, тим безпечніше буде.


20
@JoelFan: ви помиляєтеся на концепції конкретної реалізації платформи.
whatsisname

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

24
Вигаданий -1, так як мені не вистачає представника щодо грошового погляду :) ... Це може бути правильним для того, що є у вашому гаманці, але є безліч облікових ситуацій, коли ви цілком можете мати справу з десятими частками або меншими частками. Decimalє єдиною розумною системою для вирішення цього питання, і ваш коментар "ігноруйте, що наразі" є передвісником приреченості для програмістів скрізь: P
дет.

9
@kevin cline: Існують дробові центи в обчисленнях, але є умови, як поводитися з ними. Мета фінансових розрахунків - не математична коректність, а отримання таких самих результатів, як і банкір з калькулятором.
Девід Торнлі

6
Все буде ідеально, замінивши слово "ціле" на "раціональне" -
Еміліо Гаравалія

15

Надання підтримки типу Decimal допомагає у багатьох випадках. Багато мов мають десятковий тип, але вони не використовуються.

Розуміння наближення, яке виникає при роботі з поданням дійсних чисел, є важливим. Використання як десяткових, так і типів з плаваючою комою 9 * (1/9) != 1є правильним твердженням. Коли константи оптимізатор може оптимізувати обчислення, щоб він був правильним.

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


2
0.9999...трильйон доларів точно дорівнює 1 трлн доларів фактично.
ПРОСТО МОЕ правильне ДУМКА

5
@ JUST: Так, але я не стикався з жодними комп’ютерами з регістрами 0.99999.... Усі вони в деякий момент усікаються, що призводить до нерівності. 0.9999є достатньо рівним для техніки. У фінансових цілях це не так.
BillThor

2
Але яка система використовувала трильйони доларів як базову одиницю замість доларів?
Бред

@Brad Спробуйте обчислити (1 трлн. / 3) * 3 на калькуляторі. Яку цінність ви отримуєте?
BillThor

8

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

Я пригадую лектора, який сказав: "Числа з плаваючою комою - це наближення. Використовуйте цілі типи грошей. Використовуйте FORTRAN або іншу мову з номерами BCD для точного обчислення". (а потім він вказав на наближення, використовуючи той класичний приклад 0,2, який неможливо точно представити у двійковій плаваючій точці). Це також виявилося того тижня в лабораторних вправах.

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

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

Перш ніж скаржитися на якість гітари, навчіться грати.

Чотири роки тому у мене був колега, який працював у JPL. Він висловив невіру, що ми використовували FORTRAN для деяких речей. (Нам потрібні були супер точні числові симуляції, розраховані в автономному режимі.) "Ми замінили все це FORTRAN на C ++", - гордо сказав він. Я перестав цікавитись, чому вони пропустили планету.


2
+1 правильний інструмент для правильної роботи. Хоча я фактично не використовую FORTRAN. На щастя, ні я не працюю над нашими фінансовими системами на роботі.
Джеймс Хоурі

"Якщо вам потрібно отримати більшу точність від плаваючої точки, відсортуйте свої умови. Додайте невеликі числа разом, а не великі числа." Будь-який зразок на цьому?
mamcx

@mamcx Уявіть десяткове число з плаваючою комою, що має лише одну цифру точності. Обчислення 1.0 + 0.1 + ... + 0.1(повторення 10 разів) повертається, 1.0коли кожен проміжний результат округляється. Роблячи це навпаки, ви отримуєте проміжні результати 0.2, 0.3..., 1.0і , нарешті 2.0. Це надзвичайний приклад, але з реалістичними числами з плаваючою комою подібні проблеми трапляються. Основна ідея полягає в тому, що додавання чисел, подібних за розміром, призводить до найменшої помилки. Почніть з найменших чисел, оскільки їх сума більша, а тому краще підходить для додавання до більших.
maaartinus

Матеріали з плаваючою точкою у Fortran та C ++ збираються здебільшого однакові. І те, і інше - офлайн, і я впевнений, що у Фортран немає рідних дій BCD ...
Марк

8

Попередження: System з плаваючою комою не має точності для прямого тестування рівності.

double x = CalculateX();
if (x == 0.1)
{
    // ............
}

Я не вірю, що щось можна чи потрібно робити на мовному рівні.


1
Я давно не користувався поплавцем чи дублем, тому мені цікаво. Це фактичне існуюче попередження компілятора чи просто одне, що ви хотіли б побачити?
Карл Білефельдт

1
@Karl - Особисто я цього не бачив і не потребував, але я думаю, що це може бути корисно відданим, але зеленим розробникам.
ChaosPandion

1
Бінарні типи з плаваючою крапкою не є кращими або гіршими якісно, ​​ніж Decimalколи йдеться про тестування рівності. Різниця між величинами 1.0m/7.0m*7.0mі 1.0mможе бути на багато порядків меншою, ніж різниця 1.0/7.0*7.0, але це не нуль.
supercat

1
@Patrick - Я не впевнений, у що ти потрапляєш. Існує величезна різниця між тим, що щось є істинним для одного випадку і істинним для всіх випадків.
ChaosPandion

1
@ChaosPandion Проблема з прикладом у цій публікації не є порівнянням рівності, це літералом з плаваючою комою. Немає плавця з точним значенням 1,0 / 10. Математика з плаваючою комою призводить до 100% точних результатів при обчисленні з цілими числами, що вміщуються в мантісі.
Патрік

7

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

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


1
Як ти тоді поводишся з нераціональними числами?
dimimcha

3
Ви робите це так само, як і з плавцями: наближення.
Waquo

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

1
Обчислення з раціональною точністю з довільною точністю часто будуть на порядок повільнішими (можливо, МНОГО порядків повільніше), ніж обчислення з апаратним забезпеченням double. Якщо підрахунок повинен бути точним до частки на мільйон, краще витратити мікросекунду, обчислюючи його в межах декількох частин на мільярд, ніж витратити другу обчислення його абсолютно точно.
supercat

5
@supercat: Те, що ви пропонуєте, - це лише дитина, яка доносить передчасну оптимізацію. Поточна ситуація полягає в тому, що переважній більшості програмістів не потрібно нічого в швидкій математиці, а потім їх покусає важко зрозуміти поведінка з плаваючою комою (помилка), так що відносно крихітна кількість програмістів, які потребують швидкої математики, отримує це, не маючи при цьому ввести один додатковий символ. Це мало сенс у сімдесятих, зараз це просто дурниці. За замовчуванням має бути безпечним. Ті, кому потрібно швидко, повинні просити цього.
Waquo

4

Дві найбільші проблеми, пов’язані з числами з плаваючою комою:

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

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

Другий тип відмови - це концептуальний збій. Невдачі проявляються, коли люди вважають їх абсолютними числами. Це впливає на операції рівності, кумулятивні помилки округлення тощо. Наприклад, може бути правильним те, що для однієї системи два вимірювання еквівалентні в межах певного похибки. Тобто .999 і 1.001 приблизно збігаються з 1,0, коли вам не байдуже відмінності, менші за +/- .1. Однак, не всі системи такі поблажливі.

Якщо потрібен якийсь рівень мовного рівня, я б назвав це точністю рівності . У NUnit, JUnit і аналогічно побудованих тестових рамах ви можете контролювати точність, яку вважають правильною. Наприклад:

Assert.That(.999, Is.EqualTo(1.001).Within(10).Percent);
// -- or --
Assert.That(.999, Is.EqualTo(1.001).Within(.1));

Якщо, наприклад, C # або Java були змінені, щоб включити оператор точності, це може виглядати приблизно так:

if(.999 == 1.001 within .1) { /* do something */ }

Однак, якщо ви надаєте подібну функцію, вам також доведеться враховувати випадок, коли рівність хороша, якщо сторони +/- не однакові. Наприклад, + 1 / -10 вважає два числа еквівалентними, якби одне з них було в межах 1 більше, або на 10 менше, ніж перше число. Для вирішення цього випадку вам може знадобитися також додати rangeключове слово:

if(.999 == 1.001 within range(.001, -.1)) { /* do something */ }

2
Я переключив би замовлення. Концептуальна проблема поширена. Питання перетворення одиниць порівняно незначне порівняно.
S.Lott

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

Це також можна було легко зробити в бібліотеці.
Майкл К

1
@ dan04: Я думав більше про "всі розрахунки точні до одного відсотка" або подібне. Я бачив смолу, яка є одиницею вимірювання, і я тримаюсь далеко.
TMN

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

3

Що можуть робити мови програмування? Не знаю, чи є одна відповідь на це питання, оскільки все, що компілятор / перекладач робить від імені програміста для полегшення його життя, зазвичай працює проти продуктивності, ясності та читабельності. Я думаю, що і спосіб C ++ (платити лише за те, що потрібно), і спосіб Perl (принцип найменшого здивування) є дійсними, але це залежить від програми.

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

Я переймаюся тим, що повинен знати програміст:

  • Які типи з плаваючою комою доступні в системі та мовою
  • Який тип потрібен
  • Як висловити наміри того, який тип потрібен у коді
  • Як правильно скористатися будь-яким автоматичним просуванням типу, щоб збалансувати чіткість та ефективність, зберігаючи правильність

3

Що можуть зробити мови програмування, щоб уникнути [плаваючої точки] підводних каменів ...?

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

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


3

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

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


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

@jk: Навіть якщо результат будь-яких обчислень ніколи не був би гарантований рівним результату будь-якого іншого обчислення, порівняння рівності все-таки було б корисним у випадку, коли одне і те ж значення присвоюється двом змінним (хоча правила рівності, що зазвичай застосовуються, можливо занадто вільно, оскільки x== yне означає, що виконання обчислень xбуде давати такий самий результат, як і виконання тих же обчислень на y).
supercat

@supercat вам все-таки потрібно порівняння, але я б скоріше вимагав від мене мови вказати допуск для кожного порівняння з плаваючою точкою, я можу все одно повернутися до рівності, вибравши толерантність = 0, але я принаймні змушений зробити це вибір
jk.

3

Можливо зробити одне, що можна зробити - видалити порівняння рівності з типів з плаваючою точкою, крім прямого порівняння зі значеннями NAN.

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


3

Мені здається дивним, що ніхто не вказав на раціональну кількість хитрощів родини Лісп.

Серйозно, відкрийте sbcl і зробіть це так: (+ 1 3)і ви отримаєте 4. Якщо *( 3 2)ви отримаєте 6. Тепер спробуйте, (/ 5 3)і ви отримаєте 5/3, або 5 третин.

Це може дещо допомогти в деяких ситуаціях, чи не так?


Цікаво, чи можливо дізнатись, чи потрібно результат відображати як 1/3 чи може бути точним десятком?
mamcx

гарна пропозиція
Пітер Порфі

3

Одне, що я хотів би бачити, - це визнання того, що doubleйого floatслід розглядати як розширення конверсії, тоді як floatдо doubleзвуження (*). Це може здатися протиінтуїтивно зрозумілим, але врахуйте, що типи означають насправді:

  • 0,1f означає "13,421,773,5 / 134,217,728, плюс-мінус 1 / 268,435,456 або близько того".
  • 0,1 дійсно означає 3,602,879,701,896,397 / 36,028,797,018,963,968 плюс або мінус 1 / 72,057,594,037,927,936 або так "

Якщо один має a, doubleякий найкраще відображає кількість "десята частина" і перетворює його floatв результат, то це буде "13,421,773,5 / 134,217,728 плюс або мінус 1 / 268,435,456 або так", що є правильним описом значення.

На противагу цьому, якщо у людини є a, floatяка найкраще відображає кількість "десята частина" і перетворює її в double, результат буде "13,421,773,5 / 134,217,728, плюс або мінус 1 / 72,057,594,037,927,936 або так" - рівень мається на увазі точності що неправильно в коефіцієнті понад 53 мільйони.

Хоча стандарт IEEE-744 вимагає, щоб математика з плаваючою комою виконувалася так, як ніби кожне число з плаваючою комою представляє точну числову величину саме в центрі його діапазону, що не слід вважати, що значення з плаваючою комою насправді представляють саме такі точні числові величини. Швидше, вимога про те, щоб значення вважалися в центрі їх діапазонів, випливає з трьох фактів: (1) обчислення повинні виконуватися так, ніби операнди мають якісь конкретні точні значення; (2) послідовні та задокументовані припущення є кориснішими, ніж суперечливі або недокументовані; (3) якщо можна зробити послідовне припущення, жодне інше послідовне припущення не може бути кращим, ніж припущення, що величина являє собою центр його діапазону.

Між іншим, я пам’ятаю, якихось 25 років або близько тому хтось придумав пакет із числовими номерами для C, який використовував «типи діапазону», кожен з яких складався з пари 128-бітних плавців; всі обчислення будуть зроблені таким чином, щоб обчислити мінімальне та максимально можливе значення для кожного результату. Якщо хтось зробив великий тривалий ітеративний розрахунок і придумав значення [12.53401391134 12.53902812673], можна бути впевненим, що хоча багато цифр точності втрачено на помилки округлення, результат все одно може бути розумно виражений як 12,54 (і це не було " t дійсно 12,9 або 53,2). Я здивований, що я не бачив жодної підтримки таких типів на будь-яких основних мовах, тим більше, що вони здадуться добре підходити до математичних одиниць, які можуть працювати паралельно на кількох значеннях.

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


2

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

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


Визначення довжини та точності мало б корисно. Маючи базову базу 10 з фіксованою точкою, було б корисно для фінансової обробки, яка б зняла велику частину сюрпризу, який люди отримують з плаваючою комою.
Девід Торнлі

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

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

4
Такого, Float(2)як ви пропонуєте, не слід називати Float, оскільки тут нічого не плаває, звичайно, не «десяткова крапка».
Paŭlo Ebermann

1
  • мови мають підтримку типу Decimal; звичайно, це насправді не вирішує проблему, все ж у вас немає точного та кінцевого представлення, наприклад ⅓;
  • деякі БД і рамки мають підтримку типу Money, це в основному зберігає кількість центів як ціле число;
  • є кілька бібліотек для раціональної підтримки чисел; що вирішує задачу ⅓, але не вирішує задачу, наприклад, √2;

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


1

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

Функції, призначені для імпортування оцінок з плаваючою комою, повинні бути чітко позначені як такі та забезпечені параметрами, відповідними цій операції, наприклад:

Finance.importEstimate(float value, Finance roundingStep)

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

Кілька речей, які можуть допомогти:

  • Я другого, хто запитає, "чому точне тестування рівності для плаваючої точки навіть законне?"
  • Натомість використовуйте isNear()функцію.
  • Забезпечувати та заохочувати використання об'єктів акумулятора з плаваючою комою (які стабільніше додають послідовності значень з плаваючою комою, ніж просто додавати їх у звичайну змінну з плаваючою точкою).

-1

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


1
C не мав десяткового типу, оскільки він не примітивний, дуже мало комп'ютерів, що мають будь-які апаратні десяткові інструкції. Ви можете запитати, чому BASIC і Pascal цього не мали, оскільки вони не були розроблені так, щоб вони відповідали металу. COBOL та PL / I - це єдині мої мої часи, які мали щось подібне.
Девід Торнлі

3
@JoelFan: так як ви пишете ⅓ в COBOL? Десяткове число не вирішує жодних проблем, основа 10 настільки ж неточна, як база 2.
vartec

2
Десяткові вирішують проблему точного представлення доларів та центів, що корисно для мови, орієнтованої на бізнес. Але в іншому випадку десятковий знак марний; він має однакові помилки (наприклад, 1/3 * 3 = 0,99999999) при цьому набагато повільніше. Ось чому це не за замовчуванням у мовах, які не були спеціально розроблені для обліку.
dan04

1
І FORTRAN, який передував C більше десяти років, також не має стандартної десяткової підтримки.
dan04

1
@JoelFan: якщо у вас є щоквартальне значення і вам потрібне значення на місяць, здогадайтеся, що вам потрібно помножити на ... ні, це не 0,33, це ⅓.
vartec
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.