¿Cómo redondeo un valor decimal a 2 decimales (para salida en una página)

649

Cuando se muestra el valor de un decimal actualmente con .ToString(), es preciso que le gusten 15 lugares decimales, y como lo estoy usando para representar dólares y centavos, solo quiero que la salida sea 2 lugares decimales.

¿Utilizo una variación de .ToString()para esto?

wows
fuente

Respuestas:

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

o

decimalVar.ToString ("0.##"); // returns "0"  when decimalVar == 0
alberteína
fuente
31
El problema aquí es cuando tenemos 0.00; devuelve una cadena vacía.
Jronny
164
Entonces podría hacer decimalVar.ToString ("0. ##"). También puede usar 0.00 como la cadena de formato.
albertein
54
Con esta solución, no tendrá el formato de cultura que uno esperaría al leer números. Para esto, debe usar ToString ("N2") o ToString ("N").
Shautieh
2
El método @Hill Decimaland Doubletype ToStringacepta argumentos para formatear. Intente convertir su valor a decimal / doble primero.
sohaiby
1
@ f470071 Los decimales son tipos de valor y, como tales, nunca se "modifican". En cualquier caso, nunca se ha esperado que ToString () modifique el contenido de lo que se llame.
Justin Skiles
590

Sé que esta es una vieja pregunta, pero me sorprendió ver que nadie parecía publicar una respuesta que;

  1. No utilicé banqueros redondeando
  2. No mantuvo el valor como un decimal.

Esto es lo que usaría:

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

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

Mike M.
fuente
3
ToString o string.Format no utiliza redondeo de banqueros: msdn.microsoft.com/en-us/library/0c899ak8.aspx#sectionToggle1
Matthijs Wessels
1
@MatthijsWessels Lo sé ... pero tampoco mantiene el valor como decimal.
Mike M.
1
Esta es una mejor manera de representar realmente dos lugares decimales, ya que no eliminará ceros finales.
LiquidDrummer
355
decimalVar.ToString("F");

Esta voluntad:

  • Redondear a 2 decimales, por ejemplo. 23.45623.46
  • Asegúrese de que siempre haya 2 decimales, por ejemplo. 2323.00; 12.512.50

Ideal para mostrar moneda.

Consulte la documentación en ToString ("F") (gracias a Jon Schneider).

Sofox
fuente
10
Esto funciona bien cuando solo tiene 1 decimal; .ToString ("#. ##") falla. Esta respuesta es mucho mejor
Eric Frick
2
¿No redondearía 23.456 => 23.46?
rtpHarry
14
Documentación sobre lo que significa "F" aquí y cómo funciona: msdn.microsoft.com/en-us/library/…
Jon Schneider
44
¿Por qué no .ToString ("N") en lugar de "F"? Tengo entendido que ambos trabajarán para las necesidades de esta pregunta, pero N también colocará comas por miles.
jgerman
Nota: El .puede ser reemplazado por ,basado en la cultura. Debe pasar CultureInfo.InvariantCulturecomo el segundo argumento para deshabilitar esto.
Duncan Luk
56

Dado decimal d = 12.345; las expresiones d.ToString ("C") o String.Format ("{0: C}", d) rinden $ 12.35 ; tenga en cuenta que se utiliza la configuración de moneda de la cultura actual, incluido el símbolo.

Tenga en cuenta que "C" utiliza el número de dígitos de la cultura actual. Siempre puede anular el valor predeterminado para forzar la precisión necesaria con me C{Precision specifier}gusta String.Format("{0:C2}", 5.123d).

Hafthor
fuente
44
@ Slick86 - el signo actual
fubo
48

Si lo desea formateado con comas, así como un punto decimal (pero sin símbolo de moneda), como 3,456,789.12 ...

decimalVar.ToString("n2");
Joel Mueller
fuente
1
Mejor respuesta ya que la pregunta era sobre la salida en una página, y el formato de números es importante para los números grandes. Además, "n *" tiene en cuenta la cultura actual, por lo que podría ser "3.456.789,12", "3 456 789,12", etc.
Shautieh
29

Ya hay dos respuestas de alta puntuación que se refieren a Decimal. Redonda (...) pero creo que se necesita un poco más de explicación, porque hay una propiedad inesperada e importante de Decimal que no es obvia.

Un decimal 'sabe' cuántos decimales tiene en función de su origen.

Por ejemplo, lo siguiente puede 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"

Hacer las mismas operaciones con Doubleno dará lugares decimales ( "25") para cada uno de los anteriores.

Cuando quieres un decimal a 2 decimales, hay aproximadamente un 95% de posibilidades de que sea porque es moneda, en cuyo caso esto probablemente esté bien el 95% del tiempo:

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

O en XAML solo usas {Binding Price, StringFormat=c}

Un caso con el que me encontré donde necesitaba un decimal AS era cuando enviaba XML al servicio web de Amazon. El servicio se quejaba porque un valor decimal (originalmente de SQL Server) se estaba enviando como 25.1200rechazado, (25.12 era el formato esperado).

Todo lo que necesitaba hacer era Decimal.Round(...)con 2 decimales para solucionar el problema.

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

TypedValuees de tipo, Decimalasí que no podía hacerlo ToString("N2")y necesitaba redondearlo y mantenerlo como decimal.

Simon_Weaver
fuente
55
+1 esta es una gran respuesta. Cuando dice que System.Decimal "sabe cuántos lugares decimales tiene", el término es que System.Decimal no se auto normaliza como los otros tipos de coma flotante. Otra propiedad útil de System.Decimal es que el resultado de las operaciones matemáticas siempre tiene el mayor número de decimales de los argumentos de entrada, es decir. 1.0m + 2.000m = 3.000m . Puede usar este hecho para forzar un decimal sin decimales a 2 decimales simplemente multiplicándolo por 1,00m, por ejemplo. 10m * 1.00m = 10.00m .
MattDavey
2
MattDavey's es incorrecto, se agrega la precisión decimal. (1.0m * 1.00m) .ToString () = "1.000"
Kaido
2
Es muy, muy útil saber que "un decimal 'sabe' cuántos decimales tiene en función de su origen". ¡Muchas gracias!
iheartcsharp
21

Aquí hay un pequeño programa de 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("===================");
}

Aquí están los 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
===================
Lo que sería genial
fuente
16

Método Math.Round (Decimal, Int32)

John Smith
fuente
¿No usa eso el redondeo bancario?
Danimal
Esta es la mejor manera, ya que el valor doesnt convertido en una cadena y todavía se pueden realizar operaciones matemáticas
shinji14
@Danimal: puede proporcionar un tercer argumento para cambiar el tipo de redondeo
Jay Sullivan
11

Muy raramente querría una cadena vacía si el valor es 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"

La respuesta mejor calificada es incorrecta y ha desperdiciado 10 minutos (la mayoría) del tiempo de las personas.

goamn
fuente
1
básicamente "#"significa dígito de número (si es necesario) (sin relleno si no es necesario) "0"significa dígito de número (no importa qué) (rellenado con ceros si no está disponible)
Sr. Heelis
10

La respuesta de Mike M. fue perfecta para mí en .NET, pero .NET Core no tiene un decimal.Roundmétodo al momento de escribir.

En .NET Core, tuve que usar:

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

Un método hacky, que incluye la conversión a cadena, es:

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

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

Ninguno de estos hizo exactamente lo que necesitaba, forzar 2 dp y redondear como0.005 -> 0.01

Forzar 2 dp requiere aumentar la precisión en 2 dp para garantizar que tengamos al menos 2 dp

luego redondeando para asegurarnos de que no tenemos más de 2 dp

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

6.665m.ToString() -> "6.67"

6.6m.ToString() -> "6.60"
Kaido
fuente
9

La respuesta mejor calificada describe un método para formatear la representación de cadena del valor decimal, y funciona.

Sin embargo, si realmente desea cambiar la precisión guardada en el valor real, debe escribir algo como lo siguiente:

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

Un ejemplo de prueba unitaria:

[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"));
}
Alex
fuente
7

Puede usar system.globalization para formatear un número en cualquier formato requerido.

Por ejemplo:

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

Si tiene un decimal d = 1.2300000y necesita recortarlo a 2 decimales, entonces puede imprimirse así d.Tostring("F2",ci);donde F2 está formando cadenas a 2 decimales y ci es la configuración regional o información cultural.

Para obtener más información, consulte este enlace
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

Smitha Poluri
fuente
+1 pero - el objeto CultureInfo solo afectaría el carácter unicode usado para denotar el lugar decimal. p.ej. fr-FR usaría una coma en lugar de un punto. No está relacionado con el número de decimales representados.
MattDavey
4

https://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx

Este enlace explica en detalle cómo puede manejar su problema y qué puede hacer si desea obtener más información. Por simplicidad, lo que quieres hacer es

double whateverYouWantToChange = whateverYouWantToChange.ToString("F2");

si desea esto para una moneda, puede hacerlo más fácil escribiendo "C2" en lugar de "F2"

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

Si necesita mantener solo 2 lugares decimales (es decir, cortar todo el resto de dígitos decimales):

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

Si necesita mantener solo 3 decimales:

decimal val = 3.14789m;
decimal result = Math.Floor(val * 1000) / 1000; // result = 3.147
Aleksei Mialkin
fuente