Como arredondar um valor decimal para 2 casas decimais (para saída em uma página)


649

Ao exibir o valor de um decimal atualmente com .ToString(), é preciso gostar de 15 casas decimais e, como estou usando-o para representar dólares e centavos, quero apenas que a saída tenha 2 casas decimais.

Eu uso uma variação .ToString()para isso?

Respostas:


911
decimalVar.ToString ("#.##"); // returns "" when decimalVar == 0

ou

decimalVar.ToString ("0.##"); // returns "0"  when decimalVar == 0

31
o problema aqui é quando temos 0,00; retorna uma string vazia.
Jronny

164
Então você pode fazer decimalVar.ToString ("0. ##"). Você também pode usar 0,00 como a string de formatação.
Albertein 04/04

54
Com esta solução, você não terá a formatação de cultura que seria de esperar ao ler números. Para isso, você deve usar ToString ("N2") ou ToString ("N").
precisa saber é o seguinte

2
O método @Hill Decimale Doubletype ToStringaceita argumento para formatação. Tente converter seu valor para decimal / duplo primeiro.
sohaiby

1
@ f470071 Os decimais são tipos de valor e, como tal, nunca são "modificados". Independentemente disso, nunca se espera que o ToString () modifique o conteúdo do que é chamado.
26716 Justin Skiles

590

Sei que essa é uma pergunta antiga, mas fiquei surpreso ao ver que ninguém parecia postar uma resposta;

  1. Não usou arredondamento de banqueiros
  2. Não manteve o valor como decimal.

Isto é o que eu usaria:

decimal.Round(yourValue, 2, MidpointRounding.AwayFromZero);

http://msdn.microsoft.com/en-us/library/9s0xa85y.aspx


3
ToString ou string.Format não use banqueiros arredondamento: msdn.microsoft.com/en-us/library/0c899ak8.aspx#sectionToggle1
Matthijs Wessels

1
@MatthijsWessels que eu conheço ... mas também não mantém o valor como decimal.
Mike M.

1
Essa é a melhor maneira de representar verdadeiramente duas casas decimais, pois não eliminará zeros à direita.
precisa saber é o seguinte

355
decimalVar.ToString("F");

Isso vai:

  • Arredonde para 2 casas decimais, por exemplo. 23.45623.46
  • Garanta que sempre haja 2 casas decimais, por exemplo. 2323.00; 12.512.50

Ideal para exibição de moeda.

Confira a documentação do ToString ("F") (graças a Jon Schneider).


10
Isso funciona bem quando tem apenas 1 decimal; .ToString ("#. ##") falha. Esta resposta é muito melhor
Eric Frick

2
Não seria 23.456 => 23.46?
rtpHarry

14
Documentação sobre o que significa o "F" aqui, e como ele funciona: msdn.microsoft.com/en-us/library/...
Jon Schneider

4
Por que não .ToString ("N") em vez de "F"? Pelo que entendi, ambos trabalharão para as necessidades dessa pergunta, mas N também colocará vírgulas para milhares.
jgerman

Nota: O .pode ser substituído por com ,base na cultura. Você deve passar adiante CultureInfo.InvariantCulturecomo o segundo argumento para desativar isso.
Duncan Luk


56

Dado decimal d = 12,345; as expressões d.ToString ("C") ou String.Format ("{0: C}", d) rendem US $ 12,35 - observe que são usadas as configurações de moeda da cultura atual, incluindo o símbolo.

Observe que "C" usa o número de dígitos da cultura atual. Você sempre pode substituir o padrão para forçar a precisão necessária com o C{Precision specifier}gosto String.Format("{0:C2}", 5.123d).


4
@ Slick86 - o sinal
atual

48

Se você quiser que ele seja formatado com vírgulas e um ponto decimal (mas sem símbolo de moeda), como 3.456.789,12 ...

decimalVar.ToString("n2");

1
Melhor resposta, pois a pergunta era sobre a saída de uma página e a formatação de números é importante para grandes números. Além disso, "n *" leva em consideração a cultura atual, portanto pode ser "3.456.789,12", "3 456 789,12" etc.)
Shautieh

29

Já existem duas respostas de alta pontuação que se referem a Decimal.Round (...), mas acho que é necessária uma explicação um pouco mais - porque há uma propriedade importante inesperada de Decimal que não é óbvia.

Um decimal 'sabe' quantas casas decimais se baseou em sua origem.

Por exemplo, o seguinte pode ser inesperado:

Decimal.Parse("25").ToString()          =>   "25"
Decimal.Parse("25.").ToString()         =>   "25"
Decimal.Parse("25.0").ToString()        =>   "25.0"
Decimal.Parse("25.0000").ToString()     =>   "25.0000"

25m.ToString()                          =>   "25"
25.000m.ToString()                      =>   "25.000"

Fazer as mesmas operações com Doublenão fornecerá casas decimais ( "25") para cada uma das opções acima.

Quando você deseja um decimal com duas casas decimais, há cerca de 95% de chance, é porque é a moeda; nesse caso, isso provavelmente é bom para 95% das vezes:

Decimal.Parse("25.0").ToString("c")     =>   "$25.00"

Ou no XAML você apenas usa {Binding Price, StringFormat=c}

Um caso em que encontrei onde eu precisava de um decimal, era como um decimal ao enviar XML para o serviço web da Amazon. O serviço estava reclamando porque um valor decimal (originalmente do SQL Server) estava sendo enviado 25.1200e rejeitado ( 25.12era o formato esperado).

Tudo o que eu precisava fazer era Decimal.Round(...)com duas casas decimais para corrigir o problema.

 // This is an XML message - with generated code by XSD.exe
 StandardPrice = new OverrideCurrencyAmount()
 {
       TypedValue = Decimal.Round(product.StandardPrice, 2),
       currency = "USD"
 }

TypedValueé do tipo Decimalque eu não podia fazer ToString("N2")e precisava arredondá-lo e mantê-lo como a decimal.


5
+1 esta é uma ótima resposta. Quando você diz que System.Decimal "sabe quantas casas decimais existem " - o termo é que System.Decimal não é auto-normalizado como os outros tipos de ponto flutuante. Outra propriedade útil do System.Decimal é que o resultado das operações matemáticas sempre tem o maior número de casas decimais dos argumentos de entrada, ou seja. 1.0m + 2.000m = 3.000m . Você pode usar esse fato para forçar um decimal sem casas decimais para 2 casas decimais simplesmente multiplicando-o por 1,00m, por exemplo. 10m * 1,00m = 10,00m .
precisa saber é o seguinte

2
MattDavey's está incorreto, a precisão decimal é adicionada. (1.0m * 1.00m) .ToString () = "1.000"
Kaido

2
É muito, muito útil saber que "Um decimal 'sabe' quantas casas decimais se baseou em sua origem". Muito obrigado!
Iheartcsharp

21

Aqui está um pequeno programa do Linqpad para mostrar diferentes formatos:

void Main()
{
    FormatDecimal(2345.94742M);
    FormatDecimal(43M);
    FormatDecimal(0M);
    FormatDecimal(0.007M);
}

public void FormatDecimal(decimal val)
{
    Console.WriteLine("ToString: {0}", val);
    Console.WriteLine("c: {0:c}", val);
    Console.WriteLine("0.00: {0:0.00}", val);
    Console.WriteLine("0.##: {0:0.##}", val);
    Console.WriteLine("===================");
}

Aqui estão os resultados:

ToString: 2345.94742
c: $2,345.95
0.00: 2345.95
0.##: 2345.95
===================
ToString: 43
c: $43.00
0.00: 43.00
0.##: 43
===================
ToString: 0
c: $0.00
0.00: 0.00
0.##: 0
===================
ToString: 0.007
c: $0.01
0.00: 0.01
0.##: 0.01
===================


11

Muito raramente, você deseja uma sequência vazia se o valor for 0.

decimal test = 5.00;
test.ToString("0.00");  //"5.00"
decimal? test2 = 5.05;
test2.ToString("0.00");  //"5.05"
decimal? test3 = 0;
test3.ToString("0.00");  //"0.00"

A resposta mais votada está incorreta e perdeu 10 minutos do tempo (da maioria) das pessoas.


1
basicamente "#"significa dígito do número (se necessário) (sem preenchimento se não for necessário) "0"significa dígito do número (não importa o que) (preenchidos com zeros se não disponível)
Sr. Heelis

10

A resposta de Mike M. foi perfeita para mim no .NET, mas o .NET Core ainda não possui um decimal.Roundmétodo.

No .NET Core, eu tive que usar:

decimal roundedValue = Math.Round(rawNumber, 2, MidpointRounding.AwayFromZero);

Um método hacky, incluindo a conversão em string, é:

public string FormatTo2Dp(decimal myNumber)
{
    // Use schoolboy rounding, not bankers.
    myNumber = Math.Round(myNumber, 2, MidpointRounding.AwayFromZero);

    return string.Format("{0:0.00}", myNumber);
}

9

Nenhuma delas fez exatamente o que eu precisava, forçar 2 pontos de pontos e arredondar0.005 -> 0.01

Forçar 2 dp exige aumentar a precisão em 2 dp para garantir que tenhamos pelo menos 2 dp

arredondando para garantir que não temos mais de 2 pontos

Math.Round(exactResult * 1.00m, 2, MidpointRounding.AwayFromZero)

6.665m.ToString() -> "6.67"

6.6m.ToString() -> "6.60"

9

A resposta com melhor classificação descreve um método para formatar a representação em seqüência do valor decimal e funciona.

No entanto, se você realmente deseja alterar a precisão salva no valor real, precisa escrever algo como o seguinte:

public static class PrecisionHelper
{
    public static decimal TwoDecimalPlaces(this decimal value)
    {
        // These first lines eliminate all digits past two places.
        var timesHundred = (int) (value * 100);
        var removeZeroes = timesHundred / 100m;

        // In this implementation, I don't want to alter the underlying
        // value.  As such, if it needs greater precision to stay unaltered,
        // I return it.
        if (removeZeroes != value)
            return value;

        // Addition and subtraction can reliably change precision.  
        // For two decimal values A and B, (A + B) will have at least as 
        // many digits past the decimal point as A or B.
        return removeZeroes + 0.01m - 0.01m;
    }
}

Um exemplo de teste de unidade:

[Test]
public void PrecisionExampleUnitTest()
{
    decimal a = 500m;
    decimal b = 99.99m;
    decimal c = 123.4m;
    decimal d = 10101.1000000m;
    decimal e = 908.7650m

    Assert.That(a.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("500.00"));

    Assert.That(b.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("99.99"));

    Assert.That(c.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("123.40"));

    Assert.That(d.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("10101.10"));

    // In this particular implementation, values that can't be expressed in
    // two decimal places are unaltered, so this remains as-is.
    Assert.That(e.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("908.7650"));
}

7

Você pode usar system.globalization para formatar um número em qualquer formato necessário.

Por exemplo:

system.globalization.cultureinfo ci = new system.globalization.cultureinfo("en-ca");

Se você tiver um decimal d = 1.2300000e precisar recortá-lo com 2 casas decimais, ele poderá ser impresso assim em d.Tostring("F2",ci);que F2 está formando uma string com 2 casas decimais e ci é a localidade ou a informação da cultura.

para obter mais informações, consulte este link
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx


+1 mas - o objeto CultureInfo afetaria apenas o caractere unicode usado para indicar a casa decimal. por exemplo. fr-FR usaria uma vírgula em vez de um ponto. Não está relacionado ao número de casas decimais renderizadas.
precisa saber é o seguinte


1
Double Amount = 0;
string amount;
amount=string.Format("{0:F2}", Decimal.Parse(Amount.ToString()));

1

Se você precisar manter apenas 2 casas decimais (ou seja, cortar todo o restante dos dígitos decimais):

decimal val = 3.14789m;
decimal result = Math.Floor(val * 100) / 100; // result = 3.14

Se você precisar manter apenas 3 casas decimais:

decimal val = 3.14789m;
decimal result = Math.Floor(val * 1000) / 1000; // result = 3.147
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.