Вы, похоже, используете преимущества с плавающей точкой. Я склонен проектировать на десятичные знаки во всех случаях и полагаться на профилировщика, чтобы сообщить мне, если операции с десятичной точкой вызывают узкие места или замедления. В таких случаях я буду «сбрасывать», чтобы удваивать или плавать, но делать это только внутренне и тщательно пытаться управлять точностью потерь, ограничивая количество значимых цифр в выполняемой математической операции.
В общем случае, если ваше значение временно (не используется повторно), вы можете использовать тип с плавающей точкой. Реальная проблема с типами с плавающей запятой заключается в следующих трех сценариях.
- Вы агрегирование значений с плавающей точкой (в этом случае точность ошибки соединения)
- Вы строите значения на основе значения с плавающей точкой (например, в рекурсивном алгоритме)
- Вы делаете математику с очень широкий ряд существенных цифр (например,
123456789.1 * .000000000000000987654321
)
РЕДАКТИРОВАТЬ
огласно к reference documentation on C# decimals:
десятичное ключевое слово обозначает 128-битовый тип данных . По сравнению с типами с плавающей точкой десятичный тип имеет большую точность и меньший диапазон , что делает его подходящим для финансовых и денежных расчетов .
Так прояснить мою выше заявление:
Я, как правило, дизайн для десятичных знаков во всех случаях, и полагаться на профайлер, чтобы мне знать, если операции по десятичной системе является вызывая узкие места или медленно -downs.
Я только когда-либо работал в отраслях, где десятичные значения благоприятны. Если вы работаете с phsyics или графическими движками, вероятно, гораздо более полезно разработать для типа с плавающей точкой (float или double).
Decimal не является бесконечно точным (это невозможно представить бесконечную точность для невстроенного в примитивном типе данных), но это гораздо более точное, чем дважды:
- десятичных = 28-29 значащих цифр
- двойные = 15-16 значащие цифры
- поплавка = 7 значащих цифр
EDIT 2
В ответ на комментарий Konrad Rudolph, элемент № 1 (выше) определенно правильный. Агрегация неточности действительно сложна. Смотрите ниже код для примера:
private const float THREE_FIFTHS = 3f/5f;
private const int ONE_MILLION = 1000000;
public static void Main(string[] args)
{
Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
float asSingle = 0f;
double asDouble = 0d;
decimal asDecimal = 0M;
for (int i = 0; i < ONE_MILLION; i++)
{
asSingle += THREE_FIFTHS;
asDouble += THREE_FIFTHS;
asDecimal += (decimal) THREE_FIFTHS;
}
Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
Console.ReadLine();
}
Это выводит следующее:
Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000
Как вы можете видеть, даже если мы добавляем из того же источника постоянного, результаты дубля меньше точнее (хотя, вероятно, будет округлять правильно), а поплавок гораздо менее точен, до того момента, когда он был уменьшен до двухзначных цифр.
см. Также http://stackoverflow.com/questions/2545567/in-net-how-do-i-choose-between-a-decimal-and-a-double –
Это довольно регулярно поддерживается, и я все еще боюсь с этим. Например, я работаю над приложением, которое выполняет финансовые расчеты, поэтому я использую десятичное целое. Но Math и VisualBasic. Финансовые функции используют double, поэтому есть много конверсий, из-за которых я постоянно размышляю над использованием десятичной дроби. –
@JamieIde, это безумие Финансовые функции используют double, деньги всегда должны быть десятичными. –