Tengo algunos campos devueltos por una colección como
2.4200
2.0044
2.0000
Quiero resultados como
2.42
2.0044
2
Intenté con String.Format
, pero vuelve 2.0000
y configurándolo para N0
redondear los otros valores también.
¿No es tan simple como esto, si la entrada ES una cadena? Puedes usar uno de estos:
string.Format("{0:G29}", decimal.Parse("2.0044"))
decimal.Parse("2.0044").ToString("G29")
2.0m.ToString("G29")
Esto debería funcionar para todas las entradas.
Actualización Consulte los formatos numéricos estándar . He tenido que establecer explícitamente el especificador de precisión en 29, ya que los documentos indican claramente:
Sin embargo, si el número es un decimal y se omite el especificador de precisión, siempre se usa la notación de punto fijo y se conservan los ceros finales
Actualización Konrad señaló en los comentarios:
Tenga cuidado con valores como 0.000001. El formato G29 los presentará de la forma más corta posible, por lo que cambiará a la notación exponencial.
string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))
dará "1E-08" como resultado.
Me encontré con el mismo problema, pero en un caso en el que no tengo control de la salida a la cadena, que fue atendida por una biblioteca. Después de buscar detalles en la implementación del tipo Decimal (ver http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ), se me ocurrió un buen truco (aquí como una extensión método):
public static decimal Normalize(this decimal value)
{
return value/1.000000000000000000000000000000000m;
}
La parte exponente del decimal se reduce a lo que se necesita. Llamar a ToString () en el decimal de salida escribirá el número sin ningún 0 final. Por ejemplo
1.200m.Normalize().ToString();
1
seguidas por 33 0
-s, pero eso crea exactamente la misma decimal
instancia que un número con 29 cifras, una 1
y 28 0
-s. Justo como dijo @ThomasMaterna en su comentario. No System.Decimal
puede tener más de 29 cifras (los números con dígitos iniciales mayores que 79228...
solo pueden tener 28 cifras en total) Si desea más ceros al final, multiplique por en 1.000...m
lugar de dividir. Además, Math.Round
puede cortar algunos ceros, por ejemplo , Math.Round(27.40000m, 2)
da 27.40m
, por lo que solo queda un cero.
En mi opinión, es más seguro usar cadenas de formato numérico personalizado .
decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13
Uso este código para evitar la notación científica "G29":
public static string DecimalToString(this decimal dec)
{
string strdec = dec.ToString(CultureInfo.InvariantCulture);
return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}
EDITAR: utilizando el sistema CultureInfo.NumberFormat.NumberDecimalSeparator:
public static string DecimalToString(this decimal dec)
{
string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string strdec = dec.ToString(CultureInfo.CurrentCulture);
return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}
Culture.NumberFormat.NumberDecimalSeparator
Use el #
símbolo hash ( ) para mostrar solo los ceros finales cuando sea necesario. Ver las pruebas a continuación.
decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;
num1.ToString("0.##"); //13.15%
num2.ToString("0.##"); //49.1%
num3.ToString("0.##"); //30%
num1.ToString("0.##")
debería devolver 13.1534545765
(sin cambios) porque no hay ceros finales.
Encontré una solución elegante en http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/
Básicamente
decimal v=2.4200M;
v.ToString("#.######"); // Will return 2.42. The number of # is how many decimal digits you support.
v
es así 0m
, el resultado de su código es una cadena vacía en lugar de "0"
.
Un enfoque de muy bajo nivel, pero creo que esta sería la forma más eficaz utilizando solo cálculos enteros rápidos (y sin métodos lentos de análisis de cadenas y sensibles a la cultura):
public static decimal Normalize(this decimal d)
{
int[] bits = decimal.GetBits(d);
int sign = bits[3] & (1 << 31);
int exp = (bits[3] >> 16) & 0x1f;
uint a = (uint)bits[2]; // Top bits
uint b = (uint)bits[1]; // Middle bits
uint c = (uint)bits[0]; // Bottom bits
while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
{
uint r;
a = DivideBy10((uint)0, a, out r);
b = DivideBy10(r, b, out r);
c = DivideBy10(r, c, out r);
exp--;
}
bits[0] = (int)c;
bits[1] = (int)b;
bits[2] = (int)a;
bits[3] = (exp << 16) | sign;
return new decimal(bits);
}
private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
ulong total = highBits;
total <<= 32;
total = total | (ulong)lowBits;
remainder = (uint)(total % 10L);
return (uint)(total / 10L);
}
a
y b
) en cada iteración mientras todos son cero de todos modos. Sin embargo, encontré esta solución sorprendentemente simple que también supera fácilmente lo que tú y yo hemos logrado con respecto al rendimiento .
Esto funcionará:
decimal source = 2.4200m;
string output = ((double)source).ToString();
O si su valor inicial es string
:
string source = "2.4200";
string output = double.Parse(source).ToString();
Presta atención a este comentario .
double.ToString
elimina los ceros finales de forma predeterminada.
Esto es simple.
decimal decNumber = Convert.ToDecimal(value);
return decNumber.ToString("0.####");
Probado
Salud :)
Depende de lo que represente su número y de cómo desee administrar los valores: ¿es una moneda, necesita redondeo o truncamiento, necesita este redondeo solo para mostrar?
Si para visualización, considere formatear los números son x.ToString ("")
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx y
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
Si solo se trata de redondeo, use Math.Round overload que requiere una sobrecarga MidPointRounding
http://msdn.microsoft.com/en-us/library/ms131274.aspx )
Si obtiene su valor de una base de datos, considere la conversión en lugar de la conversión: valor doble = (decimal) myRecord ["columnName"];
Solo puede establecer como:
decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));
En caso de que desee mantener el número decimal, intente el siguiente ejemplo:
number = Math.Floor(number * 100000000) / 100000000;
Intentando hacer una solución más amigable de DecimalToString ( https://stackoverflow.com/a/34486763/3852139 ):
private static decimal Trim(this decimal value)
{
var s = value.ToString(CultureInfo.InvariantCulture);
return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
: value;
}
private static decimal? Trim(this decimal? value)
{
return value.HasValue ? (decimal?) value.Value.Trim() : null;
}
private static void Main(string[] args)
{
Console.WriteLine("=>{0}", 1.0000m.Trim());
Console.WriteLine("=>{0}", 1.000000023000m.Trim());
Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}
Salida:
=>1
=>1.000000023
=>1.000000023
=>
Realicé los siguientes métodos de extensión para mí para adaptarme a uno de mis proyectos, pero tal vez sean beneficiosos para otra persona.
using System.Numerics;
using System.Text.RegularExpressions;
internal static class ExtensionMethod
{
internal static string TrimDecimal(this BigInteger obj) => obj.ToString().TrimDecimal();
internal static string TrimDecimal(this decimal obj) => new BigInteger(obj).ToString().TrimDecimal();
internal static string TrimDecimal(this double obj) => new BigInteger(obj).ToString().TrimDecimal();
internal static string TrimDecimal(this float obj) => new BigInteger(obj).ToString().TrimDecimal();
internal static string TrimDecimal(this string obj)
{
if (string.IsNullOrWhiteSpace(obj) || !Regex.IsMatch(obj, @"^(\d+([.]\d*)?|[.]\d*)$")) return string.Empty;
Regex regex = new Regex("^[0]*(?<pre>([0-9]+)?)(?<post>([.][0-9]*)?)$");
MatchEvaluator matchEvaluator = m => string.Concat(m.Groups["pre"].Length > 0 ? m.Groups["pre"].Value : "0", m.Groups["post"].Value.TrimEnd(new[] { '.', '0' }));
return regex.Replace(obj, matchEvaluator);
}
}
Aunque requerirá una referencia a System.Numerics
.
La respuesta muy simple es usar TrimEnd (). Aquí está el resultado,
double value = 1.00;
string output = value.ToString().TrimEnd('0');
La salida es 1 Si mi valor es 1.01, entonces mi salida será 1.01
value = 100
?
El siguiente código podría usarse para no usar el tipo de cadena:
int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
decimalResult = decimalResult / 10;
}
return decimalResult;
Devuelve 789.5
Truncar los ceros finales es muy fácil, resuelva con una conversión dúplex:
decimal mydecimal = decimal.Parse("1,45000000"); //(I)
decimal truncate = (decimal)(double)mydecimal; //(II)
(I) -> Analiza el valor decimal de cualquier fuente de cadena.
(II) -> Primero: Cast para duplicar esto, eliminar los ceros finales. Segundo: Otro conversión a decimal porque no existe conversión implícita de decimal a doble y viceversa)
prueba este código:
string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');
intenta así
string s = "2.4200";
s = s.TrimStart('0').TrimEnd('0', '.');
y luego convertir eso para flotar
subString()
método para eso, pero de acuerdo con la pregunta publicada aquí, no veo ningún requisito como ese =)
"12300.00"
que se recortará un examen "123"
. Otro efecto que parece indeseable es que algunos números, como los que "0.00"
se recortan hasta la cadena vacía ""
(aunque este número es un caso especial de ser un "múltiplo de 10.0" integral).
String.Format()
con 'G' debería obtener lo que desea ... He actualizado mi respuesta con un enlace a formatos numéricos estándar. Muy útildouble
y el valor predeterminadoToString
para doble emite los ceros finales. lea estoToString
función.