Porównanie i różnice między typami danych Double, Float i Decimal w C# .NET 4.0

Wszyscy jesteśmy przyzwyczajeni do tego, że gdy korzystamy tylko z liczb całkowitych w naszym programie (np. -1, 0, 4) to wykorzystujemy odpowiedniki typu Integer (np. int, short, long, uint). Obliczenia wtedy są dokładne, lecz nie możemy korzystać z dobrodziejstw ułamków.

Z drugiej strony, gdy wiemy, że będziemy korzystać z ułamków w naszym programie, to stosujemy liczby zmiennoprzecinkowe, czyli odpowiedniki typy Float (np. float, single, double, real). Możemy wtedy operować na ułamkach, ale musimy się zgodzić z tym, że niektóre liczby nie będą zapisane dokładnie, a jedynie w postaci bardzo przybliżonej do wartości oczekiwanej. Wynika to z tego, że liczby zmiennoprzecinkowe wykorzystują podstawę o wartości 2, a co za tym idzie np. liczba 0.1 ma nieskończone rozwinięcie w tym zapisie i musimy zaokrąglać do najbliżej wartości jaka mieści się w ograniczonej liczbie bitów.

Takie zaokrąglanie czasami jest dopuszczalne (a właściwie bardzo często) i godzimy się na nie. W niektórych zastosowaniach jest to jednak niedopuszczalne – przykładem może być aplikacja bankowa, w której niedopuszczalne są takie zaokrąglenia i wartości muszą być w 100% dokładne.

Naprzeciw takiemu stanowi rzeczy wychodzi typ Decimal dostępny w .NET. Typ Decimal nie jest tak naprawdę typem prostym, a strukturą ze zdefiniowanymi operacjami matematycznymi na niej (np. +, -, *, /). Typ ten stosuje wewnątrz siebie do zapisu ułamków podstawę o wartości 10, więc pozwala na dokładne reprezentowanie liczb w systemie dziesiątkowym.

Można zadać sobie pytanie, po co w takim razie stosować jakiekolwiek inne typy niż Decimal. Odpowiedź jest bardzo prosta. Typy takie jak Integer oraz Float są typami prostymi, więc są bezpośrednio obsługiwane przez procesor – tak samo podstawowe operacje matematyczne również można wykonywać na nich bezpośrednio za pomocą procesora. Sprawia to, że praca na nich jest stosunkowo bardzo szybka.

Typ Decimal nie jest typem prostym – procesor nie może bezpośrednio wykonywać na tym typie operacji. Wiąże się to z tym, że każda operacja na typie Decimal wiąże się z wieloma dodatkowymi operacjami, które służą przetłumaczeniu tego typu na typy proste, wykonaniu na nich odpowiednich operacji i ponownym przywróceniu do typu złożonego z zachowaniem dokładności. Wszystko to sprawia, że operacje na typie Decimal są stosunkowo wolniejsze – niektóre źródła donoszą, że średnio 20x wolniejsze.

Reasumując, gdy zależy nam na dokładności to stosujemy typ Decimal. Gdy zależy nam na szybkości (a małe niedokładności pomijamy) to stosujemy typ Float lub Double.