Kann ich lange in int konvertieren?

142

Ich möchte konvertieren longzu int.

Wenn der Wert long> ist int.MaxValue, lasse ich ihn gerne herumlaufen.

Was ist der beste Weg?

trotz
quelle

Antworten:

218

Tu es einfach (int)myLongValue. Es wird genau das tun, was Sie wollen (MSBs verwerfen und LSBs nehmen) im uncheckedKontext (dies ist die Standardeinstellung des Compilers). Es wird OverflowExceptionin den checkedKontext geworfen, wenn der Wert nicht in Folgendes passt int:

int myIntValue = unchecked((int)myLongValue);
Mehrdad Afshari
quelle
15
Für alle anderen, die dieselbe Frage hatten wie ich: Beachten Sie, dass das Verwerfen der MSBs Auswirkungen auf das Vorzeichen des Ergebnisses haben kann. Mit dem oben genannten myIntValuekann negativ enden, wenn myLongValuepositiv ( 4294967294 => -2) ist und umgekehrt ( -4294967296 => 0). Wenn Sie beispielsweise eine CompareToOperation implementieren , können Sie das Ergebnis der Subtraktion longvon einer Operation nicht glücklich in eine intumwandeln und diese zurückgeben. Bei einigen Werten würde Ihr Vergleich zu einem falschen Ergebnis führen.
TJ Crowder
21
@ Chris: new Random()verwendet Environment.TickCountunter der Haube; Keine Notwendigkeit, manuell mit Uhrzecken zu säen.
Mehrdad Afshari
@MehrdadAfshari war das schon immer so?
Chris Marisic
3
Obwohl dies vor Jahren war, war der Grund, warum ich es in New Random verwendet habe, dass ich in einem Unit-Test genau die gleichen Ergebnisse erzielte und Varianz wollte. Die Verwendung der Nummer gab mir Varianz.
Chris Marisic
3
Der Standardkontext ist. Wenn uncheckedSie ihn nicht explizit geändert haben, wird das uncheckedSchlüsselwort (wie in dieser Antwort und im Kommentar von @ ChrisMarisic usw. gezeigt) nicht benötigt und int myIntValue = (int)myLongValueist genau gleichwertig. Beachten Sie jedoch, dass unabhängig davon, ob Sie das uncheckedSchlüsselwort verwenden oder nicht, das von @TJCrowder beschriebene nicht-mathematische Verhalten beim unhöflichen Abschneiden angezeigt wird, bei dem das Vorzeichen in einigen Überlauffällen umdrehen kann. Die einzige Möglichkeit, die mathematische Korrektheit wirklich sicherzustellen, besteht darin, den checked(...)Kontext zu verwenden, in dem diese Fälle eine Ausnahme auslösen.
Glenn Slayden
35
Convert.ToInt32(myValue);

Obwohl ich nicht weiß, was es tun wird, wenn es größer als int.MaxValue ist.

Max Schmeling
quelle
42
"Obwohl ich nicht weiß, was es tun wird, wenn es größer als int.MaxValue ist" Es wird ein ausgelöstOverflowException , was genau das ist, was das OP nicht will: msdn.microsoft.com/en-us/library/d4haekc4.aspx
TJ Crowder
4
Testen Sie vor dem Ausführen der Konvertierung, ob myValue> Integer.Max ist, wenn Sie bei myValue> Integer.Max eine andere Verarbeitung durchführen müssen. Convert.ToInt32 (myValue) läuft sonst über (keine Ausnahme, glaube ich). Diese Methode funktioniert auch in VB.NET.
TamusJRoyce
3
Während (int) gültig ist, ist Konvertieren eine bessere Antwort. Besser seltsame Ausnahmen als seltsame Daten.
Richard Juni
1
@ RichardJune Ähm, nein? Das OP hier sagt ausdrücklich : " Wenn der Wert von long> int.MaxValue ist, lasse ich ihn gerne umlaufen. " Ich kann sehen, dass Ihre Aussage im Allgemeinen argumentiert, aber in diesem speziellen Fall ist nein Convertnicht gut.
Ruffin
if (value > Int32.MaxValue) return Int32.MaxValue; else return Convert.ToInt32( value );
Sergey
15

Manchmal interessiert Sie der tatsächliche Wert nicht wirklich, sondern seine Verwendung als Prüfsumme / Hashcode . In diesem Fall ist die integrierte Methode GetHashCode()eine gute Wahl:

int checkSumAsInt32 = checkSumAsIn64.GetHashCode();
Realbart
quelle
7
Es ist schon eine Weile her, seit diese Antwort gegeben wurde, obwohl ich erwähnen möchte, dass die Hashcode-Implementierung zwischen .NET-Versionen unterschiedlich sein kann. Dies ist möglicherweise nicht der Fall, es gibt jedoch keine Garantie dafür, dass dieser Wert zwischen verschiedenen Anwendungsläufen / Anwendungsdomänen gleich ist.
Caramiriel
1
Um das zu ergänzen, was @Caramiriel sagt: Wenn Sie es während Ihrer aktuellen App-Sitzung als temporären Hashcode verwenden, GetHashCodeist dies eine geeignete Wahl. Wenn Sie nach einer dauerhaften Prüfsumme suchen - ein Wert, der beim späteren Ausführen Ihrer App gleich bleibt, verwenden Sie ihn nicht GetHashCode, da nicht garantiert wird, dass er für immer derselbe Algorithmus ist.
ToolmakerSteve
9

Der sicherste und schnellste Weg ist die Verwendung der Bitmaskierung vor dem Wirken ...

int MyInt = (int) ( MyLong & 0xFFFFFFFF )

Der 0xFFFFFFFFWert für Bit Mask ( ) hängt von der Größe von Int ab, da die Größe von Int von der Maschine abhängt.

Mashake
quelle
Sie müssen entscheiden, was passieren soll, wenn das Ergebnis entweder überläuft oder eine negative Zahl wird. Was Sie zeigen, wird immer noch überlaufen, IIRC, weil Sie das Zeichen durchbrechen lassen. [Wie in einer anderen Antwort erwähnt, erhalten Sie im uncheckedKontext keinen Überlauf - Sie müssen sich jedoch nicht maskieren unchecked, um den Überlauf zu vermeiden. Daher wird eine Lösung nur im checkedKontext benötigt .] Beispiel für 16-Bit. Vorzeichenbehaftete 16-Bit-Holds (-32768, 32767). Das Maskieren mit 0xFFFF ermöglicht einen Wert von bis zu 65535, was zu einem Überlauf (IIRC) führt. Könnte maskieren, um Vorzeichenbit, 0x7FFF oder 0x7FFFFFFF zu vermeiden, wenn nur positiv gewünscht wird.
ToolmakerSteve
1

Es kann konvertieren durch

Convert.ToInt32-Methode

Es wird jedoch eine OverflowException ausgelöst, wenn der Wert außerhalb des Bereichs des Int32-Typs liegt. Ein grundlegender Test zeigt uns, wie es funktioniert:

long[] numbers = { Int64.MinValue, -1, 0, 121, 340, Int64.MaxValue };
int result;
foreach (long number in numbers)
{
   try {
         result = Convert.ToInt32(number);
        Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
                    number.GetType().Name, number,
                    result.GetType().Name, result);
     }
     catch (OverflowException) {
      Console.WriteLine("The {0} value {1} is outside the range of the Int32 type.",
                    number.GetType().Name, number);
     }
}
// The example displays the following output:
//    The Int64 value -9223372036854775808 is outside the range of the Int32 type.
//    Converted the Int64 value -1 to the Int32 value -1.
//    Converted the Int64 value 0 to the Int32 value 0.
//    Converted the Int64 value 121 to the Int32 value 121.
//    Converted the Int64 value 340 to the Int32 value 340.
//    The Int64 value 9223372036854775807 is outside the range of the Int32 type.

Hier gibt es eine längere Erklärung.

nzrytmn
quelle
0

Würde nicht

(int) Math.Min(Int32.MaxValue, longValue)

mathematisch gesehen der richtige Weg sein?

Rémy Esmery
quelle
Dies würde das auf das nächste darstellbare Element klemmenlongValue , intwenn der ursprüngliche Wert zu groß ist. Es fehlt jedoch die gleiche Behandlung von zu negativen Eingaben, die stattdessen die höchstwertigen Bits verlieren würden. Sie müssten auch mit vergleichen Int32.MinValue. Das Originalplakat schien jedoch keine Klemmung zu wollen.
Jeppe Stig Nielsen
IMHO ist es manchmal besser, eine Ausnahme als einen falschen Wert zu bekommen, der Int32.MaxValue wäre ...
G. Goncharov
0

Die folgende Lösung wird auf int.MinValue / int.MaxValue abgeschnitten, wenn der Wert außerhalb der Ganzzahlgrenzen liegt.

myLong < int.MinValue ? int.MinValue : (myLong > int.MaxValue ? int.MaxValue : (int)myLong)
Clement
quelle
0

Eine Möglichkeit besteht darin, den Modulo-Operator zu verwenden, um nur die Werte im int32-Bereich zu belassen, und ihn dann in int umzuwandeln.

var intValue= (int)(longValue % Int32.MaxValue);
Andre
quelle