C # Double - Formatage ToString () avec deux décimales mais pas d'arrondi


153

Comment formater un Doubleen un Stringen C # pour n'avoir que deux décimales?

Si j'utilise String.Format("{0:0.00}%", myDoubleValue)le nombre est alors arrondi et je veux une simple troncature sans aucun arrondi. Je souhaite également que la conversion Stringsoit sensible à la culture.


Qu'entendez-vous par «sensible à la culture»? Cela signifie-t-il que le résultat de la mise en forme doit varier en fonction d'une valeur de culture fournie par le programmeur? Ou souhaitez-vous utiliser la culture par défaut du thread actuel?
CesarGon

Réponses:


204

J'utilise ce qui suit:

double x = Math.Truncate(myDoubleValue * 100) / 100;

Par exemple:

Si le numéro est 50,947563 et que vous utilisez ce qui suit, les événements suivants se produiront:

- Math.Truncate(50.947563 * 100) / 100;
- Math.Truncate(5094.7563) / 100;
- 5094 / 100
- 50.94

Et votre réponse est tronquée, maintenant pour formater la chaîne, procédez simplement comme suit:

string s = string.Format("{0:N2}%", x); // No fear of rounding and takes the default number format

3
-1 Vous pouvez effectuer la mise en forme sensible à la culture dans la même string.Formatétape qui formate la chaîne. Voir ma réponse ci-dessous.
CesarGon

1
C'est génial. J'espère que mon commentaire n'a pas l'air aussi idiot maintenant. :-) Je changerai alors mon vote défavorable.
CesarGon

1
Pour moi, c'est le cas, car la solution sur le formatage des chaînes est incroyablement simple, la troncature était plus délicate.
Kyle Rosendo

1
Malheureusement, votre solution ne fonctionne pas lorsque le nombre est inférieur à 1, pour illustrer: 0,97, existe-t-il une solution de contournement pour cette situation?
Ali Dehghan

2
@Jonny qui ne fonctionnera pas car il arrondit - OP veut qu'il tronque (et non arrondi). La différence est subtile.
BKSpurgeon

102

Ce qui suit arrondit les nombres, mais n'affiche que 2 décimales maximum (en supprimant les zéros de fin), grâce à .##.

decimal d0 = 24.154m;
decimal d1 = 24.155m;
decimal d2 = 24.1m;
decimal d3 = 24.0m;

d0.ToString("0.##");   //24.15
d1.ToString("0.##");   //24.16 (rounded up)
d2.ToString("0.##");   //24.1  
d3.ToString("0.##");   //24

http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/


12
Cela ne marche pas. Essayez-le avec 0.2415999. Cette solution arrondit, pas tronque.
BJury

5
Wow, il y a tellement de votes et pourtant il utilise l'arrondi. Il peut être nécessaire de souligner que l'arrondi se dirige vers la décimale la plus proche demandée, alors que la troncature consiste à couper après la décimale la plus proche demandée.
mysticcoder

1
@mysticcoder Je suppose que ma réponse reçoit tellement de votes positifs parce qu'ils arrivent à la question des opérations dans une recherche Google de la même manière que moi, en cherchant à supprimer les zéros de fin et en ne recherchant pas le désir d'arrondi de la question sur les opérations. Je suppose que je devrais supprimer ma réponse ...
Brian Ogden

@BrianOgden - Non, veuillez ne pas supprimer. Je suis arrivé ici à la recherche de votre réponse. +1
Roberto

35

Je vous suggère de tronquer d'abord, puis de formater:

double a = 123.4567;
double aTruncated = Math.Truncate(a * 100) / 100;
CultureInfo ci = new CultureInfo("de-DE");
string s = string.Format(ci, "{0:0.00}%", aTruncated);

Utilisez la constante 100 pour tronquer 2 chiffres; utilisez un 1 suivi d'autant de zéros que de chiffres après la virgule décimale que vous souhaitez. Utilisez le nom de culture dont vous avez besoin pour ajuster le résultat de la mise en forme.


Je pense qu'au lieu de new CultureInfo("de-DE"), vous devriez utiliser la propriété staticCulture.InvariantCulture
vchan


13

j'utilise price.ToString("0.00") pour obtenir les 0 premiers


6

La fonction c #, telle qu'exprimée par Kyle Rozendo:

string DecimalPlaceNoRounding(double d, int decimalPlaces = 2)
{
    d = d * Math.Pow(10, decimalPlaces);
    d = Math.Truncate(d);
    d = d / Math.Pow(10, decimalPlaces);
    return string.Format("{0:N" + Math.Abs(decimalPlaces) + "}", d);
}

5

Que diriez-vous d'ajouter une décimale supplémentaire à arrondir puis à supprimer:

var d = 0.241534545765;
var result1 = d.ToString("0.###%");

var result2 = result1.Remove(result1.Length - 1);

3
C'est drôle comment une réponse qui ne fonctionne pas a 60 votes (à ce jour), et cette solution assez simple et à l'épreuve des balles n'en a qu'un ...
Arthur Kazykhanov

5
Cela ne fonctionnera pas dans le cas où l'arrondi affecte plus d'un chiffre au-dessus du seuil. Par exemple, 0,199999 se terminera par 0,20 avec ce code, au lieu de 0,19.
Bernem

4

Cela fonctionne pour moi

string prouctPrice = Convert.ToDecimal(String.Format("{0:0.00}", Convert.ToDecimal(yourString))).ToString();

2

Je sais que c'est un vieux fil mais j'ai juste dû le faire. Bien que les autres approches fonctionnent ici, je voulais un moyen simple de pouvoir affecter de nombreux appels à string.format. Donc, ajouter le Math.Truncateà tous les appels n'était pas vraiment une bonne option. De plus, comme une partie du formatage est stockée dans une base de données, la situation est encore pire.

Ainsi, j'ai créé un fournisseur de format personnalisé qui me permettrait d'ajouter une troncature à la chaîne de formatage, par exemple:

string.format(new FormatProvider(), "{0:T}", 1.1299); // 1.12
string.format(new FormatProvider(), "{0:T(3)", 1.12399); // 1.123
string.format(new FormatProvider(), "{0:T(1)0,000.0", 1000.9999); // 1,000.9

La mise en œuvre est assez simple et est facilement extensible à d'autres exigences.

public class FormatProvider : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof (ICustomFormatter))
        {
            return this;
        }
        return null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        if (arg == null || arg.GetType() != typeof (double))
        {
            try
            {
                return HandleOtherFormats(format, arg);
            }
            catch (FormatException e)
            {
                throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
            }
        }

        if (format.StartsWith("T"))
        {
            int dp = 2;
            int idx = 1;
            if (format.Length > 1)
            {
                if (format[1] == '(')
                {
                    int closeIdx = format.IndexOf(')');
                    if (closeIdx > 0)
                    {
                        if (int.TryParse(format.Substring(2, closeIdx - 2), out dp))
                        {
                            idx = closeIdx + 1;
                        }
                    }
                    else
                    {
                        throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
                    }
                }
            }
            double mult = Math.Pow(10, dp);
            arg = Math.Truncate((double)arg * mult) / mult;
            format = format.Substring(idx);
        }

        try
        {
            return HandleOtherFormats(format, arg);
        }
        catch (FormatException e)
        {
            throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
        }
    }

    private string HandleOtherFormats(string format, object arg)
    {
        if (arg is IFormattable)
        {
            return ((IFormattable) arg).ToString(format, CultureInfo.CurrentCulture);
        }
        return arg != null ? arg.ToString() : String.Empty;
    }
}

2

J'ai eu ce problème avec Xamarin Forms et je l'ai résolu avec ceci:

percent.ToString("0.##"+"%")

1

Pour ce qui vaut, pour afficher la devise, vous pouvez utiliser "C":

double cost = 1.99;
m_CostText.text = cost.ToString("C"); /*C: format as currentcy */

Production: $1.99


0

Vous pouvez également écrire votre propre IFormatProvider , même si je suppose que vous devrez éventuellement penser à un moyen de faire la troncature réelle.

Le .NET Framework prend également en charge la mise en forme personnalisée. Cela implique généralement la création d'une classe de mise en forme qui implémente à la fois IFormatProvider et ICustomFormatter . (msdn)

Au moins, il serait facilement réutilisable.

Il existe un article sur la façon d'implémenter votre propre IFormatProvider / ICustomFormatter ici sur CodeProject . Dans ce cas, "étendre" un format numérique existant peut être le meilleur choix. Cela n'a pas l'air trop dur.


0

Ce qui suit peut être utilisé pour l'affichage uniquement qui utilise la propriété de String.

double value = 123.456789;
String.Format("{0:0.00}", value);

Cela donnera "123,46". La question ne demande spécifiquement aucun arrondi.
Tobberoth

0

Solution:

var d = 0.123345678; 
var stringD = d.ToString(); 
int indexOfP = stringD.IndexOf("."); 
var result = stringD.Remove((indexOfP+1)+2);

(indexOfP + 1) +2 (ce nombre dépend du nombre que vous souhaitez conserver. Je lui donne deux parce que le propriétaire de la question le souhaite.)


0

Notez également les informations sur la culture de votre système. Voici ma solution sans arrondir.

Dans cet exemple, il vous suffit de définir la variable MyValue comme double. En conséquence, vous obtenez votre valeur formatée dans la variable de chaîne NewValue .

Remarque - Définissez également l'instruction en utilisant C #:

using System.Globalization;  

string MyFormat = "0";
if (MyValue.ToString (CultureInfo.InvariantCulture).Contains (CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
   {
      MyFormat += ".00";
   }

string NewValue = MyValue.ToString(MyFormat);
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.