Что можно сделать с языками программирования, чтобы избежать ошибок с плавающей запятой?

28

Неправильное понимание арифметики с плавающей запятой и ее недостатков является основной причиной удивления и путаницы в программировании (рассмотрим количество вопросов о переполнении стека, относящихся к «числам, которые не складываются правильно»). Учитывая то, что многим программистам еще предстоит понять его последствия, он может внести много тонких ошибок (особенно в финансовое программное обеспечение). Что могут сделать языки программирования, чтобы избежать ошибок для тех, кто не знаком с концепциями, и в то же время предлагает свою скорость, когда точность не критична для тех, кто понимает концепции?

Адам Пейнтер
источник
26
Единственное, что может сделать язык программирования, чтобы избежать ловушек обработки с плавающей запятой, - это запретить его. Обратите внимание, что это включает в себя и число с плавающей запятой base-10, которое в целом столь же неточно, за исключением того, что к нему предварительно адаптированы финансовые приложения.
Дэвид Торнли
4
Для этого и нужен «Численный анализ». Узнайте, как минимизировать потерю точности - иначе говоря, ошибки с плавающей запятой.
Хороший пример проблемы с плавающей запятой: stackoverflow.com/questions/10303762/0-0-0-0-0
Остин Хенли

Ответы:

47

Вы говорите , что «особенно для финансового обеспечения», которая воспитывает одна из моих любимых мозолей: деньги не поплавок, что это ИНТ .

Конечно, это выглядит как поплавок. Там есть десятичная точка. Но это только потому, что вы привыкли к подразделениям, которые путают проблему. Деньги всегда приходят в целых количествах. В Америке это центы. (В некоторых случаях я думаю, что это могут быть мельницы , но пока игнорируйте это.)

Поэтому, когда вы говорите 1,23 доллара, это действительно 123 цента. Всегда, всегда, всегда делайте математику в этих терминах, и у вас все будет хорошо. Для получения дополнительной информации см .:

Отвечая на вопрос напрямую, языки программирования должны просто включать тип Money в качестве разумного примитива.

Обновить

Хорошо, я должен был сказать «всегда» только два раза, а не три раза. Деньги действительно всегда инт; те, кто думает иначе, могут попробовать отправить мне 0,3 цента и показать результат в выписке по счету. Но, как отмечают комментаторы, есть редкие исключения, когда вам нужно выполнять вычисления с плавающей запятой для чисел типа денег. Например, определенные виды цен или процентных расчетов. Даже тогда к ним следует относиться как к исключениям. Деньги приходят и уходят как целые числа, поэтому, чем ближе ваша система к этому, тем разумнее она будет.

Уильям Пьетри
источник
20
@JoelFan: вы принимаете концепцию за реализацию для конкретной платформы.
whatsisname
12
Это не так просто. Расчеты процентов, среди прочего, производят дробные центы и должны быть округлены в некоторой точке в соответствии с указанным методом.
Кевин Клайн
24
Вымышленный -1, так как у меня нет представителя для понижающего голоса :) ... Это может быть правильным для всего, что есть в вашем кошельке, но есть множество ситуаций учета, где вы вполне могли бы иметь дело с десятыми долями процента или меньшими долями. Decimalэто единственная разумная система для решения этой проблемы, и ваш комментарий «игнорируйте это сейчас» является предвестником гибели для программистов во всем мире: P
детально,
9
@kevin cline: в расчетах есть дробные центы, но есть соглашения о том, как их обрабатывать. Целью финансовых расчетов является не математическая правильность, а получение точно таких же результатов, что и у банкира с калькулятором.
Дэвид Торнли
6
Все будет идеально, заменив слово «целое» на «рациональное»
Эмилио Гаравалья
15

Поддержка типа Decimal помогает во многих случаях. Многие языки имеют десятичный тип, но они используются недостаточно.

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

Предоставление приблизительного оператора поможет. Однако такие сравнения проблематичны. Обратите внимание, что 0,9999 триллиона долларов примерно равны 1 триллиону долларов. Не могли бы вы внести разницу в моем банковском счете?

BillThor
источник
2
0.9999...триллион долларов точно равен 1 триллиону долларов на самом деле.
ПРОСТО МОЕ правильное мнение
5
@ ПРОСТО: Да, но я не встречал компьютеров с регистрами, которые будут хранить 0.99999.... Все они усекаются в какой-то момент, что приводит к неравенству. 0.9999достаточно ровно для техники. Для финансовых целей это не так.
BillThor
2
Но какая система использовала триллионы долларов в качестве базовой единицы вместо долларов?
Брэд
@Brad Попробуйте рассчитать (1 триллион / 3) * 3 на своем калькуляторе. Какую ценность вы получаете?
BillThor
8

Нам сказали, что делать на первом курсе (на втором курсе) по информатике, когда я поступил в университет (этот курс также был обязательным условием для большинства научных курсов)

Я вспоминаю лектора, который говорил: «Числа с плавающей точкой являются приблизительными значениями. Используйте целочисленные типы для денег. Используйте FORTRAN или другой язык с числами BCD для точных вычислений». (а затем он указал на приближение, используя тот классический пример 0,2, который невозможно точно представить в двоичной плавающей запятой). Это также оказалось на той неделе в лабораторных упражнениях.

Та же лекция: «Если вам нужно получить больше точности от чисел с плавающей запятой, рассортируйте свои термины. Добавляйте вместе небольшие числа, а не большие». Это застряло в моей голове.

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

Прежде чем жаловаться на качество гитары, научитесь играть.

Четыре года назад у меня был сотрудник, который работал в JPL. Он выразил недоверие, что мы использовали Фортран для некоторых вещей. (Нам нужно было очень точное численное моделирование, рассчитанное в автономном режиме.) «Мы заменили весь этот FORTRAN на C ++», - сказал он с гордостью. Я перестал удивляться, почему они пропустили планету.

Тим Виллискрофт
источник
2
+1 правильный инструмент для правильной работы. Хотя я на самом деле не использую Фортран. К счастью, я не работаю над нашими финансовыми системами на работе.
Джеймс Хоури
«Если вам нужно получить больше точности от чисел с плавающей запятой, сортируйте свои термины. Добавляйте вместе маленькие числа, а не большие». Любой образец по этому поводу?
mamcx
@mamcx Представьте себе десятичное число с плавающей запятой, имеющее только одну цифру точности. Вычисление 1.0 + 0.1 + ... + 0.1(повторяется 10 раз) возвращается по 1.0мере округления каждого промежуточного результата. Делая это наоборот, вы получаете промежуточные результаты 0.2, 0.3..., 1.0и , наконец 2.0. Это крайний пример, но с реалистичными числами с плавающей запятой подобные проблемы случаются. Основная идея заключается в том, что добавление одинаковых по размеру чисел приводит к наименьшей ошибке. Начните с наименьших чисел, поскольку их сумма больше и, следовательно, лучше подходит для добавления к более крупным.
Мааартин
Хотя материал с плавающей запятой в Fortran и C ++ будет в основном идентичен. Оба являются точными и в автономном режиме, и я почти уверен, что у Фортрана нет нативных реалов BCD ...
Марк
8

Предупреждение. Типу с плавающей точкой System.Double не хватает точности для прямого тестирования на равенство.

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

Я не верю, что что-то может или должно быть сделано на уровне языка.

оборота ChaosPandion
источник
1
Я давно не использовал поплавок или удвоение, поэтому мне любопытно. Это действительно существующее предупреждение компилятора или только то, что вы хотели бы увидеть?
Карл Билефельдт,
1
@ Карл - Лично я не видел или не нуждался в этом, но я думаю, что это может быть полезно для преданных, но зеленых разработчиков
ChaosPandion
1
Бинарные типы с плавающей запятой качественно не лучше и не хуже, чем Decimalв тестах на равенство. Разница между 1.0m/7.0m*7.0mи 1.0mможет быть на много порядков меньше разницы 1.0/7.0*7.0, но она не равна нулю.
суперкат
1
@ Патрик - я не уверен, к чему ты клонишь. Существует огромная разница между чем-то, что является правдой для одного случая и является правдой для всех случаев.
ChaosPandion
1
@ChaosPandion Проблема с примером в этом посте не в сравнении равенства, а в литерале с плавающей точкой. Поплавка с точным значением 1.0 / 10 нет. Математика с плавающей точкой дает 100% точные результаты при вычислении с целыми числами, подходящими в мантиссе.
Патрик
7

По умолчанию языки должны использовать рациональные числа с произвольной точностью для нецелых чисел.

Те, кому нужно оптимизировать, всегда могут попросить поплавки. Использование их по умолчанию имело смысл в C и других языках системного программирования, но не в большинстве популярных сегодня языков.

Waquo
источник
1
Как вы справляетесь с иррациональными числами тогда?
dsimcha
3
Вы делаете это так же, как с поплавками: приближение.
Waquo
1
Я должен сказать, я думаю, что это имеет большой смысл, большинство людей, которым нужны точные числа, нуждаются в рациональных, а не иррациональных (наука и техника могут использовать иррациональные числа, но затем вы снова возвращаетесь в приблизительное царство, или вы занимаетесь довольно специализированной чистой математикой)
JK.
1
Вычисления с рациональными рациональными точками часто будут на несколько порядков медленнее (возможно, НА МНОГОХ порядков медленнее), чем вычисления с аппаратной поддержкой double. Если расчет должен быть точным с точностью до доли на миллион, лучше потратить микросекунду на его вычисление с точностью до нескольких частей на миллиард, чем на абсолютно точную секунду.
суперкат
5
@supercat: То, что вы предлагаете, это просто предвестник преждевременной оптимизации. Текущая ситуация такова, что подавляющее большинство программистов вообще не нуждаются в быстрой математике, а затем укушаются непонятным поведением с плавающей запятой, поэтому сравнительно небольшое число программистов, которым нужна быстрая математика, получает его без набрать один дополнительный символ. Это имело смысл в семидесятых, теперь это просто чепуха. По умолчанию должно быть безопасно. Те, кому нужен пост, должны просить об этом.
Waquo
4

Две большие проблемы, связанные с числами с плавающей запятой:

  • несогласованные единицы, применяемые к вычислениям (обратите внимание, что это также влияет на целочисленную арифметику таким же образом)
  • Непонимание того, что числа FP являются приблизительными и как разумно иметь дело с округлением.

Первый тип ошибки может быть исправлен только путем предоставления составного типа, который включает в себя значение и информацию о единицах. Например, 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 лет назад я увидел числовой пакет с типом, состоящим из пары чисел с плавающей точкой, представляющих максимально и минимально возможные значения для количества. По мере того, как числа проходили вычисления, разница между максимумом и минимумом будет расти. По сути, это дало возможность узнать, сколько реальной точности присутствовало в вычисленном значении.
суперкат
3

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

Программистам все еще нужно работать с языком и понимать, как он обрабатывает числа с плавающей запятой, потому что если они этого не сделают, они сделают предположения, и однажды предписанное поведение не будет соответствовать их предположениям.

Мой взгляд на то, что программист должен знать:

  • Какие типы с плавающей точкой доступны в системе и на языке
  • Какой тип нужен
  • Как выразить намерения того, какой тип нужен в коде
  • Как правильно использовать преимущества любого автоматического продвижения по типу, чтобы сбалансировать ясность и эффективность при сохранении правильности
Джон
источник
3

Что могут сделать языки программирования, чтобы избежать ловушек с плавающей запятой ...?

Используйте разумные значения по умолчанию, например, встроенную поддержку для декали.

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

Armand
источник
3

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

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

Апалала
источник
не согласен, большинство языков в настоящее время дают слишком большую поддержку двоичных типов с плавающей запятой (почему == даже определено для чисел с плавающей запятой?) и недостаточно поддерживают рациональные или десятичные числа
jk.
@jk: Даже если результат любого вычисления никогда не будет гарантированно равным результату любого другого вычисления, сравнение на равенство все равно будет полезно в случае, когда одно и то же значение присваивается двум переменным (хотя обычно реализуются правила равенства, возможно, слишком свободно, так как x== yне означает, что выполнение вычисления xдаст тот же результат, что и выполнение того же вычисления y).
суперкат
@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 или около того "

Если кто-то doubleимеет наилучшее представление величины «одна десятая» и преобразует ее в float, результат будет «13 421 773,5 / 134 217 728, плюс или минус 1/268 435 456 или около того», что является правильным описанием значения.

Напротив, если кто-то 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 (и это не было т действительно 12,9 или 53,2). Я удивлен, что не видел никакой поддержки таких типов ни в одном из основных языков, тем более что они выглядели бы подходящими для математических модулей, которые могут работать с несколькими значениями параллельно.

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

оборота суперкат
источник
2

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

Конечно, вам нужно разрешить разработчику запрашивать максимальное значение с плавающей запятой, когда разработчику нужна такая точность. И вы могли бы представить проблемы, когда слегка отличающиеся выражения одной и той же математической операции дают потенциально разные результаты из-за промежуточных операций округления, когда разработчики не имеют достаточной точности в своих переменных. Но, по крайней мере, в мире баз данных, это не так уж важно. Большинство людей не занимаются научными вычислениями, которые требуют большой точности в промежуточных результатах.

Джастин Кейв
источник
Задание длины и точности сделало бы очень мало полезного. Наличие базы с фиксированной запятой 10 было бы полезно для финансовой обработки, которая убрала бы большую часть неожиданности, которую люди получают с плавающей запятой.
Дэвид Торнли
@ Дэвид - Возможно, я что-то упускаю, но чем отличается тип данных с фиксированной точкой 10 от того, что я предлагаю здесь? Float (2) в моем примере будет иметь фиксированные 2 десятичных знака и будет автоматически округляться до ближайшей сотой, что вы, скорее всего, будете использовать для простых финансовых расчетов. Более сложные вычисления потребуют, чтобы разработчик выделил большее количество десятичных цифр.
Джастин Кейв
1
То, что вы защищаете, - это тип данных с фиксированной базой 10 с точностью, определенной программистом. Я говорю, что указанная программистом точность в большинстве случаев бессмысленна и просто приведет к ошибкам, с которыми я сталкивался в программах на языке COBOL. (Например, когда вы изменяете точность переменных, очень легко пропустить одну переменную, через которую проходит значение. Для другой потребуется гораздо больше думать о промежуточном размере результата, чем о хорошем.)
David Thornley
4
Float(2)Как вы предложить не следует называть Float, так как нет ничего плавающим здесь, конечно , не «запятой».
Паŭло Эберманн
1
  • языки имеют поддержку десятичного типа; конечно, это не решает проблему, но у вас нет точного и конечного представления, например, ⅓;
  • некоторые БД и фреймворки имеют поддержку типа Money, при этом количество центов обычно хранится как целое число;
  • есть несколько библиотек для поддержки рациональных чисел; это решает проблему ⅓, но не решает проблему, например, √2;

Это выше применимо в некоторых случаях, но на самом деле не является общим решением для работы со значениями с плавающей запятой. Реальное решение состоит в том, чтобы понять проблему и научиться решать ее. Если вы используете вычисления с плавающей точкой, вы всегда должны проверять, являются ли ваши алгоритмы численно устойчивыми . Существует огромная область математики / информатики, которая связана с этой проблемой. Это называется числовой анализ .

vartec
источник
1

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

Функции, предназначенные для импорта оценок с плавающей точкой, должны быть четко обозначены как таковые и снабжены параметрами, соответствующими этой операции, например:

Finance.importEstimate(float value, Finance roundingStep)

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

Несколько вещей, которые могут помочь, хотя:

  • Я поддержу тех, кто спрашивает: «Почему точное тестирование на равенство для чисел с плавающей запятой даже законно?»
  • Вместо этого используйте isNear()функцию.
  • Предоставлять и поощрять использование объектов-накопителей с плавающей запятой (которые добавляют последовательности значений с плавающей запятой более стабильно, чем просто добавление их всех в обычную переменную с плавающей запятой).
comingstorm
источник
-1

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

JoelFan
источник
1
C не имеет десятичного типа, потому что он не примитивен, очень немногие компьютеры имеют какие-либо аппаратные десятичные инструкции. Вы можете спросить, почему BASIC и Pascal не имели этого, поскольку они не были разработаны, чтобы соответствовать металлу. COBOL и PL / I - единственные языки, которые я знаю в то время, когда было что-то подобное.
Дэвид Торнли
3
@JoelFan: так как ты пишешь CO на языке COBOL? Десятичное не решает никаких проблем, база 10 так же неточна, как и база 2.
vartec
2
Десятичное решение решает проблему точного представления долларов и центов, что полезно для языка, ориентированного на бизнес. Но в противном случае десятичная дробь бесполезна; он имеет те же виды ошибок (например, 1/3 * 3 = 0,999999999), хотя и намного медленнее. Вот почему это не по умолчанию в языках, которые не были специально разработаны для учета.
Ден04
1
И FORTRAN, который предшествовал C более чем на десятилетие, также не имеет стандартной десятичной поддержки.
Ден04
1
@JoelFan: если у вас есть квартальная стоимость, и вам нужна месячная стоимость, угадайте, на что вы должны умножить ее ... нет, это не 0,33, это ⅓.
vartec