2008-12-10 18 views
9

Tengo un doble, que podría tener un valor de alrededor de 0,000001 a 1,000,000,000.000de formato doble como cadena en C#

Deseo dar formato a este número como una cadena, pero de forma condicional dependiendo de su tamaño. Así que si es muy pequeño Quiero darle formato con algo como:

String.Format("{0:.000000000}", number); 

si no es que la pequeña, digo 0,001 entonces quiero usar algo como

String.Format("{0:.00000}", number); 

y si es más de, digamos 1000 entonces formato como:

String.Format("{0:.0}", number); 

¿hay una forma inteligente de construir esta cadena de formato en función del tamaño del valor que voy a formatear?

Respuesta

15

Usa Math.Log10 del valor absoluto del doble para calcular cuántos 0 necesitas ya sea izquierdo (si es positivo) o derecho (si es negativo) del lugar decimal. Elija la cadena de formato en función de este valor. Necesitará manejar valores cero por separado.

string s; 
double epislon = 0.0000001; // or however near zero you want to consider as zero 
if (Math.Abs(value) < epislon) { 
    int digits = Math.Log10(Math.Abs(value)); 
    // if (digits >= 0) ++digits; // if you care about the exact number 
    if (digits < -5) { 
     s = string.Format("{0:0.000000000}", value); 
    } 
    else if (digits < 0) { 
     s = string.Format("{0:0.00000})", value); 
    } 
    else { 
     s = string.Format("{0:#,###,###,##0.000}", value); 
    } 
} 
else { 
    s = "0"; 
} 

O contrólelo dinámicamente en función del número de dígitos.

2

utilizar el carácter # de posiciones opcionales de la cadena:

string.Format("{0:#,###,##0.000}", number); 

no creo que se puede controlar el número de decimales así como la precisión de los dos es probable que complicar las cosas.

Para encapsular la lógica de decidir cuántos decimales de salida se puede ver, puede crear un formateador personalizado.

2

Los dos primeros String.Format en su pregunta se puede resolver mediante la eliminación de ceros a la derecha de forma automática:

String.Format("{0:#,##0.########}", number); 

y el último se podía resolver llamando Math.Round (número 1) para valores superiores a 1000 y luego use el mismo String.Format.

Algo así como:

String.Format("{0:#,##0.########}", number<1000 ? number : Math.Round(number,1)); 
1

Si fuera yo, me gustaría escribir una clase contenedora personalizada y poner el código de tvanfosson en su método ToString. De esta forma, aún podría trabajar con el doble valor, pero obtendría la representación de cadena correcta en casi todos los casos. Se vería algo como esto:

class FormattedDouble 
{ 
    public double Value { get; set; } 

    protected overrides void ToString() 
    { 
     // tvanfosson's code to produce the right string 
    } 
} 

Tal vez podría ser mejor para que sea una estructura, pero dudo que haría una gran diferencia. Se podría utilizar la clase como esta:

var myDouble = new FormattedDouble(); 
myDouble.Value = Math.Pi; 
Console.WriteLine(myDouble); 
2

seguimiento a OwenP (y por tvanfosson "extensión"):

Si es lo suficientemente común, y que está en C# 3.0, me gustaría convertirlo en un método de extensión en el doble:

class MyExtensions 
{ 
    public static string ToFormmatedString(this double d) 
    { 
     // Take d and implement tvanfosson's code 
    } 
} 

Ahora cualquier lugar que tenga un doble que puede hacer:

double d = 1.005343; 
string d_formatted = d.ToFormattedString(); 
Cuestiones relacionadas