C # Double - formatação ToString () com duas casas decimais, mas sem arredondamento

153

Como formatar a Doublepara a Stringem C # para ter apenas duas casas decimais?

Se eu usar String.Format("{0:0.00}%", myDoubleValue)o número, ele será arredondado e eu quero um truncado simples, sem arredondamento. Eu também quero que a conversão Stringseja sensível à cultura.

kjv
fonte
O que você quer dizer com "sensível à cultura"? Isso significa que o resultado da formatação deve variar dependendo do valor da cultura fornecido pelo programador? Ou você deseja usar qualquer cultura que seja o padrão para o encadeamento atual?
CesarGon

Respostas:

204

Eu uso o seguinte:

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

Por exemplo:

Se o número for 50.947563 e você usar o seguinte, ocorrerá o seguinte:

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

E sua resposta está truncada. Agora, para formatar a sequência, faça o seguinte:

string s = string.Format("{0:N2}%", x); // No fear of rounding and takes the default number format
Kyle Rosendo
fonte
3
-1 Você pode fazer a formatação sensível à cultura na mesma string.Formatetapa que formata a sequência. Veja minha resposta abaixo.
CesarGon
1
Isso é ótimo. Espero que meu comentário não pareça tão bobo agora. :-) Vou mudar meu voto negativo então.
CesarGon
1
Para mim, como a solução na formatação de strings é incrivelmente simples, o truncamento foi mais complicado.
Kyle Rosendo
1
Infelizmente, sua solução não funciona quando o número é menor que 1, para ilustrar: 0,97, existe alguma solução alternativa para essa situação?
Ali Dehghan
2
@ Jonny que não funcionará porque arredonda - o OP quer truncar (e não arredondar). A diferença é sutil.
BKSpurgeon
102

O seguinte arredonda os números, mas mostra apenas duas casas decimais (removendo os zeros à direita), graças a .##.

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/

Brian Ogden
fonte
12
Isso não funciona. Experimente com 0,2415999. Esta solução arredonda, não trunca.
BJury
5
Uau, tantos votos positivos e ainda assim ele usa arredondamentos. Pode ser necessário salientar que o arredondamento está indo para a casa decimal mais próxima solicitada, enquanto o truncamento é cortado após a casa decimal mais próxima solicitada.
Mysticcoder
1
@mysticcoder Eu acho que minha resposta recebe tantos votos positivos, porque eles chegam à pergunta do ops em uma pesquisa no Google da mesma maneira que eu, procurando remover zeros à direita e não procurando o desejo arredondado da pergunta do ops. Acho que eu deveria apagar a minha resposta ...
Brian Ogden
@BrianOgden - Não, por favor, não exclua. Cheguei aqui procurando sua resposta. +1
Roberto
35

Sugiro que você trunque primeiro e depois formate:

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);

Use a constante 100 para 2 dígitos truncados; use 1 seguido de tantos zeros quanto dígitos após o ponto decimal desejado. Use o nome da cultura necessário para ajustar o resultado da formatação.

CesarGon
fonte
Eu acho que, em vez de new CultureInfo("de-DE"), você deve usar a propriedade estáticaCulture.InvariantCulture
vchan
15

Método mais simples, use seqüências de caracteres numéricas:

double total = "43.257"
MessageBox.Show(total.ToString("F"));
Harambe Attack Helicopter
fonte
2
Na verdade, este método faz rodada msdn.microsoft.com/en-us/library/...
Elvin
13

eu uso price.ToString("0.00") para obter os 0s principais

CMS
fonte
6

A função c #, como expressa por 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);
}
maxp
fonte
5

Que tal adicionar um decimal extra que deve ser arredondado e descartado:

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

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

fonte
3
É engraçado como uma resposta não funciona tem 60 votos ups (a partir de hoje), e este simples bonita e à prova de balas solução tem apenas um ....
Arthur Kazykhanov
5
Isso não funcionará no caso de o arredondamento afetar mais de um dígito acima do ponto de corte. Por exemplo, 0.199999 terminará em 0,20 com esse código, em vez de 0,19.
Bernem 6/0318
4

Isso está funcionando para mim

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

Eu sei que este é um tópico antigo, mas eu apenas tive que fazer isso. Enquanto as outras abordagens aqui funcionam, eu queria uma maneira fácil de afetar muitas ligações para string.format. Portanto, adicionar a Math.Truncatetodas as chamadas não foi realmente uma boa opção. Além disso, como parte da formatação é armazenada em um banco de dados, a situação é ainda pior.

Assim, criei um provedor de formato personalizado que me permitia adicionar truncamento à string de formatação, por exemplo:

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

A implementação é bastante simples e é facilmente extensível a outros requisitos.

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;
    }
}
BJury
fonte
2

Eu tive esse problema com o Xamarin Forms e o resolvi com isso:

percent.ToString("0.##"+"%")
Diego Sanchez
fonte
1

Para o que vale a pena, para mostrar a moeda, você pode usar "C":

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

Resultado: $1.99

Roozbeh Zabihollahi
fonte
0

Você também pode escrever seu próprio IFormatProvider , embora suponha que eventualmente você precise pensar em uma maneira de fazer o truncamento real.

O .NET Framework também oferece suporte à formatação personalizada. Normalmente, isso envolve a criação de uma classe de formatação que implementa o IFormatProvider e o ICustomFormatter . (msdn)

Pelo menos, seria facilmente reutilizável.

Há um artigo sobre como implementar seu próprio IFormatProvider / ICustomFormatter aqui no CodeProject . Nesse caso, "estender" um formato numérico existente pode ser a melhor aposta. Não parece muito difícil.

Benny Jobigan
fonte
0

A seguir pode ser usado apenas para exibição que usa a propriedade String.

double value = 123.456789;
String.Format("{0:0.00}", value);
Mestre Shafiqur Rahman
fonte
Isso dará "123.46". A pergunta não pede especificamente arredondamentos.
Tobberoth
0

Solução:

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

(indexOfP + 1) +2 (esse número depende de quantos você deseja preservar. Dou dois porque o proprietário da pergunta deseja.)

劉鎮 瑲
fonte
0

Observe também a CultureInformation do seu sistema. Aqui a minha solução sem arredondar.

Neste exemplo, você apenas precisa definir a variável MyValue como double. Como resultado, você obtém seu valor formatado na variável de sequência NewValue .

Nota - Defina também o C # usando a instrução:

using System.Globalization;  

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

string NewValue = MyValue.ToString(MyFormat);
Daniel
fonte