Wie konvertiere ich eine Dezimalstelle in ein Int in C #?


227

Wie konvertiere ich eine Dezimalstelle in eine Int?


11
Es wäre hilfreich zu wissen, ob Sie auf das nächste int runden oder nur die Zahlen nach der Dezimalstelle fallen lassen möchten (dh: immer abrunden)
Dinah

128
Ich sehe ehrlich gesagt keinen Sinn darin, echte Fragen herunterzustimmen. Ja, die Antwort könnte auf Google gefunden werden, aber würde es nicht einfach die Qualität der Website verbessern, wenn die Leute aufhören würden, jede zweite Frage zu schließen? Es ist nicht so, dass diese Frage Spam oder so ist, und ich bin sicher, dass es für viele
Neulinge

Antworten:


268

Verwenden Sie Convert.ToInt32von mscorlibwie in

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

Siehe MSDN . Sie können auch verwenden Decimal.ToInt32. Siehe auch MSDN . Schließlich können Sie eine direkte Besetzung wie in machen

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

welches den expliziten Besetzungsoperator verwendet. Siehe MSDN .


10
Achtung: Convert hat ein überraschendes Verhalten für bestimmte Conversions ( nullvs. 0vs. ""). Ich würde empfehlen, Convert niemals zu verwenden, es sei denn, Sie benötigen unbedingt seine Flexibilität (dh in dynamisch typisierten Szenarien)
Eamon Nerbonne

1
-1, da dies für Werte wie decimal.MaxValue und decimal.MinValue nicht funktioniert und zu einem führt OverflowException. Ich glaube, dass @Will hier eine bessere Antwort bietet stackoverflow.com/a/501165/39532
Mezoid

8
Sei vorsichtig, denn Convert.ToInt32und Decimal.ToInt32verhalte dich anders. Von MSDN: Decimal.ToInt32- Der Rückgabewert ist der integrale Bestandteil des Dezimalwerts; Bruchziffern werden abgeschnitten . Convert.ToInt32- Rückgabewert auf die nächste 32-Bit-Ganzzahl mit Vorzeichen gerundet . Wenn der Wert auf halbem Weg zwischen zwei ganzen Zahlen liegt, wird die gerade Zahl zurückgegeben. Das heißt, 4.5 wird in 4 und 5.5 in 6 konvertiert.
vezucci

67

Das kannst du nicht.

Natürlich könnten Sie das , aber ein int (System.Int32) ist nicht groß genug, um jeden möglichen Dezimalwert aufzunehmen.

Das heißt, wenn Sie eine Dezimalstelle umwandeln, die größer als int.MaxValue ist, wird sie überlaufen, und wenn die Dezimalstelle kleiner als int.MinValue ist, wird sie unterlaufen.

Was passiert, wenn Sie unter / überlaufen? Eines von zwei Dingen. Wenn Ihr Build deaktiviert ist (dh die CLR kümmert sich nicht darum, wenn Sie dies tun), wird Ihre Anwendung nach dem Über- / Unterlauf des Werts fortgesetzt, aber der Wert im int entspricht nicht Ihren Erwartungen. Dies kann zu zeitweiligen Fehlern führen und ist möglicherweise schwer zu beheben. Ihre Anwendung befindet sich in einem unbekannten Zustand, was dazu führen kann, dass Ihre Anwendung alle wichtigen Daten beschädigt, an denen sie arbeitet. Nicht gut.

Wenn Ihre Assembly aktiviert ist (Eigenschaften-> Build-> Erweitert-> Auf arithmetischen Überlauf / Unterlauf prüfen oder die Compileroption / geprüft), löst Ihr Code eine Ausnahme aus, wenn ein Unter- / Überlauf auftritt. Das ist wahrscheinlich besser als nicht; Die Standardeinstellung für Baugruppen ist jedoch nicht die Überprüfung auf Über- / Unterlauf.

Die eigentliche Frage ist: "Was versuchst du zu tun?" Ohne Ihre Anforderungen zu kennen, kann Ihnen niemand sagen, was Sie in diesem Fall tun sollen , außer dem Offensichtlichen: TUN SIE ES NICHT.

Wenn Sie sich speziell NICHT darum kümmern, sind die Antworten hier gültig. Sie sollten jedoch Ihr Verständnis darüber kommunizieren , dass ein Überlauf auftreten kann und dass dies keine Rolle spielt, indem Sie Ihren Cast-Code in einen ungeprüften Block einschließen

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

Auf diese Weise verstehen die Leute, die hinter Ihnen stehen, dass es Ihnen egal ist, und wenn in Zukunft jemand Ihre Builds ändert / überprüft, wird Ihr Code nicht unerwartet kaputt gehen.

Wenn Sie nur den Bruchteil der Zahl löschen und den integralen Teil belassen möchten, können Sie Math.Truncate verwenden.

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

3
Obwohl ich vermute, dass sie unter der Haube dasselbe sind, wenn die Eingabe eine Dezimalzahl ist, fühle ich mich mit Decimal.Truncate wohler als mit Math.Truncate, da letzteres auch Doubles akzeptiert und daher so verstanden werden kann, dass gerade Zahlen abgeschnitten werden können das sind nicht Basis 10, im Gegensatz zu Decimal.Truncate, was eine echte Kürzung einer Basis 10-Zahl ist.
Brian

7
Nicht aktivierte Kontexte gelten nicht für Dezimalstellen. Operationen mit Dezimalstellen lösen unabhängig davon OverflowExceptions aus.
Dave

46
int i = (int)d;

gibt Ihnen die abgerundete Zahl.

Wenn Sie auf die nächste gerade Zahl runden möchten (dh> .5 wird aufgerundet), können Sie verwenden

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

Im Allgemeinen können Sie zwischen allen numerischen Typen in C # wechseln. Wenn während der Besetzung keine Informationen verloren gehen, können Sie dies implizit tun:

int i = 10;
decimal d = i;

Sie können dies jedoch trotzdem explizit tun, wenn Sie dies wünschen:

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

Wenn Sie jedoch Informationen durch die Besetzung verlieren möchten, müssen Sie dies explizit tun (um zu zeigen, dass Sie sich bewusst sind, dass Sie möglicherweise Informationen verlieren):

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

Hier verlieren Sie die ".5". Dies mag in Ordnung sein, aber Sie müssen dies explizit angeben und eine explizite Besetzung vornehmen, um zu zeigen, dass Sie möglicherweise die Informationen verlieren.


1
Sie möchten tatsächlich, dass MidpointRounding.AwayFromZero immer * * .5 aufgerundet wird
Elijah Lofgren

@ElijahLofgren Es kommt irgendwie darauf an: Wenn Sie Statistiken erstellen, ToEvensollten Sie statistische Abweichungen verhindern. Wenn Sie jedoch mit kostenpflichtigen Gegenständen oder Geld arbeiten, AwayFromZeroscheint dies die richtige Wahl zu sein.
mbx

22
decimal d = 2;
int i = (int) d;

Dies sollte gut funktionieren.


Vorsicht, bei einer expliziten Konvertierung können Informationen verloren gehen.
Phaedrus

21
Bei der Konvertierung von Dezimal nach Int gehen Informationen fast immer verloren, aber ich glaube, das ist irgendwie der Punkt.
Dinah


8

System.Decimalimplementiert die IConvertableSchnittstelle, die ein ToInt32()Mitglied hat.

Funktioniert das Anrufen System.Decimal.ToInt32()für Sie?


2
Aus der Dokumentation : "Diese API unterstützt die .NET Framework-Infrastruktur und ist nicht für die direkte Verwendung in Code vorgesehen." Warum nicht Convert.ToInt32 verwenden?
H. Wolper

7

Ein guter Trick für eine schnelle Rundung besteht darin, 0,5 hinzuzufügen, bevor Sie Ihre Dezimalstelle in ein Int umwandeln.

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

Geht noch i=10, aber

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

Würde so aufrunden i=11.


5
Warum sich die Mühe machen, wenn es Math.Floor und Math.Ceiling gibt?
Badaro

Zu dieser Zeit war ich ziemlich neu in C # und aus irgendeinem Grund wusste ich nicht, dass diese Funktionen existieren. Es ist eigentlich ein Trick, den ich aus C / C ++ gelernt habe, wo er offensichtlich nützlicher war.
DeadlyBrad42

1
Was ist, wenn der Dezimalwert zB -9,3 war?
Supercat

6

Ich bevorzuge die Verwendung von Math.Round , Math.Floor , Math.Ceiling oder Math.Truncate , um den Rundungsmodus explizit entsprechend festzulegen .

Beachten Sie, dass alle auch Decimal zurückgeben - da Decimal einen größeren Wertebereich als ein Int32 hat, müssen Sie dennoch umwandeln (und auf Überlauf / Unterlauf prüfen).

 checked {
   int i = (int)Math.Floor(d);
 }


6

Runden einer Dezimalstelle auf die nächste Ganzzahl

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

wann a = 49.9dannb = 50

wann a = 49.5dannb = 50

wann a = 49.4, dann b = 49etc.


0

Ich finde, dass der Casting-Operator nicht funktioniert, wenn Sie eine Box-Dezimalstelle haben (dh einen Dezimalwert innerhalb eines Objekttyps). Convert.ToInt32 (dezimal als Objekt) funktioniert in diesem Fall einwandfrei.

Diese Situation tritt auf, wenn IDENTITY / AUTONUMBER-Werte aus der Datenbank abgerufen werden:

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

Siehe 4.3.2 Unboxing-Konvertierungen


2
Hinzufügen von mehr als Referenz: Dies liegt daran, dass Sie nur den gleichen Originaltyp entpacken können. Hier wird SELECT SCOPE_IDENTITY()zurückgegeben, numeric(38, 0)was decimalvon .NET übersetzt wird. foo.ExecuteScalar()Gibt eine decimalBox zurück, objectdie nicht direkt in eine umgewandelt werden kann int. (int)(decimal)foo.ExecuteScalar()oder Convert.ToInt32(foo.ExecuteScalar())würde funktionieren.
Rageit

0

Keine Antwort scheint sich mit der OverflowException / UnderflowException zu befassen, die beim Versuch entsteht, eine Dezimalstelle zu konvertieren, die außerhalb des Bereichs von int liegt.

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

Diese Lösung gibt den maximal möglichen oder minimalen int-Wert zurück, wenn der Dezimalwert außerhalb des int-Bereichs liegt. Möglicherweise möchten Sie mit Math.Round, Math.Ceiling oder Math.Floor eine Rundung hinzufügen, wenn der Wert innerhalb des int-Bereichs liegt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.