Jaka jest różnica między decimal
, float
a double
w .NET?
Kiedy ktoś użyłby jednego z nich?
.net
floating-point
double
decimal
PC Luddite
źródło
źródło
Odpowiedzi:
float
idouble
są zmiennoprzecinkowymi typami binarnymi . Innymi słowy, reprezentują liczbę taką jak ta:Zarówno liczba binarna, jak i lokalizacja punktu binarnego są zakodowane w ramach wartości.
decimal
jest zmiennoprzecinkowym typem dziesiętnym . Innymi słowy, reprezentują liczbę taką jak ta:Ponownie liczba i położenie przecinka dziesiętnego są zakodowane w ramach wartości - to sprawia, że
decimal
nadal jest to zmiennoprzecinkowy typ zamiast stałego.Należy zauważyć, że ludzie są przyzwyczajeni do przedstawiania liczb całkowitych w postaci dziesiętnej i oczekują dokładnych wyników w postaci dziesiętnej; nie wszystkie liczby dziesiętne są dokładnie reprezentowalne w binarnym zmiennoprzecinkowym - na przykład 0,1 - więc jeśli użyjesz binarnej wartości zmiennoprzecinkowej, faktycznie uzyskasz przybliżenie do 0,1. Nadal będziesz otrzymywać przybliżenia, używając również zmiennoprzecinkowego miejsca dziesiętnego - na przykład wyniku dzielenia 1 przez 3 nie można dokładnie przedstawić.
Co do zastosowania, gdy:
W przypadku wartości, które są „naturalnie dokładnymi miejscami dziesiętnymi”, dobrze jest użyć
decimal
. Jest to zwykle odpowiednie dla wszelkich koncepcji wymyślonych przez ludzi: wartości finansowe są najbardziej oczywistym przykładem, ale są też inne. Weźmy na przykład punktację dla nurków lub łyżwiarzy.Dla wartości, które są więcej artefaktami natury, których tak naprawdę nie można dokładnie zmierzyć ,
float
/double
są bardziej odpowiednie. Na przykład dane naukowe byłyby zwykle reprezentowane w tej formie. Tutaj pierwotne wartości nie będą na początku „dziesiętnie dokładne”, więc nie jest ważne, aby oczekiwane wyniki zachowały „dokładność dziesiętną”. Zmienne zmiennoprzecinkowe są znacznie szybsze w pracy niż dziesiętne.źródło
float
/double
zwykle nie reprezentują liczb, ponieważ101.101110
zwykle jest przedstawiany jako coś w1101010 * 2^(01010010)
stylu wykładnikafloat
jest słowem kluczowym aliasu C # i nie jest typem .Net. toSystem.Single
..single
idouble
są zmiennoprzecinkowe typy binarne.Precyzja jest główną różnicą.
Liczba zmiennoprzecinkowa - 7 cyfr (32 bity)
Podwójne -15-16 cyfr (64 bity)
Liczba dziesiętna -28-29 cyfr znaczących (128 bitów)
Ułamki dziesiętne mają znacznie wyższą precyzję i są zwykle używane w aplikacjach finansowych, które wymagają wysokiego stopnia dokładności. Dziesiętne są znacznie wolniejsze (w niektórych testach nawet 20 razy) niż podwójne / zmiennoprzecinkowe.
Liczby dziesiętne i zmiennoprzecinkowe / podwajanie nie mogą być porównywane bez obsady, podczas gdy zmiennoprzecinkowe i podwajające mogą. Dziesiętne pozwalają również na kodowanie lub końcowe zera.
Wynik:
źródło
0.1
taka - rzadko w prawdziwym świecie! Każdy skończony format przechowywania połączy nieskończoną liczbę możliwych wartości ze skończoną liczbą wzorów bitowych. Na przykładfloat
będzie się łączyć0.1
i0.1 + 1e-8
, podczas gdydecimal
będzie się łączyć0.1
i0.1 + 1e-29
. Oczywiście, w danym zakresie pewne wartości mogą być reprezentowane w dowolnym formacie z zerową utratą dokładności (np.float
Mogą przechowywać dowolną liczbę całkowitą do 1.6e7 z zerową utratą dokładności) - ale to wciąż nie jest nieskończona dokładność.0.1
to nie jest specjalna wartość ! Jedyne, co czyni0.1
„lepszym” niż0.10000001
to, że ludzie tacy jak podstawa 10. I nawet zfloat
wartością, jeśli zainicjujesz dwie wartości w0.1
ten sam sposób, obie będą miały tę samą wartość . Tyle, że ta wartość nie będzie dokładnie0.1
- będzie najbliższą wartością,0.1
którą można dokładnie przedstawić jakofloat
. Jasne, z liczbami binarnymi(1.0 / 10) * 10 != 1.0
, ale z liczbami dziesiętnymi(1.0 / 3) * 3 != 1.0
. Żadne z nich nie jest idealnie precyzyjne.double a = 0.1; double b = 0.1;
toa == b
będzie prawdą . Po prostu toa
i oba nieb
będą dokładnie równe . W języku C #, jeśli to zrobisz, to również będzie prawdą. Ale w takim przypadku żaden z nich nie będzie dokładnie równy - oba będą równe . W obu przypadkach utrata dokładności wynika z reprezentacji. Uparcie twierdzisz, że ma „nieskończoną” precyzję, co jest fałszem .0.1
decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;
a == b
a
b
1/3
0.3333...
decimal
Struktura dziesiętna jest ściśle dostosowana do obliczeń finansowych wymagających dokładności, które są stosunkowo nietolerancyjne zaokrąglania. Ułamki dziesiętne nie są odpowiednie do zastosowań naukowych, jednak z kilku powodów:
źródło
Zobacz tutaj, aby uzyskać więcej informacji .
źródło
Nie będę powtarzać ton dobrych (i niektórych złych) informacji, na które już udzielono odpowiedzi w innych odpowiedziach i komentarzach, ale odpowiem na twoje pytanie uzupełniające wskazówką:
Użyj wartości dziesiętnych dla zliczonych wartości
Użyj wartości zmiennoprzecinkowych / podwójnych dla zmierzonych wartości
Kilka przykładów:
pieniądze (czy liczymy pieniądze czy mierzymy pieniądze?)
odległość (czy liczymy odległość czy mierzymy odległość? *)
wyniki (czy liczymy wyniki czy mierzymy wyniki?)
Zawsze liczymy pieniądze i nigdy nie powinniśmy ich mierzyć. Zwykle mierzymy odległość. Często liczymy wyniki.
* W niektórych przypadkach, co nazwałbym odległością nominalną , rzeczywiście możemy chcieć „policzyć” odległość. Może na przykład mamy do czynienia z znakami państwowymi, które pokazują odległości do miast i wiemy, że odległości te nie mają więcej niż jednej cyfry dziesiętnej (xxx.x km).
źródło
float
7 cyfr precyzjidouble
ma około 15 cyfr precyzjidecimal
ma około 28 cyfr precyzjiJeśli potrzebujesz większej dokładności, użyj podwójnej zamiast pływakowej. We współczesnych procesorach oba typy danych mają prawie taką samą wydajność. Jedyną zaletą używania pływaka jest to, że zajmują mniej miejsca. Praktycznie ma znaczenie tylko wtedy, gdy masz ich wiele.
Uważam, że to interesujące. Co każdy informatyk powinien wiedzieć o arytmetyki zmiennoprzecinkowej
źródło
double
właściwe zastosowanie w aplikacjach księgowych w tych przypadkach (i zasadniczo tylko w tych przypadkach), w których nie był dostępny typ liczby całkowitej większy niż 32 bity idouble
był używany tak, jakby był to 53-bitowy typ liczby całkowitej (np. Do przechowywania cała liczba centów lub cała setna setna centa). Obecnie niewiele takich zastosowań, ale wiele języków zyskało możliwość korzystania z wartości zmiennoprzecinkowych o podwójnej precyzji na długo przed uzyskaniem 64-bitowej (lub w niektórych przypadkach nawet 32-bitowej!) Matematyki całkowitej.Real
IIRC mógł reprezentować wartości do 1.8E + 19 z dokładnością do jednostki. Myślę, że byłoby znacznie rozsądniej, gdyby aplikacja księgowaReal
reprezentowała całą liczbę groszy niż ...double
które miały dokładność jednostkową do 9E15. Jeśli trzeba przechowywać liczby całkowite, które są większe niż największy dostępny typ liczb całkowitych, użyciedouble
może być prostsze i bardziej wydajne niż próba fałszowania matematyki wieloprecyzyjnej, szczególnie biorąc pod uwagę, że podczas gdy procesory mają instrukcje wykonywania 16x16-> 32 lub. ..Nikt o tym nie wspominał
mam na myśli
zgłasza wyjątek OverflowException .
Ale te nie:
I
źródło
float.MaxValue+1 == float.MaxValue
, podobnie jakdecimal.MaxValue+0.1D == decimal.MaxValue
. Może miałeś na myśli coś takiegofloat.MaxValue*2
?System.Decimal
Zgłasza wyjątek tuż przed staje się niezdolny do odróżnienia całych jednostek, ale jeśli aplikacja ma do czynienia z np dolarów i centów, że może być za późno.źródło
decimal
przez zero (CS0020), i to samo dotyczy literałów całkowitych. Jeśli jednak wartość dziesiętna środowiska wykonawczego zostanie podzielona przez zero, otrzymasz wyjątek, a nie błąd kompilacji.Jak wspomniano, liczby całkowite są liczbami całkowitymi. Nie mogą zapamiętać czegoś takiego, jak .7, .42 i .007. Jeśli chcesz przechowywać liczby, które nie są liczbami całkowitymi, potrzebujesz innego rodzaju zmiennej. Możesz użyć typu podwójnego lub typu zmiennoprzecinkowego. Ustawiasz te typy zmiennych dokładnie w ten sam sposób: zamiast używać słowa
int
, wpisujeszdouble
lubfloat
. Lubię to:(
float
to skrót od „zmiennoprzecinkowy” i oznacza po prostu liczbę z punktem na końcu czegoś).Różnica między nimi polega na wielkości liczb, które mogą pomieścić. W
float
twoim numerze możesz mieć do 7 cyfr. Dladouble
s możesz mieć do 16 cyfr. Aby być bardziej precyzyjnym, oto oficjalny rozmiar:float
jest liczbą 32-bitową idouble
jest liczbą 64-bitową.Kliknij dwukrotnie nowy przycisk, aby uzyskać kod. Dodaj następujące trzy wiersze do kodu przycisku:
Zatrzymaj swój program i wróć do okna kodowania. Zmień tę linię:
Uruchom program i kliknij podwójny przycisk. W oknie komunikatu poprawnie wyświetlany jest numer. Dodaj kolejną liczbę na końcu, a C # ponownie zaokrągli w górę lub w dół. Morał jest taki, że jeśli chcesz dokładności, uważaj na zaokrąglanie!
źródło
źródło
decimal
jest faktycznie przechowywany w formacie dziesiętnym (w przeciwieństwie do podstawy 2, więc nie straci ani nie zaokrągli cyfr z powodu konwersji między dwoma systemami numerycznymi); ponadtodecimal
nie ma pojęcia wartości specjalnych, takich jak NaN, -0, ∞ lub -∞.To był dla mnie interesujący wątek, ponieważ dzisiaj mieliśmy po prostu paskudny mały błąd dotyczący
decimal
mniejszej precyzji niżfloat
.W naszym kodzie C # odczytujemy wartości liczbowe z arkusza kalkulacyjnego Excel, konwertujemy je na
decimal
, a następnie odsyłamy zdecimal
powrotem do usługi, aby zapisać w bazie danych SQL Server .Teraz, dla prawie wszystkich naszych wartości Excela, działało to pięknie. Ale w przypadku niektórych, bardzo małych wartości Excela, użycie
decimal.TryParse
całkowicie utraciło wartość. Jednym z takich przykładów jestcellValue = 0,00006317592
Decimal.TryParse (cellValue.ToString (), wartość wyjściowa); // zwróci 0
Dziwnym rozwiązaniem było przekonwertowanie wartości Excela na
double
najpierw, a następnie nadecimal
:Chociaż
double
ma mniejszą precyzję niż adecimal
, faktycznie zapewniło to, że małe liczby będą nadal rozpoznawane. Z jakiegoś powodudouble.TryParse
był w stanie odzyskać tak małe liczby, a jednocześniedecimal.TryParse
ustawić je na zero.Dziwny. Bardzo dziwne.
źródło
decimal.Parse("0.00006317592")
działa - dzieje się coś innego. - Być może notacja naukowa?W aplikacjach, takich jak gry i systemy wbudowane, w których zarówno pamięć, jak i wydajność mają krytyczne znaczenie, liczba zmiennoprzecinkowa jest zwykle numerycznym wyborem, ponieważ jest szybsza i dwukrotnie mniejsza. Kiedyś bronią z wyboru były liczby całkowite, ale wydajność zmiennoprzecinkowa wyprzedziła liczbę całkowitą w nowoczesnych procesorach. Dziesiętny jest już gotowy!
źródło
Typy zmiennych Decimal, Double i Float różnią się sposobem przechowywania wartości. Precyzja jest główną różnicą, w której liczba zmiennoprzecinkowa to zmiennoprzecinkowy typ danych o pojedynczej precyzji (32 bity), podwójna to zmiennoprzecinkowy typ danych o podwójnej precyzji (64 bity), a liczba dziesiętna to 128-bitowy zmiennoprzecinkowy typ danych.
Float - 32 bity (7 cyfr)
Podwójny - 64 bity (15-16 cyfr)
Dziesiętny - 128 bitów (28-29 cyfr znaczących)
Więcej o ... różnicy między dziesiętną, zmiennoprzecinkową i podwójną
źródło
Problem z tymi wszystkimi typami polega na tym, że istnieje pewna niedokładność ORAZ że ten problem może wystąpić przy małych liczbach dziesiętnych, jak w poniższym przykładzie
Pytanie: Jaką wartość zawiera zmienna bLower?
Odpowiedź: Na 32-bitowej maszynie bLower zawiera PRAWDA !!!
Jeśli zastąpię Double przez Decimal, bLower zawiera FAŁSZ, co jest dobrą odpowiedzią.
Podwójnie problem polega na tym, że fMean-fDelta = 1.09999999999, który jest niższy niż 1.1.
Uwaga: Myślę, że ten sam problem z pewnością może istnieć w przypadku innych liczb, ponieważ dziesiętny jest tylko dwukrotnością z większą precyzją, a precyzja ma zawsze limit.
W rzeczywistości Double, Float i Decimal odpowiadają BINARNYM dziesiętnym w języku COBOL!
Szkoda, że inne typy liczbowe zaimplementowane w języku COBOL nie istnieją w .Net. Dla tych, którzy nie znają języka COBOL, istnieje w języku COBOL następujący typ liczbowy
źródło
W prostych słowach:
źródło
Decimal
nadaje się do zastosowań finansowych i jest głównym kryterium przy podejmowaniu decyzji międzyDecimal
aDouble
. Rzadko zdarza się, żeDouble
precyzja nie wystarcza na przykład do zastosowań naukowych (iDecimal
często nie nadaje się do zastosowań naukowych ze względu na ograniczony zasięg).Główną różnicą między nimi jest precyzja.
float
jest32-bit
liczbą,double
jest64-bit
liczbą idecimal
jest128-bit
liczbą.źródło
Dziesiętny 128-bitowy (28-29 cyfr znaczących) W przypadku aplikacji finansowych lepiej jest używać typów dziesiętnych, ponieważ zapewnia wysoki poziom dokładności i łatwe do uniknięcia błędy zaokrąglania Użyj dziesiętnego dla matematyki niecałkowitej, gdzie wymagana jest precyzja (np. pieniądze i waluta)
Podwójny 64-bitowy (15-16 cyfr) Typy podwójne są prawdopodobnie najczęściej używanym typem danych dla wartości rzeczywistych, z wyjątkiem obsługi pieniędzy. Użyj podwójnego dla matematyki niecałkowitej, gdzie najbardziej precyzyjna odpowiedź nie jest konieczna.
Float 32-bitowy (7 cyfr) Używany jest głównie w bibliotekach graficznych, ponieważ bardzo wysokie wymagania dotyczące mocy obliczeniowych, również w sytuacjach, które mogą znosić błędy zaokrąglania.
Decimals
są znacznie wolniejsze niż adouble/float
.Decimals
iFloats/Doubles
nie można go porównać bez obsady,Floats
a jednocześnieDoubles
można.Decimals
zezwól również na kodowanie lub końcowe zera.źródło
Aby zdefiniować dziesiętny, zmiennoprzecinkowy i podwójny w .Net (c #)
musisz podać wartości jako:
i sprawdź wyniki.
I Bajty zajmowane przez każdego są
źródło