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


227

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


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 .


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));

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.


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.


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?


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.


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);
 }


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.


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


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.