Как решить, что использовать - двойное или десятичное?

Возможный дубликат:
десятичное против двойного! - Какой из них использовать и когда?

Я использую тип double для определения цены в моем торговом программном обеспечении. Заметил, что иногда возникают странные ошибки. Они возникают, если цена содержит 4 цифры после точки, например 2,1234.

Когда я отправил из своей программы «2,1234», в рыночном ордере появляется цена «2,1235».

Я не использую decimal, потому что мне не нужна «экстремальная» точность. Мне не нужно, например, отличать «2,0000000000003» от «2,00000000002». Мне нужно максимум 6 цифр после точки.

Возникает вопрос - а где же линия? Когда использовать decimal?

Стоит ли использовать decimal для каких-либо финансовых операций? Даже если мне нужна всего одна цифра после точки? (1.1 1.2 и т. Д.)

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


person Oleg Vazhnev    schedule 14.06.2011    source источник
comment
У вас не должно возникнуть проблем с удвоением на таких маленьких числах, состоящих из нескольких цифр. Число двойной точности приближается к 15 значащим цифрам, например 10 цифр после запятой, даже если значения исчисляются тысячами. Я бы проверил ваш код, поскольку ошибка округления и т. Д. Не исправляется с помощью десятичной дроби ...   -  person dtech    schedule 14.06.2011


Ответы (11)


Используйте десятичную дробь всякий раз, когда вы имеете дело с величинами, которые вы хотите (и можете) представить точно в системе счисления 10. Это включает в себя денежные значения, потому что вы хотите, чтобы 2,1234 было представлено точно как 2,1234.

Используйте double, если вам не нужно точное представление в базе 10. Обычно это хорошо для обработки измерений, потому что это уже приблизительные, а не точные величины.

Конечно, если для вас не важно наличие или отсутствие точного представления в базе 10, следует учитывать другие факторы, которые могут иметь или не иметь значения в зависимости от конкретной ситуации:

  • double имеет больший диапазон (может работать как с очень большими, так и с очень маленькими величинами);
  • десятичная дробь имеет большую точность (имеет большее количество значащих цифр);
  • вам может потребоваться использовать double для взаимодействия с некоторыми старыми API-интерфейсами, которые не поддерживают десятичный формат;
  • double быстрее десятичного;
  • десятичный формат занимает больше памяти;
person R. Martinho Fernandes    schedule 14.06.2011
comment
А также для вашего списка: double имеет гораздо больший диапазон как на верхнем, так и на нижнем концах, если вам нужно представить действительно огромные или крошечные числа. - person Eric Lippert; 14.06.2011

Когда точность необходима и важна, используйте decimal.

Когда точность не так важна, вы можете использовать double.

В вашем случае вы должны использовать decimal в качестве финансового вопроса.

person Nawaz    schedule 14.06.2011

Для финансовых операций я всегда использую десятичный тип

person Serghei    schedule 14.06.2011

Используйте decimal, он создан для представления мощности 10 лунок (т. Е. Цен ).

person George Duckett    schedule 14.06.2011

Десятичные числа - это способ определения цен.

person Chuck Gracey    schedule 14.06.2011

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

person Matt Bond    schedule 14.06.2011

В этом примере простой ответ:

decimal d = 0.3M+0.3M+0.3M;
            bool ret = d == 0.9M; // true
            double db = 0.3 + 0.3 + 0.3;
            bool dret = db == 0.9; // false

тест с двойным числом завершается неудачно, поскольку значение 0,3 в его двоичном представлении (основание 2) является периодическим, поэтому вы теряете точность, десятичное число представлено двоично-десятичным числом, поэтому основание 10, и вы не потеряли значащую цифру неожиданно. К сожалению, Decimal значительно медленнее, чем double. Обычно мы используем десятичную дробь для финансовых расчетов, где необходимо учитывать любую цифру, чтобы избежать допуска, двойное / плавающее для инженерных расчетов.

person Felice Pollano    schedule 14.06.2011

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

person dtech    schedule 14.06.2011
comment
Хотя я согласен с вашими выводами, есть ли у вас ссылка в подтверждение вашего утверждения о том, что десятичная дробь предназначена специально для денег? Разве это не полезно для любых расчетов, требующих высокой точности? - person Dan Diplo; 14.06.2011
comment
@Dan: Я отсылаю вас к разделу 4.1.7 спецификации C #, в котором говорится, что десятичный тип - это 128-битный тип данных, подходящий для финансовых и денежных расчетов. Вот для чего он был добавлен в язык. - person Eric Lippert; 14.06.2011
comment
@Eric Lippert Спасибо, не могу найти более авторитетного источника, чем это! - person Dan Diplo; 14.06.2011

Объяснение этого есть на MSDN

person Rajeev    schedule 14.06.2011

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

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

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

person Martin Liversage    schedule 14.06.2011
comment
например интегралы, используемые в актуарных расчетах - цитата, пожалуйста? Я бы подумал, что более точная десятичная дробь будет лучше, хотя и медленнее. - person kristianp; 10.04.2012
comment
@kristianp: Для финансовых вычислений обычно следует использовать десятичные дроби. Проблема заключается не в отсутствии точности в числах с плавающей запятой (точность высока), а в том факте, что числа, подобные 0,1, не могут быть точно представлены с помощью чисел с плавающей запятой. Однако некоторые финансовые вычисления включают в себя нечто большее, чем простые алгебраические операции сложения и умножения чисел (например, актуарные вычисления). Если вы не хотите создавать свои собственные log или sin функции для десятичных чисел, вам придется преобразовать десятичные дроби в числа с плавающей запятой и использовать математическую библиотеку. - person Martin Liversage; 10.04.2012

Если вы всегда знаете максимальное количество десятичных знаков, которое у вас будет (цифры после точки). Тогда лучше всего использовать нотацию с фиксированной точкой. Это даст вам точный результат при очень быстрой работе.

Самый простой способ использования фиксированной точки - просто сохранить число в виде целого числа тысяч частей. Например, если цена всегда имеет 2 десятичных знака, вы сэкономите сумму в центах (12,45 доллара США хранятся в int со значением 1245, что, таким образом, будет представлять 1245 центов). С четырьмя десятичными знаками вы будете хранить десятки тысяч (12,3456 будет храниться в int со значением 123456, представляющим 123456 десятитысячных) и т. Д.

Недостатком этого является то, что вам иногда может потребоваться преобразование, если, например, вы умножаете два значения вместе (0.1 * 0.1 = 0.01 в то время как 1 * 1 = 1, единица измерения изменилась с десятых до сотых). И если вы собираетесь использовать некоторые другие математические функции, вы также должны принять во внимание такие вещи.

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

person lyml    schedule 14.06.2011
comment
спасибо, что имеет смысл. Думаю, наверное, так decimal работает :) - person Oleg Vazhnev; 14.06.2011
comment
Как часто вообще имеет смысл умножение одной денежной стоимости на другую? ;) - person Stein G. Strindhaug; 14.06.2011
comment
@Stein: Процентные ставки указаны в десятых и сотых долях процента. Вы все время умножаете их на деньги. Вы хотите, чтобы расчет 123456,78 м * 0,0325 м * / 12 м был точным, когда это ваш ежемесячный процент по ипотеке, верно? Используйте десятичную дробь для умножения финансовых величин. - person Eric Lippert; 14.06.2011
comment
Да, но ответ будет таким же, если вы умножите процентную ставку по центам или долларам на десятичные дроби. 1% от 1 доллара (1 * 0,01 = 0,01) будет таким же, как 1% от 100 центов (100 * 0,01 = 1) ( при условии 100 центов за доллар, я не из США). Если нет какой-либо причины для умножения долларов на доллары (что приводит к квадратным долларам?), Нет необходимости преобразовывать перед умножением на процентные десятичные значения, независимо от того, хранятся ли они в виде десятичных долларов или целых центов. - Но, конечно, если Decimal в C # предназначен для денег, лучше использовать, чем накатывать свой собственный. - person Stein G. Strindhaug; 15.06.2011
comment
Кстати, согласно Google Calculator, квадратные доллары существуют: google.com / search? q = 2% 24 + раз + 4% 24 ... или они вслепую вычисляют ответ, какой бы глупый вопрос ни был;) - person Stein G. Strindhaug; 15.06.2011