129 votes

Troncature Deux décimales sans arrondir

Disons que j'ai une valeur de 3.4679 et que je veux 3.46, comment puis-je la tronquer à deux décimales sans l'arrondir ?

J'ai essayé ce qui suit, mais les trois me donnent 3.47 :

void Main()
{
    Console.Write(Math.Round(3.4679, 2,MidpointRounding.ToEven));
    Console.Write(Math.Round(3.4679, 2,MidpointRounding.AwayFromZero));
    Console.Write(Math.Round(3.4679, 2));
}

Cela donne 3,46, mais ça semble sale :

void Main()
{
    Console.Write(Math.Round(3.46799999999 -.005 , 2));
}

175voto

Hans Passant Points 475940
value = Math.Truncate(100 * value) / 100;

Attention, les fractions de ce type ne peuvent pas être représentées avec précision en virgule flottante.

13 votes

Utilisez des décimales pour vos valeurs et cette réponse fonctionnera. Il est peu probable qu'elle fonctionne toujours dans n'importe quelle représentation en virgule flottante.

2 votes

Cela m'amène à me demander s'il ne serait pas possible de spécifier le sens de l'arrondi dans les littéraux à virgule flottante. Hmmmm.

0 votes

Il doit y avoir algunos manière de dire au programmeur que calculer en supposant qu'un nombre peut contenir plus de 308 chiffres est grossièrement inapproprié. Double ne peut en stocker que 15. Le débordement est très présent ici, il a débordé plutôt mal.

57voto

Corgalore Points 474

Il serait plus utile d'avoir une fonction complète pour l'utilisation réelle de la troncature d'un décimal en C#. Cette fonction pourrait être convertie en une méthode d'extension Decimal assez facilement si vous le souhaitiez :

public decimal TruncateDecimal(decimal value, int precision)
{
    decimal step = (decimal)Math.Pow(10, precision);
    int tmp = (int)Math.Truncate(step * value);
    return tmp / step;
}

Si vous avez besoin de VB.NET, essayez ceci :

Function TruncateDecimal(value As Decimal, precision As Integer) As Decimal
    Dim stepper As Decimal = Math.Pow(10, precision)
    Dim tmp As Integer = Math.Truncate(stepper * value)
    Return tmp / stepper
End Function

Ensuite, utilisez-le comme suit :

decimal result = TruncateDecimal(0.275, 2);

ou

Dim result As Decimal = TruncateDecimal(0.275, 2)

3 votes

Cela débordera sur les grands nombres.

1 votes

Pour ajouter au codeur de nuit, le fait que vous utilisiez Int32 comme intermédiaire dans votre fonction provoquera des débordements. Vous devriez utiliser Int64 si vous devez vraiment le convertir en un Integer. La question serait de savoir pourquoi vous voudriez encourir cette surcharge supplémentaire de toute façon puisque Truncate renvoie des intégrales décimales de toute façon. Faites simplement quelque chose comme : decimal step = (decimal)Math.Pow(10, precision) ; return Math.Truncate(step * value) / step ;

0 votes

J'ai laissé tomber le casting en Integer. Je les ai laissés sur des lignes séparées pour une meilleure lisibilité et compréhension du fonctionnement de la fonction.

36voto

Leonard Lewis Points 1

Utilisez l'opérateur modulo :

var fourPlaces = 0.5485M;
var twoPlaces = fourPlaces - (fourPlaces % 0.01M);

résultat : 0,54

2 votes

Je ne comprends pas (lisez : je n'ai pas pris le temps de vérifier) toutes ces autres solutions fantaisistes, mais celle-ci le fait. exactement ce que je cherchais. Merci !

1 votes

Exécution sur .Net Fiddle clicky produit 0.5400 ... Le site réponse de D. Nesterov ci-dessous ont produit les résultats attendus 0.54 .

1 votes

Tu réalises, @ttugates , que 0.54 et 0.5400 sont exactement la même valeur, n'est-ce pas ? Le nombre de zéros qui suivent n'a pas d'importance, sauf si/jusqu'au moment de formater pour l'affichage - auquel cas, le résultat sera le même s'il est formaté correctement : $"{0.54m:C}" produit "$0.54" et oui, $"{0.5400m:C}" produit "$0.54" .

24voto

Tim Lloyd Points 23571

Un problème avec les autres exemples est qu'ils multiplient la valeur d'entrée avant le diviser. Il existe un cas limite dans lequel vous pouvez dépasser le nombre de décimales en multipliant d'abord, un cas limite, mais que j'ai rencontré. Il est plus sûr de traiter la partie fractionnaire séparément comme suit :

    public static decimal TruncateDecimal(this decimal value, int decimalPlaces)
    {
        decimal integralValue = Math.Truncate(value);

        decimal fraction = value - integralValue;

        decimal factor = (decimal)Math.Pow(10, decimalPlaces);

        decimal truncatedFraction = Math.Truncate(fraction * factor) / factor;

        decimal result = integralValue + truncatedFraction;

        return result;
    }

0 votes

Je sais que c'est vieux mais j'ai remarqué un problème avec ceci. Le facteur que vous avez ici est un int et donc si vous tronquez à un grand nombre de décimales (disons 25), le résultat final aura une erreur de précision. J'ai résolu le problème en changeant le type de facteur en décimal.

0 votes

@TheKingDave : probablement que ce n'est pas pertinent mais comme le facteur ne peut pas avoir de décimales, il vaut mieux le modéliser en tant que long, non ?

0 votes

@SoMoS Pour moi, Decimal a mieux fonctionné car il m'a donné les valeurs de stockage les plus élevées pour le facteur. Il a toujours une limitation mais il est assez grand pour mon application. D'un autre côté, Long n'était pas capable de stocker des nombres suffisamment grands pour mon application. Par exemple, si vous faites un Truncate(25) avec long, il y aura une certaine imprécision.

2voto

John Boker Points 36308

Cela vous conviendrait-il ?

Console.Write(((int)(3.4679999999*100))/100.0);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X