Ви, здається, помітили переваги використання типу плаваючої точки. Я схильний розробляти десяткові знаки у всіх випадках і покладаюсь на профілера, щоб повідомити мені, чи операції з десятковою дією викликають вузькі місця або уповільнення. У цих випадках я буду "вниз кидати", щоб подвоїтись або плавати, але тільки робити це внутрішньо, і обережно намагатись керувати втратами на точність, обмежуючи кількість значущих цифр у математичній операції, що виконується.
Загалом, якщо ваше значення є тимчасовим (не використовується повторно), ви можете використовувати тип плаваючої точки. Справжня проблема типів з плаваючою комою - це наступні три сценарії.
- Ви агрегуєте значення з плаваючою комою (у такому випадку сполуки помилок точності)
- Ви будуєте значення на основі значення з плаваючою комою (наприклад, в рекурсивному алгоритмі)
- Ви займаєтесь математикою з дуже великою кількістю значущих цифр (наприклад,
123456789.1 * .000000000000000987654321
)
EDIT
Відповідно до довідкової документації на десяткові числа C # :
Десяткове ключове слово позначає тип даних 128-бітовим. Порівняно з типами з плаваючою комою, десятковий тип має більшу точність та менший діапазон, що робить його придатним для фінансових та грошових розрахунків.
Отже, щоб уточнити моє вище твердження:
Я схильний розробляти десяткові знаки у всіх випадках і покладаюсь на профілера, щоб повідомити мені, чи операції з десятковою дією викликають вузькі місця або уповільнення.
Я тільки коли-небудь працював у галузях, де децикали сприятливі. Якщо ви працюєте над фізикою або графічними двигунами, можливо, набагато вигідніше розробити тип типу з плаваючою комою (плаваючою або подвійною).
Десяткові знаки не є нескінченно точними (неможливо представити нескінченну точність для неінтегрального в примітивному типі даних), але це набагато точніше, ніж подвійне:
- десяткова = 28-29 значущих цифр
- подвійний = 15-16 значущих цифр
- float = 7 значущих цифр
EDIT 2
У відповідь на коментар Конрада Рудольфа пункт №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
Як ви бачите, навіть якщо ми додаємо з однієї і тієї ж вихідної константи, результати подвійних є менш точними (хоча, ймовірно, будуть округлені правильно), і поплавок набагато менш точний, до тієї точки, де він був зведений до лише дві значущі цифри.