C # Double: formato ToString () con dos decimales pero sin redondeo

153

¿Cómo formateo a Doublea a Stringen C # para tener solo dos decimales?

Si uso String.Format("{0:0.00}%", myDoubleValue)el número, entonces se redondea y quiero un simple truncado sin ningún redondeo. También quiero que la conversión Stringsea ​​sensible a la cultura.

kjv
fuente
¿Qué quieres decir con "sensible a la cultura"? ¿Significa eso que el resultado del formato debe variar según el valor cultural proporcionado por el programador? ¿O quieres usar cualquier cultura que sea la predeterminada para el hilo actual?
CesarGon

Respuestas:

204

Yo uso lo siguiente:

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

Por ejemplo:

Si el número es 50.947563 y usa lo siguiente, sucederá lo siguiente:

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

Y ahí está su respuesta truncada, ahora para formatear la cadena simplemente haga lo siguiente:

string s = string.Format("{0:N2}%", x); // No fear of rounding and takes the default number format
Kyle Rosendo
fuente
3
-1 Puede hacer el formato sensible a la cultura en el mismo string.Formatpaso que formatea la cadena. Vea mi respuesta a continuación.
CesarGon
1
Eso es genial. Espero que mi comentario no parezca tan tonto ahora. :-) Cambiaré mi downvote entonces.
CesarGon
1
Para mí lo hizo, ya que la solución en el formato de cadena es increíblemente simple, el truncamiento fue más complicado.
Kyle Rosendo
1
Desafortunadamente, su solución no funciona cuando el número es menor que 1, para ilustrar: 0.97, ¿Hay alguna solución para esta situación?
Ali Dehghan
2
@Jonny que no funcionará porque se redondea: OP quiere que se trunca (y no se redondea). La diferencia es sutil.
BKSpurgeon
102

Lo siguiente redondea los números, pero solo muestra hasta 2 decimales (eliminando los ceros finales), gracias 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
fuente
12
Esto no funciona Pruébalo con 0.2415999. Esta solución redondea, no trunca.
BJury
55
Wow, tantos votos positivos y, sin embargo, está usando el redondeo. Puede ser necesario señalar que el redondeo se dirige hacia la posición decimal más cercana solicitada, mientras que el truncamiento se corta después de la posición decimal más cercana solicitada.
mysticcoder
1
@mysticcoder Supongo que mi respuesta recibe muchos votos positivos porque llegan a la pregunta de operaciones en una búsqueda en Google de la misma manera que lo hice, buscando eliminar los ceros finales, y no buscando el deseo de redondeo de la pregunta de operaciones. Creo que debería eliminar mi respuesta ...
Brian Ogden
@BrianOgden - No, por favor no elimines. Llegué aquí buscando tu respuesta. +1
Roberto
35

Te sugiero que primero trunques y luego formatee:

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 la constante 100 para 2 dígitos truncados; use un 1 seguido de tantos ceros como dígitos después del punto decimal que desea. Use el nombre de la cultura que necesita para ajustar el resultado del formato.

CesarGon
fuente
Creo que en lugar de new CultureInfo("de-DE"), debería usar la propiedad estáticaCulture.InvariantCulture
vchan
15

Método más simple, use cadenas de formato numérico:

double total = "43.257"
MessageBox.Show(total.ToString("F"));
Helicóptero de ataque Harambe
fuente
2
En realidad, este método redondea msdn.microsoft.com/en-us/library/…
elvin el
13

Yo uso price.ToString("0.00") para obtener los primeros 0s

CMS
fuente
6

La función c #, expresada 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
fuente
5

¿Qué tal agregar un decimal adicional que se redondeará y luego se descartará?

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

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

fuente
3
Es curioso cómo una respuesta que no funciona tiene 60 votos (a partir de hoy), y esta solución bastante simple y a prueba de balas solo tiene una ...
Arthur Kazykhanov
55
Esto no funcionará en el caso de que el redondeo afecte más de un dígito por encima del límite. Por ejemplo, 0.199999 terminará en 0.20 con este código, en lugar de 0.19.
Bernem
4

Esto es trabajo para mí

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

Sé que este es un hilo viejo pero solo tuve que hacer esto. Mientras que los otros enfoques aquí funcionan, quería una manera fácil de poder afectar muchas llamadas string.format. Entonces agregar el Math.Truncatea todas las llamadas no fue realmente una buena opción. Además, como parte del formato se almacena en una base de datos, lo hizo aún peor.

Por lo tanto, hice un proveedor de formato personalizado que me permitiría agregar truncamiento a la cadena de formato, por ejemplo:

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 implementación es bastante simple y se puede extender fácilmente a otros 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;
    }
}
Jurado
fuente
2

Tuve ese problema con Xamarin Forms y lo resolví con esto:

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

Para lo que vale, para mostrar la moneda, puede usar "C":

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

Salida: $1.99

Roozbeh Zabihollahi
fuente
0

También podría escribir su propio IFormatProvider , aunque supongo que eventualmente tendría que pensar en una forma de hacer el truncamiento real.

.NET Framework también admite formatos personalizados. Esto generalmente implica la creación de una clase de formato que implementa tanto IFormatProvider como ICustomFormatter . (msdn)

Al menos sería fácilmente reutilizable.

Hay un artículo sobre cómo implementar su propio IFormatProvider / ICustomFormatter aquí en CodeProject . En este caso, "extender" un formato numérico existente podría ser la mejor opción. No parece demasiado difícil.

Benny Jobigan
fuente
0

Los siguientes se pueden usar para mostrar solo los que usan la propiedad de String.

double value = 123.456789;
String.Format("{0:0.00}", value);
MD Shafiqur Rahman
fuente
Esto le dará "123.46". La pregunta específicamente no requiere redondeo.
Tobberoth
0

Solución:

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

(indexOfP + 1) +2 (este número depende de cuántos números desea conservar. Le doy dos porque el propietario de la pregunta quiere).

劉鎮 瑲
fuente
0

También tenga en cuenta la información cultural de su sistema. Aquí mi solución sin redondear.

En este ejemplo, solo tiene que definir la variable MyValue como doble. Como resultado, obtiene su valor formateado en la variable de cadena NewValue .

Nota: también establezca C # usando la instrucción:

using System.Globalization;  

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

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