Meilleur moyen d'obtenir une partie entière d'un nombre décimal


89

Quelle est la meilleure façon de renvoyer la partie entière d'un nombre décimal (en c #)? (Cela doit fonctionner pour de très grands nombres qui peuvent ne pas rentrer dans un int).

GetIntPart(343564564.4342) >> 343564564
GetIntPart(-323489.32) >> -323489
GetIntPart(324) >> 324

Le but de ceci est: J'insère dans un champ décimal (30,4) dans la base de données, et je veux m'assurer que je n'essaye pas d'insérer un nombre trop long pour le champ. La détermination de la longueur de la partie entière du nombre décimal fait partie de cette opération.


Vous ne pouvez pas obtenir la partie int; vous pouvez obtenir la partie numérique entière et abandonner la partie fractionnaire. La partie entière d'un nombre décimal peut facilement déborder d'un int et soit jeter ou envelopper, tuant silencieusement votre code.

1
Eh bien, c'est pourquoi cette question n'est pas aussi simple qu'il y paraît. J'ai besoin que cela fonctionne pour de très grands nombres de manière aussi fiable que pour de petits nombres. Cependant, "nombre entier" est plus précis que "int" - je vais reformuler ci-dessus.
Yaakov Ellis

Réponses:


212

Au fait les gars, (int) Decimal.MaxValue débordera. Vous ne pouvez pas obtenir la partie "int" d'une décimale parce que la décimale est trop grande pour être placée dans la zone int. Je viens de vérifier ... c'est encore trop gros pendant longtemps (Int64).

Si vous voulez le bit d'une valeur décimale à GAUCHE du point, vous devez faire ceci:

Math.Truncate(number)

et renvoyez la valeur comme ... UN DECIMAL ou un DOUBLE.

edit: Tronquer est définitivement la bonne fonction!


Donc le résultat est décimal ou double qui n'aura jamais rien après le point mais il n'y a pas d'objet intégré pour stocker le résultat comme un "int" (sans décimales) qui semble un peu boiteux?
Coops

@CodeBlend: Il n'y a pas beaucoup d'appels à concevoir des frameworks autour d'un désir de perdre en précision.

@CodeBlend: Vous perdriez encore de la précision parce que vous coupez les valeurs décimales d'un nombre. Je ne sais pas à quoi vous voulez en venir.

Pas sûr que cela fonctionnera ou non. Parce que Math.Truncate (-5.99999999999999999) renvoie -6.0 pour moi ... !!
Bharat Mori

@Bharat Mori: Il semble que -5,99999999999999999 soit arrondi à -6,0 avant le tronçon. Essayez avec le suffixe "m" et cela fonctionnera. Math.Truncate (-5,99999999999999999m) donne -5.
Henry


4

Cela dépend de ce que vous faites.

Par exemple:

//bankers' rounding - midpoint goes to nearest even
GetIntPart(2.5) >> 2
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -6

ou

//arithmetic rounding - midpoint goes away from zero
GetIntPart(2.5) >> 3
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -7

La valeur par défaut est toujours la première, ce qui peut être une surprise mais qui est très logique .

Votre distribution explicite fera:

int intPart = (int)343564564.5
// intPart will be 343564564

int intPart = (int)343564565.5
// intPart will be 343564566

D'après la façon dont vous avez formulé la question, il semble que ce n'est pas ce que vous voulez - vous voulez la poser à chaque fois.

Je ferais:

Math.Floor(Math.Abs(number));

Vérifiez également la taille de votre decimal- ils peuvent être assez gros, vous devrez peut-être utiliser un fichier long.


(long) Decimal.MaxValue déborde.

Bon point - Je suppose que c'est pourquoi Math.Truncate (décimal) renvoie décimal.
Keith

En C #, la conversion en int ne s'arrondit pas, donc (int) 0.6f sera 0, et (int) 343564565.5 se terminera par 5, pas 6. Essayez ici: repl.it/repls/LuxuriousCheerfulDistributeddatabase
sschmidTU

0

Il vous suffit de le lancer, en tant que tel:

int intPart = (int)343564564.4342

Si vous souhaitez toujours l'utiliser comme décimal dans les calculs ultérieurs, alors Math.Truncate (ou éventuellement Math.Floor si vous voulez un certain comportement pour les nombres négatifs) est la fonction souhaitée.


5
C'est faux faux faux. Si le résultat est supérieur à ce qu'un Int32 peut contenir, il lèvera une exception ou (pire encore !!!) débordera silencieusement et reviendra, vous donnant un résultat complètement incorrect sans même que vous le sachiez.

2
Non, ce n'est pas faux . Beaucoup ne sont pas valables pour de très grandes valeurs décimales / virgule flottante, mais cela convient parfaitement à la plupart des situations. Les nombres sont très souvent contraints d'être suffisamment bas lors du codage, donc cela ne doit pas être un problème. De plus, j'ai fourni une solution Math.Truncate qui fonctionne pour toutes les valeurs.
Noldorin

2
Je vois pourquoi tu es en colère contre moi. Le fait est que votre réponse est fausse. Vous lui dites de tenter sa chance en ne se cassant pas parce que, hé, beaucoup de chiffres sont petits. C'est un risque insensé à prendre. Vous devez éditer votre réponse et supprimer tout sauf Math.Truncate car c'est la seule partie correcte.

1
Vous savez ce qu'ils disent sur ASSUME. De plus, votre hypothèse est particulièrement horrible. Est-ce que c'est incendiaire? Je suppose que vous pourriez dire ça. Vous pouvez également dire que dire à quelqu'un de faire quelque chose de stupide qui lui causera des problèmes plus tard est également incendiaire, sinon carrément contraire à l'éthique.

1
En fait, ce serait faux si j'avais l'intention de donner une réponse trompeuse. Pour ainsi dire, j'essayais simplement d'aider. Si je suis coupable d'un léger malentendu ou de ne pas apprécier pleinement la question, c'est assez juste - ce n'est pas un crime. Alors pourquoi nous disputons-nous maintenant? Nous convenons tous que Truncate est la bonne réponse.
Noldorin le

0

Moyen très simple de séparer la valeur et sa valeur de partie fractionnaire.

double  d = 3.5;
int i = (int)d;
string s = d.ToString();
s = s.Replace(i + ".", "");

s est une partie fractionnaire = 5 et
i est une valeur comme entier = 3


1
Voir la première réponse ci-dessus. Cela ne fonctionne pas car (int)Decimal.MaxValuecela débordera.
Yaakov Ellis

0

J'espère vous aider.

/// <summary>
/// Get the integer part of any decimal number passed trough a string 
/// </summary>
/// <param name="decimalNumber">String passed</param>
/// <returns>teh integer part , 0 in case of error</returns>
private int GetIntPart(String decimalNumber)
{
    if(!Decimal.TryParse(decimalNumber, NumberStyles.Any , new CultureInfo("en-US"), out decimal dn))
    {
        MessageBox.Show("String " + decimalNumber + " is not in corret format", "GetIntPart", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return default(int);
    } 

    return Convert.ToInt32(Decimal.Truncate(dn));
}

-2
   Public Function getWholeNumber(number As Decimal) As Integer
    Dim round = Math.Round(number, 0)
    If round > number Then
        Return round - 1
    Else
        Return round
    End If
End Function

1
La réponse acceptée - publiée il y a plus de huit ans - explique pourquoi cette réponse est fausse. La plage de decimalest bien plus grande que celle de int. De plus, ce n'est pas une question VB.
Joe Farrell

@JoeFarrell - si vous pensez que la réponse est fausse, vous pouvez envisager de voter contre elle en plus de simplement laisser un commentaire à l'effet. Cependant, ne le signalez pas (pas que je dise que vous l'avez). C'est une tentative de répondre à la question. Cela peut être dans la mauvaise langue, cela peut être faux même en VB, mais c'est une tentative. Voir, par exemple, « Lorsqu'une réponse répond à la mauvaise question, n'est-ce pas une réponse? ».
Wai Ha Lee
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.