Wydaje ci się, że masz zalety korzystania z typu zmiennoprzecinkowego. Zwykle projektuję dziesiętne we wszystkich przypadkach i polegam na profilerze, który informuje mnie, czy operacje dziesiętne powodują wąskie gardła lub spowolnienia. W takich przypadkach „rzucę” w dół, aby podwajać lub unosić, ale robię to tylko wewnętrznie i ostrożnie staram się zarządzać utratą precyzji, ograniczając liczbę znaczących cyfr w wykonywanej operacji matematycznej.
Ogólnie rzecz biorąc, jeśli twoja wartość jest przejściowa (nie jest ponownie wykorzystywana), możesz bezpiecznie używać typu zmiennoprzecinkowego. Rzeczywistym problemem związanym z typami zmiennoprzecinkowymi są następujące trzy scenariusze.
- Agregujesz wartości zmiennoprzecinkowe (w takim przypadku złożona liczba błędów precyzji)
- Budujesz wartości na podstawie wartości zmiennoprzecinkowych (na przykład w algorytmie rekurencyjnym)
- Robisz matematykę z bardzo dużą liczbą cyfr znaczących (na przykład
123456789.1 * .000000000000000987654321
)
EDYTOWAĆ
Zgodnie z dokumentacją referencyjną dotyczącą liczb dziesiętnych w C # :
Dziesiętny kluczowe oznacza typ danych 128-bitowym. W porównaniu do typów zmiennoprzecinkowych, typ dziesiętny ma większą precyzję i mniejszy zakres, co czyni go odpowiednim do obliczeń finansowych i pieniężnych.
Aby wyjaśnić moje powyższe stwierdzenie:
Zwykle projektuję dziesiętne we wszystkich przypadkach i polegam na profilerze, który informuje mnie, czy operacje dziesiętne powodują wąskie gardła lub spowolnienia.
Pracowałem tylko w branżach, w których dziesiętne są korzystne. Jeśli pracujesz nad silnikami fizyki lub graficznymi, prawdopodobnie bardziej korzystne jest zaprojektowanie typu zmiennoprzecinkowego (zmiennoprzecinkowego lub podwójnego).
Dziesiętny nie jest nieskończenie dokładny (nie można przedstawić nieskończonej precyzji dla niecałkowitej w prymitywnym typie danych), ale jest znacznie bardziej precyzyjny niż dwukrotność:
- dziesiętny = 28-29 cyfr znaczących
- double = 15-16 cyfr znaczących
- liczba zmiennoprzecinkowa = 7 cyfr znaczących
EDYCJA 2
W odpowiedzi na komentarz Konrada Rudolfa punkt 1 (powyżej) jest zdecydowanie poprawny. Agregacja niedokładności rzeczywiście się pogarsza. Zobacz poniższy kod dla przykładu:
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();
}
To powoduje, że:
Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000
Jak widać, mimo że dodajemy z tej samej stałej źródłowej, wyniki podwójności są mniej precyzyjne (chociaż prawdopodobnie będą się zaokrąglały poprawnie), a liczba zmiennoprzecinkowa jest znacznie mniej dokładna, do tego stopnia, że została zredukowana do tylko dwie cyfry znaczące.