Jaka jest różnica między decimal
, float
a double
w .NET?
Kiedy ktoś użyłby jednego z nich?
Jaka jest różnica między decimal
, float
a double
w .NET?
Kiedy ktoś użyłby jednego z nich?
Odpowiedzi:
float
i double
są zmiennoprzecinkowymi typami binarnymi . Innymi słowy, reprezentują liczbę taką jak ta:
10001.10010110011
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:
12345.65789
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.
float
/ double
zwykle nie reprezentują liczb, ponieważ 101.101110
zwykle jest przedstawiany jako coś w 1101010 * 2^(01010010)
stylu wykładnika
float
jest słowem kluczowym aliasu C # i nie jest typem .Net. to System.Single
.. single
i double
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.
float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);
Wynik:
float: 0.3333333
double: 0.333333333333333
decimal: 0.3333333333333333333333333333
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ład float
będzie się łączyć 0.1
i 0.1 + 1e-8
, podczas gdy decimal
będzie się łączyć 0.1
i 0.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 czyni 0.1
„lepszym” niż 0.10000001
to, że ludzie tacy jak podstawa 10. I nawet z float
wartością, jeśli zainicjujesz dwie wartości w 0.1
ten sam sposób, obie będą miały tę samą wartość . Tyle, że ta wartość nie będzie dokładnie 0.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;
to a == b
będzie prawdą . Po prostu to a
i oba nie b
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:
+---------+----------------+---------+----------+---------------------------------------------+
| C# | .Net Framework | Signed? | Bytes | Possible Values |
| Type | (System) type | | Occupied | |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte | System.Sbyte | Yes | 1 | -128 to 127 |
| short | System.Int16 | Yes | 2 | -32768 to 32767 |
| int | System.Int32 | Yes | 4 | -2147483648 to 2147483647 |
| long | System.Int64 | Yes | 8 | -9223372036854775808 to 9223372036854775807 |
| byte | System.Byte | No | 1 | 0 to 255 |
| ushort | System.Uint16 | No | 2 | 0 to 65535 |
| uint | System.UInt32 | No | 4 | 0 to 4294967295 |
| ulong | System.Uint64 | No | 8 | 0 to 18446744073709551615 |
| float | System.Single | Yes | 4 | Approximately ±1.5 x 10-45 to ±3.4 x 1038 |
| | | | | with 7 significant figures |
| double | System.Double | Yes | 8 | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
| | | | | with 15 or 16 significant figures |
| decimal | System.Decimal | Yes | 12 | Approximately ±1.0 x 10-28 to ±7.9 x 1028 |
| | | | | with 28 or 29 significant figures |
| char | System.Char | N/A | 2 | Any Unicode character (16 bit) |
| bool | System.Boolean | N/A | 1 / 2 | true or false |
+---------+----------------+---------+----------+---------------------------------------------+
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ą:
Kiedy ktoś użyłby jednego z nich?
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).
float
7 cyfr precyzji
double
ma około 15 cyfr precyzji
decimal
ma około 28 cyfr precyzji
Jeś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
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 i double
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ęgowa Real
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życie double
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ł
W ustawieniach domyślnych zmiennoprzecinkowe (System.Single) i doubles (System.Double) nigdy nie będą używać sprawdzania przepełnienia, podczas gdy Decimal (System.Decimal) zawsze będzie używać sprawdzania przepełnienia.
mam na myśli
decimal myNumber = decimal.MaxValue;
myNumber += 1;
zgłasza wyjątek OverflowException .
Ale te nie:
float myNumber = float.MaxValue;
myNumber += 1;
I
double myNumber = double.MaxValue;
myNumber += 1;
float.MaxValue+1 == float.MaxValue
, podobnie jak decimal.MaxValue+0.1D == decimal.MaxValue
. Może miałeś na myśli coś takiego float.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.
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
, wpisujesz double
lub float
. Lubię to:
float myFloat;
double myDouble;
( 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. Dla double
s możesz mieć do 16 cyfr. Aby być bardziej precyzyjnym, oto oficjalny rozmiar:
float: 1.5 × 10^-45 to 3.4 × 10^38
double: 5.0 × 10^-324 to 1.7 × 10^308
float
jest liczbą 32-bitową i double
jest liczbą 64-bitową.
Kliknij dwukrotnie nowy przycisk, aby uzyskać kod. Dodaj następujące trzy wiersze do kodu przycisku:
double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());
Zatrzymaj swój program i wróć do okna kodowania. Zmień tę linię:
myDouble = 0.007;
myDouble = 12345678.1234567;
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!
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); ponadto decimal
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 z decimal
powrotem do usługi, aby zapisać w bazie danych SQL Server .
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
decimal value = 0;
Decimal.TryParse(cellValue.ToString(), out value);
}
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 jest
cellValue = 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 na decimal
:
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
double valueDouble = 0;
double.TryParse(cellValue.ToString(), out valueDouble);
decimal value = (decimal) valueDouble;
…
}
Chociaż double
ma mniejszą precyzję niż a decimal
, faktycznie zapewniło to, że małe liczby będą nadal rozpoznawane. Z jakiegoś powodu double.TryParse
był w stanie odzyskać tak małe liczby, a jednocześnie decimal.TryParse
ustawić je na zero.
Dziwny. Bardzo dziwne.
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!
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ą
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
Dim fMean as Double = 1.18
Dim fDelta as Double = 0.08
Dim fLimit as Double = 1.1
If fMean - fDelta < fLimit Then
bLower = True
Else
bLower = False
End If
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
BINARY or COMP like float or double or decimal
PACKED-DECIMAL or COMP-3 (2 digit in 1 byte)
ZONED-DECIMAL (1 digit in 1 byte)
W prostych słowach:
/==========================================================================================
Type Bits Have up to Approximate Range
/==========================================================================================
float 32 7 digits -3.4 × 10 ^ (38) to +3.4 × 10 ^ (38)
double 64 15-16 digits ±5.0 × 10 ^ (-324) to ±1.7 × 10 ^ (308)
decimal 128 28-29 significant digits ±7.9 x 10 ^ (28) or (1 to 10 ^ (28)
/==========================================================================================
Możesz przeczytać więcej tutaj , Float , Double i Decimal .
Decimal
nadaje się do zastosowań finansowych i jest głównym kryterium przy podejmowaniu decyzji między Decimal
a Double
. Rzadko zdarza się, że Double
precyzja nie wystarcza na przykład do zastosowań naukowych (i Decimal
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
jest 32-bit
liczbą, double
jest 64-bit
liczbą i decimal
jest 128-bit
liczbą.
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ż a double/float
.
Decimals
i Floats/Doubles
nie można go porównać bez obsady, Floats
a jednocześnie Doubles
można.
Decimals
zezwól również na kodowanie lub końcowe zera.
musisz podać wartości jako:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;
i sprawdź wyniki.
Float - 4
Double - 8
Decimal - 12