Puis-je convertir long en int?

142

Je veux convertir longà int.

Si la valeur de long> int.MaxValue, je suis heureux de la laisser s'enrouler.

Quel est le meilleur moyen?

en dépit
la source

Réponses:

218

Fais juste (int)myLongValue. Il fera exactement ce que vous voulez (en supprimant les MSB et en prenant des LSB) en uncheckedcontexte (ce qui est la valeur par défaut du compilateur). Cela mettra OverflowExceptionen checkedcontexte si la valeur ne rentre pas dans un int:

int myIntValue = unchecked((int)myLongValue);
Mehrdad Afshari
la source
15
Pour tous ceux qui ont posé la même question que moi: notez que la suppression des MSB peut avoir un effet sur le signe du résultat. Avec ce qui précède, myIntValuepeut finir négatif quand myLongValueest positif ( 4294967294 => -2) et vice-versa ( -4294967296 => 0). Ainsi, lors de l'implémentation d'une CompareToopération, par exemple, vous ne pouvez pas convertir le résultat de la soustraction longde l'un à l'autre en un intet le renvoyer; pour certaines valeurs, votre comparaison donnerait un résultat incorrect.
TJ Crowder
21
@Chris: new Random()utilise Environment.TickCountsous le capot; pas besoin de semer manuellement avec des tics d'horloge.
Mehrdad Afshari
@MehrdadAfshari a-t-il toujours été le cas?
Chris Marisic
3
Même si c'était il y a des années, la raison pour laquelle je l'ai utilisé dans le nouveau Random était que j'obtenais exactement les mêmes résultats dans un test unitaire et que je voulais une variance. L'utilisation du nombre m'a donné une variance.
Chris Marisic
3
Le contexte par défaut est uncheckeddonc, à moins que vous ne l'ayez explicitement modifié, le uncheckedmot - clé (comme indiqué dans cette réponse et le commentaire de @ ChrisMarisic, etc.) n'est pas nécessaire et int myIntValue = (int)myLongValueest exactement équivalent. Cependant , ne note que peu importe si vous utilisez le uncheckedmot - clé ou non, vous obtenez le comportement de troncature grossier non-mathématique décrit par @TJCrowder où le signe peut retourner dans certains cas de débordement. La seule façon de vraiment garantir l'exactitude mathématique est d'utiliser le checked(...)contexte, où ces cas lèveront une exception.
Glenn Slayden le
35
Convert.ToInt32(myValue);

Bien que je ne sache pas ce qu'il fera quand il est supérieur à int.MaxValue.

Max Schmeling
la source
42
"Bien que je ne sache pas ce qu'il fera quand il sera supérieur à int.MaxValue" Il lancera un OverflowException, ce qui est exactement ce que l'OP ne veut pas: msdn.microsoft.com/en-us/library/d4haekc4.aspx
TJ Crowder
4
Testez si myValue> Integer.Max avant d'exécuter la conversion, si vous devez effectuer un autre traitement lorsque myValue> Integer.Max. Convert.ToInt32 (myValue) débordera (sans exception, je crois) sinon. Cette méthode fonctionne également dans VB.NET.
TamusJRoyce
3
Alors que (int) est valide, Convert est une meilleure réponse. Mieux vaut avoir des exceptions étranges que des données étranges.
Richard juin
1
@RichardJune Euh, non? L'OP ici dit explicitement : " Si la valeur de long> int.MaxValue, je suis heureux de la laisser s'enrouler. " Je peux voir argumenter votre déclaration en général, mais dans ce cas précis , non, ce Convertn'est pas bon.
ruffin
if (value > Int32.MaxValue) return Int32.MaxValue; else return Convert.ToInt32( value );
Sergey
15

Parfois, vous n'êtes pas vraiment intéressé par la valeur réelle, mais par son utilisation comme somme de contrôle / hashcode . Dans ce cas, la méthode intégrée GetHashCode()est un bon choix:

int checkSumAsInt32 = checkSumAsIn64.GetHashCode();
realbart
la source
7
Cela fait un moment que cette réponse a été donnée, même si je tiens à mentionner que l'implémentation du hashcode peut différer entre les versions .NET. Cela ne se produit peut-être pas réellement, mais il n'y a aucune garantie que cette valeur soit la même entre les différentes exécutions d'applications / domaines d'application.
Caramiriel
1
Pour ajouter à ce que dit @Caramiriel: si vous l'utilisez comme hashcode temporaire , lors de votre session d'application actuelle, alors GetHashCodec'est un choix approprié. Si vous recherchez une somme de contrôle persistante - une valeur qui sera la même lorsque vous exécuterez votre application plus tard, ne l'utilisez pas GetHashCode, car il n'est pas garanti que ce soit le même algorithme pour toujours.
ToolmakerSteve
9

Le moyen le plus sûr et le plus rapide est d'utiliser le masquage de bits avant de lancer ...

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

La valeur Bit Mask ( 0xFFFFFFFF) dépendra de la taille de Int car la taille Int dépend de la machine.

Mashake
la source
Vous devez décider de ce que vous voulez faire lorsque le résultat débordera ou deviendra un nombre négatif. Ce que vous montrez va encore déborder, IIRC, car vous laissez passer le signe. [Comme mentionné dans une autre réponse, dans le uncheckedcontexte, vous n'obtiendrez pas de débordement - mais vous n'avez pas besoin de vous masquer uncheckedpour éviter le débordement, donc une solution n'est nécessaire que dans le checkedcontexte.] Exemple pour 16 bits. Signé 16 bits détient (-32768, 32767). Le masquage avec 0xFFFF permet une valeur jusqu'à 65535, provoquant un débordement, IIRC. Pourrait masquer pour éviter le bit de signe, 0x7FFF ou 0x7FFFFFFF, si vous voulez seulement positif.
ToolmakerSteve
1

Il peut convertir en

Méthode Convert.ToInt32

Mais il lèvera une OverflowException si la valeur est en dehors de la plage du type Int32. Un test de base nous montrera comment cela fonctionne:

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.

Ici, il y a une explication plus longue.

nzrytmn
la source
0

Ne serait pas

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

être la bonne manière, mathématiquement parlant?

Rémy Esmery
la source
Cela bloquerait le longValueplus proche représentable intsi la valeur d'origine est trop grande. Mais il lui manque le même traitement des entrées trop négatives, qui perdraient à la place les bits les plus significatifs; vous auriez besoin de comparer Int32.MinValueaussi. L'affiche originale ne semblait pas vouloir de serrage, cependant.
Jeppe Stig Nielsen
À mon humble avis parfois préférable d'obtenir exception que la valeur erronée qui Int32.MaxValue serait ...
G. Goncharov
0

La solution suivante sera tronquée à int.MinValue / int.MaxValue si la valeur est en dehors des limites Integer.

myLong < int.MinValue ? int.MinValue : (myLong > int.MaxValue ? int.MaxValue : (int)myLong)
Clément
la source
0

Un moyen possible consiste à utiliser l'opérateur modulo pour laisser uniquement les valeurs rester dans la plage int32, puis à les convertir en int.

var intValue= (int)(longValue % Int32.MaxValue);
André
la source