Jaka jest różnica między decimal, floata doublew .NET?
Kiedy ktoś użyłby jednego z nich?
Jaka jest różnica między decimal, floata doublew .NET?
Kiedy ktoś użyłby jednego z nich?
Odpowiedzi:
floati doublesą 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.
decimaljest 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 decimalnadal 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/ doublesą 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/ doublezwykle nie reprezentują liczb, ponieważ 101.101110zwykle jest przedstawiany jako coś w 1101010 * 2^(01010010)stylu wykładnika
floatjest słowem kluczowym aliasu C # i nie jest typem .Net. to System.Single.. singlei doublesą 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 floatbędzie się łączyć 0.1i 0.1 + 1e-8, podczas gdy decimalbędzie się łączyć 0.1i 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. floatMogą przechowywać dowolną liczbę całkowitą do 1.6e7 z zerową utratą dokładności) - ale to wciąż nie jest nieskończona dokładność.
0.1to nie jest specjalna wartość ! Jedyne, co czyni 0.1„lepszym” niż 0.10000001to, że ludzie tacy jak podstawa 10. I nawet z floatwartością, jeśli zainicjujesz dwie wartości w 0.1ten 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.1któ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 ai oba nie bbę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.1decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;a == bab1/30.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
doublewł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 doublebył 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.
RealIIRC 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 Realreprezentowała całą liczbę groszy niż ...
doublektó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 doublemoż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.DecimalZgł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.
decimalprzez 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 doublelub float. Lubię to:
float myFloat;
double myDouble;
( floatto 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 floattwoim numerze możesz mieć do 7 cyfr. Dla doubles 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
floatjest liczbą 32-bitową i doublejest 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!
decimaljest 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 decimalnie 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 decimalmniejszej 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 decimalpowrotem 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.TryParsecał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 doublenajpierw, 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ż doublema mniejszą precyzję niż a decimal, faktycznie zapewniło to, że małe liczby będą nadal rozpoznawane. Z jakiegoś powodu double.TryParsebył w stanie odzyskać tak małe liczby, a jednocześnie decimal.TryParseustawić 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 .
Decimalnadaje się do zastosowań finansowych i jest głównym kryterium przy podejmowaniu decyzji między Decimala Double. Rzadko zdarza się, że Doubleprecyzja nie wystarcza na przykład do zastosowań naukowych (i Decimalczęsto nie nadaje się do zastosowań naukowych ze względu na ograniczony zasięg).
Główną różnicą między nimi jest precyzja.
floatjest 32-bitliczbą, doublejest 64-bitliczbą i decimaljest 128-bitliczbą.
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.
Decimalssą znacznie wolniejsze niż a double/float.
Decimalsi Floats/Doublesnie można go porównać bez obsady, Floatsa jednocześnie Doublesmoż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