Comment convertir une décimale en int en C #?

227

Comment convertir une décimale en int?

Rob Hruska
la source
11
Il serait utile de savoir si vous voulez arrondir à l'entier le plus proche ou simplement supprimer les nombres après la décimale (c.-à-d. Toujours arrondir à la baisse)
Dinah
128
honnêtement, je ne vois pas l'utilité de voter contre des questions authentiques. oui, la réponse pourrait être trouvée sur google MAIS cela n'améliorerait-il pas simplement la qualité du site si les gens arrêtaient de fermer une question sur deux? ce n'est pas comme si cette question était du spam ou quoi que ce soit, et je suis sûr qu'il serait utile pour de nombreux nouveaux arrivants de c #
jay_t55

Réponses:

268

Utilisez Convert.ToInt32de mscorlibcomme

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

Voir MSDN . Vous pouvez également utiliser Decimal.ToInt32. Encore une fois, voir MSDN . Enfin, vous pouvez faire un cast direct comme dans

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

qui utilise l'opérateur de transtypage explicite. Voir MSDN .

Jason
la source
10
Attention: Convert a un comportement surprenant pour certaines conversions ( nullvs. 0vs. ""). Je recommanderais de ne jamais utiliser Convert, sauf si vous avez absolument besoin de sa flexibilité (c'est-à-dire dans des scénarios typés dynamiquement)
Eamon Nerbonne
1
-1 car cela ne fonctionnera pas pour des valeurs telles que decimal.MaxValue et decimal.MinValue et entraîne un OverflowException. Je crois que @Will fournit une meilleure réponse ici stackoverflow.com/a/501165/39532
mezoid
8
Soyez prudent, car Convert.ToInt32et Decimal.ToInt32comportez-vous différemment. À partir de MSDN: Decimal.ToInt32- La valeur de retour fait partie intégrante de la valeur décimale; les chiffres fractionnaires sont tronqués . Convert.ToInt32- Renvoie la valeur arrondie à l'entier signé 32 bits le plus proche. Si la valeur est à mi-chemin entre deux nombres entiers, le nombre pair est renvoyé; c'est-à-dire que 4,5 est converti en 4 et 5,5 est converti en 6.
vezucci
67

Tu ne peux pas.

Bien sûr, vous pourriez , cependant, un int (System.Int32) n'est pas assez grand pour contenir toutes les valeurs décimales possibles.

Cela signifie que si vous transtypez une décimale plus grande que int.MaxValue, vous déborderez et si la décimale est plus petite que int.MinValue, elle dépassera.

Que se passe-t-il lorsque vous débordez / débordez? Une des deux choses. Si votre build n'est pas coché (c'est-à-dire que le CLR s'en fiche si vous le faites), votre application continuera après la valeur over / underflows, mais la valeur dans l'int ne sera pas celle que vous attendiez. Cela peut entraîner des bogues intermittents et peut être difficile à corriger. Vous finirez votre application dans un état inconnu, ce qui peut entraîner la corruption de votre application, quelles que soient les données importantes sur lesquelles elle travaille. Pas bon.

Si votre assemblage est vérifié (propriétés-> build-> avancé-> vérifier le dépassement / sous-dépassement arithmétique ou l'option de compilateur / vérifié), votre code lèvera une exception lorsqu'un sous-dépassement / dépassement se produira. C'est probablement mieux qu'improbable; cependant, la valeur par défaut pour les assemblages n'est pas de vérifier les débordements / débordements.

La vraie question est "qu'essayez-vous de faire?" Sans connaître vos besoins, personne ne peut vous dire ce que vous devez faire dans ce cas, autre que l'évidence: NE PAS FAIRE.

Si vous ne vous souciez pas spécifiquement, les réponses ici sont valides. Cependant, vous devez communiquer votre compréhension qu'un débordement peut se produire et que cela n'a pas d'importance en enveloppant votre code de distribution dans un bloc non contrôlé

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

De cette façon, les gens qui vous suivent comprennent que vous ne vous souciez pas, et si à l'avenir quelqu'un change vos versions en / vérifié, votre code ne se cassera pas de manière inattendue.

Si tout ce que vous voulez faire est de supprimer la partie fractionnaire du nombre, en laissant la partie intégrale, vous pouvez utiliser Math.Truncate.

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

la source
3
Bien que je soupçonne que c'est la même chose sous le capot si l'entrée est une décimale, je me sens plus à l'aise avec Decimal.Truncate que Math.Truncate, car ce dernier accepte également les doubles et peut donc être compris pour pouvoir tronquer les nombres pairs qui ne sont pas en base 10, par opposition à Decimal.Truncate, qui est une vraie troncature d'un nombre en base 10.
Brian
7
Les contextes non contrôlés ne s'appliquent pas aux décimales; les opérations sur les décimales lèveront malgré tout OverflowExceptions.
Dave
46
int i = (int)d;

vous donnera le nombre arrondi.

Si vous voulez arrondir au nombre pair le plus proche (c'est-à-dire> .5 arrondira), vous pouvez utiliser

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

En général, vous pouvez effectuer un cast entre tous les types numériques en C #. S'il n'y a aucune information qui sera perdue pendant la distribution, vous pouvez le faire implicitement:

int i = 10;
decimal d = i;

mais vous pouvez toujours le faire explicitement si vous le souhaitez:

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

Cependant, si vous allez perdre des informations via le casting, vous devez le faire explicitement (pour montrer que vous êtes conscient que vous risquez de perdre des informations):

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

Ici, vous perdez le ".5". Cela peut être bien, mais vous devez être explicite à ce sujet et faire un casting explicite pour montrer que vous savez que vous perdez peut-être les informations.

ICR
la source
1
Vous voulez réellement MidpointRounding.AwayFromZero si vous voulez> * .5 pour toujours arrondir en fonction de mon expérience en essayant le code ci-dessus en regardant un exemple de sortie ici: msdn.microsoft.com/en-us/library/…
Elijah Lofgren
@ElijahLofgren Cela dépend un peu: si vous faites des statistiques, cela ToEvendevrait empêcher la dérive des statistiques. Si vous opérez cependant avec des articles payants ou de l'argent, cela AwayFromZerosemble être le bon choix.
mbx
22
decimal d = 2;
int i = (int) d;

Cela devrait très bien fonctionner.

luiscubal
la source
Attention, avec une conversion explicite, les informations peuvent être perdues.
Phaedrus
21
Lors de la conversion de décimal en int, les informations seront presque toujours perdues, mais je pense que c'est un peu le point.
Dinah
8

System.Decimalimplémente l' IConvertableinterface, qui a un ToInt32()membre.

L'appel System.Decimal.ToInt32()vous convient-il?

Andy
la source
2
D'après la documentation : "Cette API prend en charge l'infrastructure .NET Framework et n'est pas destinée à être utilisée directement à partir de votre code". Pourquoi ne pas utiliser Convert.ToInt32?
H.Wolper
7

Une astuce intéressante pour un arrondi rapide consiste à ajouter 0,5 avant de convertir votre décimale en entier.

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

Part toujours i=10, mais

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

Arrondirait ainsi i=11.

DeadlyBrad42
la source
5
Pourquoi s'embêter à faire ça quand il y a Math.Floor et Math.Ceiling?
Badaro
À l'époque, j'étais relativement nouveau en C # et pour une raison quelconque, je ne savais pas que ces fonctions existaient. C'est en fait une astuce que j'ai apprise en C / C ++, où c'était évidemment plus utile.
DeadlyBrad42
1
Et si la valeur décimale était par exemple -9,3?
supercat
6

Je préfère utiliser Math.Round , Math.Floor , Math.Ceiling ou Math.Truncate pour définir explicitement le mode d'arrondi comme il convient.

Notez qu'ils renvoient tous également Decimal - puisque Decimal a une plus grande plage de valeurs qu'un Int32, vous devrez donc toujours caster (et vérifier le débordement / le débordement).

 checked {
   int i = (int)Math.Floor(d);
 }
Mark Brackett
la source
6

Arrondir une décimale à l'entier le plus proche

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

quand a = 49.9, alorsb = 50

quand a = 49.5, alorsb = 50

quand a = 49.4, alors b = 49etc.

somnambule
la source
0

Je trouve que l'opérateur de casting ne fonctionne pas si vous avez une décimale encadrée (c'est-à-dire une valeur décimale à l'intérieur d'un type d'objet). Convert.ToInt32 (décimal en tant qu'objet) fonctionne correctement dans ce cas.

Cette situation se produit lors de la récupération des valeurs IDENTITY / AUTONUMBER de la base de données:

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

Voir 4.3.2 Unboxing conversions

Timbo
la source
2
En ajouter plus pour référence: c'est parce que vous ne pouvez décompresser que le même type d'origine. Voici les SELECT SCOPE_IDENTITY()retours numeric(38, 0)qui se traduisent decimalpar .NET. foo.ExecuteScalar()renvoie un cadre decimalcomme objectqui ne peut pas être converti directement en un int. (int)(decimal)foo.ExecuteScalar()ou Convert.ToInt32(foo.ExecuteScalar())fonctionnerait.
rageit
0

Aucune réponse ne semble traiter de l'OverflowException / UnderflowException qui vient d'essayer de convertir une décimale qui est en dehors de la plage d'int.

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

Cette solution renverra la valeur int maximale ou minimale possible si la valeur décimale est en dehors de la plage int. Vous voudrez peut-être ajouter un arrondi avec Math.Round, Math.Ceiling ou Math.Floor lorsque la valeur se trouve dans la plage int.

Kapten-N
la source