Jak przekonwertować liczbę dziesiętną na liczbę całkowitą w języku C #?

227

Jak przekonwertować liczbę dziesiętną na liczbę całkowitą?

Rob Hruska
źródło
11
Przydałoby się wiedzieć, czy chcesz zaokrąglić do najbliższej liczby całkowitej, czy po prostu upuścić cyfry po przecinku (tzn. Zawsze zaokrąglać w dół)
Dinah
128
szczerze mówiąc, nie widzę sensu w przeglądzie autentycznych pytań. tak, odpowiedź mogłaby być znaleziona w Google, ALE czy nie poprawiłoby to tylko jakości strony, gdyby ludzie przestali zamykać co drugie pytanie? to nie jest tak, że to pytanie jest spamem lub czymkolwiek innym, i jestem pewien, że przydałoby się wielu początkującym do c #
jay_t55

Odpowiedzi:

268

Użyj Convert.ToInt32od mscorlibjak w

decimal value = 3.14m;
int n = Convert.ToInt32(value);

Zobacz MSDN . Możesz także użyć Decimal.ToInt32. Ponownie zobacz MSDN . Wreszcie możesz wykonać rzut bezpośredni jak w

decimal value = 3.14m;
int n = (int) value;

który używa jawnego operatora rzutowania. Zobacz MSDN .

Jason
źródło
10
Uwaga: konwersja ma pewne zaskakujące zachowanie w przypadku niektórych konwersji ( nullvs. 0vs. ""). Polecam nigdy nie używać Konwertuj, chyba że absolutnie potrzebujesz jego elastyczności (tj. W scenariuszach z dynamicznym typowaniem)
Eamon Nerbonne,
1
-1, ponieważ to nie będzie działać dla wartości takich jak decimal.MaxValue i decimal.MinValue i spowoduje to, że OverflowException. Wierzę, że @Will zapewnia lepszą odpowiedź tutaj stackoverflow.com/a/501165/39532
mezoid
8
Bądź ostrożny, ponieważ Convert.ToInt32i Decimal.ToInt32zachowuj się inaczej. Z MSDN: Decimal.ToInt32- Wartość zwracana jest integralną częścią wartości dziesiętnej; cyfry ułamkowe są obcinane . Convert.ToInt32- Zwracana wartość zaokrąglona do najbliższej 32-bitowej liczby całkowitej ze znakiem. Jeśli wartość znajduje się w połowie odległości między dwiema liczbami całkowitymi, zwracana jest liczba parzysta; to znaczy 4.5 jest konwertowane na 4, a 5.5 jest konwertowane na 6.
vezucci
67

Nie możesz

Oczywiście, że można , jednak int (System.Int32) nie jest wystarczająco duży, aby pomieścić każdą możliwą wartość dziesiętną.

Oznacza to, że jeśli użyjesz miejsca dziesiętnego większego niż int.MaxValue, przepełnisz się, a jeśli miejsce dziesiętne jest mniejsze niż int.MinValue, nastąpi niedopełnienie.

Co dzieje się, gdy nie masz / przepełniasz? Jedna z dwóch rzeczy. Jeśli Twoja kompilacja nie jest zaznaczona (tzn. CLR nie ma znaczenia, jeśli tak zrobisz), aplikacja będzie kontynuowana po przekroczeniu / przekroczeniu wartości, ale wartość int nie będzie zgodna z oczekiwaniami. Może to prowadzić do sporadycznych błędów i może być trudne do naprawienia. Skończysz aplikację w nieznanym stanie, co może spowodować, że aplikacja uszkodzi wszelkie ważne dane, na których działa. Niedobrze.

Jeśli Twój zespół jest sprawdzony (właściwości-> kompilacja-> zaawansowane-> sprawdź arytmetyczne przepełnienie / niedopełnienie lub opcja / sprawdzony kompilator), Twój kod zgłosi wyjątek, gdy nastąpi niedopełnienie / przepełnienie. Jest to prawdopodobnie lepsze niż nie; jednak domyślnie dla zestawów nie jest sprawdzanie przepełnienia / niedopełnienia.

Prawdziwe pytanie brzmi: „co próbujesz zrobić?” Bez znajomości twoich wymagań nikt nie jest w stanie powiedzieć ci, co powinieneś zrobić w tym przypadku, poza oczywistym: NIE RÓB TO.

Jeśli nie przejmujesz się tym, odpowiedzi tutaj są poprawne. Powinieneś jednak przekazać swoje zrozumienie, że może dojść do przepełnienia i że nie ma to znaczenia, zawijając swój rzutowany kod w niezaznaczonym bloku

unchecked
{
  // do your conversions that may underflow/overflow here
}

W ten sposób ludzie za tobą zrozumieją, że cię to nie obchodzi, a jeśli w przyszłości ktoś zmieni twoje kompilacje na / sprawdzone, twój kod nie zepsuje się nieoczekiwanie.

Jeśli wszystko, co chcesz zrobić, to upuścić ułamkową część liczby, pozostawiając część integralną, możesz użyć Math.Truncate.

decimal actual = 10.5M;
decimal expected = 10M;
Assert.AreEqual(expected, Math.Truncate(actual));

źródło
3
Chociaż podejrzewam, że pod maską są takie same, jeśli dane wejściowe są dziesiętne, czuję się bardziej komfortowo stosując Decimal.Truncate niż Math.Truncate, ponieważ ten drugi akceptuje również liczby podwójne i dlatego można zrozumieć, że można obcinać liczby parzyste które nie są bazą 10, w przeciwieństwie do Decimal.Truncate, która jest prawdziwym obcięciem liczby 10 bazowej.
Brian
7
Niezaznaczone konteksty nie mają zastosowania do miejsc po przecinku; operacje na liczbach dziesiętnych spowodują wygenerowanie wyjątków przepełnienia niezależnie.
Dave
46
int i = (int)d;

poda ci liczbę zaokrągloną w dół.

Jeśli chcesz zaokrąglić do najbliższej liczby parzystej (tj.> .5 zaokrągli w górę), możesz użyć

int i = (int)Math.Round(d, MidpointRounding.ToEven);

Ogólnie rzecz biorąc, możesz przesyłać między wszystkimi typami liczbowymi w C #. Jeśli nie ma żadnych informacji, które zostaną utracone podczas przesyłania, możesz to zrobić domyślnie:

int i = 10;
decimal d = i;

choć nadal możesz to zrobić jawnie, jeśli chcesz:

int i = 10;
decimal d = (decimal)i;

Jeśli jednak tracisz informacje za pośrednictwem obsady, musisz to zrobić jawnie (aby pokazać, że masz świadomość, że tracisz informacje):

decimal d = 10.5M;
int i = (int)d;

Tracisz „.5”. Może to być w porządku, ale musisz wyrazić się jasno i rzucić wyraźną obsadę, aby pokazać, że możesz stracić informacje.

ICR
źródło
1
Naprawdę chcesz, aby MidpointRounding.AwayFromZero, jeśli chcesz, aby> * .5 zawsze zaokrąglał w górę na podstawie mojego doświadczenia w wypróbowaniu powyższego kodu, patrząc na przykładowe wyniki tutaj: msdn.microsoft.com/en-us/library/…
Elijah Lofgren
@ElijahLofgren To trochę zależy: Jeśli robisz statystyki, ToEvenpowinno zapobiegać dryfowaniu statystyk. Jeśli jednak operujesz przy użyciu przedmiotów podlegających opłacie lub pieniędzy, AwayFromZerowydaje się to właściwym wyborem.
mbx
22
decimal d = 2;
int i = (int) d;

To powinno działać dobrze.

luiscubal
źródło
Ostrożnie, z wyraźnymi informacjami o konwersji mogą zostać utracone.
Phaedrus
21
Podczas konwersji z miejsca dziesiętnego na całkowite informacje prawie zawsze zostaną utracone, ale myślę, że o to chodzi.
Dinah
8

System.Decimalimplementuje IConvertableinterfejs, który ma ToInt32()członka.

Czy dzwonienie System.Decimal.ToInt32()działa dla Ciebie?

Andy
źródło
2
Z dokumentacji : „Ten interfejs API obsługuje infrastrukturę .NET Framework i nie jest przeznaczony do używania bezpośrednio z kodu”. Dlaczego nie skorzystać z Convert.ToInt32?
H.Wolper
7

Zgrabną sztuczką do szybkiego zaokrąglania jest dodanie .5 przed rzutem dziesiętnym na liczbę całkowitą.

decimal d = 10.1m;
d += .5m;
int i = (int)d;

Wciąż odchodzi i=10, ale

decimal d = 10.5m;
d += .5m;
int i = (int)d;

By zaokrąglić w górę tak, że i=11.

DeadlyBrad42
źródło
5
Po co męczyć się tym, gdy jest Math.Floor i Math.Ceiling?
Badaro,
W tym czasie byłem dość nowy w języku C # iz jakiegoś powodu nie zdawałem sobie sprawy, że te funkcje istnieją. To właściwie sztuczka, której nauczyłem się od C / C ++, która była oczywiście bardziej przydatna.
DeadlyBrad42
1
Co jeśli wartość dziesiętna wynosiła np. -9,3?
supercat
6

Wolę za pomocą Math.round , Math.floor , Math.Ceiling lub Math.Truncate jawnie ustawić tryb zaokrąglania się odpowiednio.

Pamiętaj, że wszystkie zwracają również wartości dziesiętne - ponieważ liczba dziesiętna ma większy zakres wartości niż Int32, więc nadal będziesz musiał rzutować (i sprawdzić przepełnienie / niedopełnienie).

 checked {
   int i = (int)Math.Floor(d);
 }
Mark Brackett
źródło
6

Zaokrąglanie liczby dziesiętnej do najbliższej liczby całkowitej

decimal a ;
int b = (int)(a + 0.5m);

kiedy a = 49.9tob = 50

kiedy a = 49.5tob = 50

kiedy a = 49.4, a następnie b = 49itp.

sleepwalkerfx
źródło
0

Uważam, że operator rzutowania nie działa, jeśli masz dziesiętną ramkę (tj. Wartość dziesiętną wewnątrz typu obiektu). Convert.ToInt32 (dziesiętny jako obiekt) działa dobrze w tym przypadku.

Ta sytuacja pojawia się podczas pobierania wartości IDENTITY / AUTONUMBER z bazy danych:

SqlCommand foo = new SqlCommand("INSERT INTO...; SELECT SCOPE_IDENTITY()", conn);
int ID = Convert.ToInt32(foo.ExecuteScalar());  // works
int ID = (int)foo.ExecuteScalar();              // throws InvalidCastException

Zobacz 4.3.2 Konwersje rozpakowywania

Timbo
źródło
2
Dodanie do niego więcej w celach informacyjnych: to dlatego, że można rozpakować tylko do tego samego typu oryginału. Tutaj SELECT SCOPE_IDENTITY()zwraca, numeric(38, 0)co tłumaczy decimal.NET. foo.ExecuteScalar()zwraca decimalzapakowane w objectktórych nie można rzutować bezpośrednio do int. (int)(decimal)foo.ExecuteScalar()lub Convert.ToInt32(foo.ExecuteScalar())działałby.
rageit
0

Wydaje się, że żadna odpowiedź nie dotyczy OverflowException / UnderflowException, które pochodzą z próby konwersji dziesiętnej, która jest poza zakresem int.

int intValue = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, decimalValue));

To rozwiązanie zwróci maksymalną lub minimalną wartość int, jeśli wartość dziesiętna jest poza zakresem int. Możesz zaokrąglić za pomocą Math.Round, Math.Ceiling lub Math.Floor, gdy wartość znajduje się w zakresie int.

Kapten-N
źródło