Conversión de doble a cadena sin notación científica

81

¿Cómo convertir un doble en una representación de cadena de punto flotante sin notación científica en .NET Framework?

Muestras "pequeñas" (los números efectivos pueden ser de cualquier tamaño, como 1.5E200o 1e-200):

3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562

Ninguno de los formatos de números estándar es así, y un formato personalizado tampoco parece permitir tener un número abierto de dígitos después del separador decimal.

Esto no es un duplicado de Cómo convertir doble en cadena sin la representación de potencia a 10 (E-05) porque las respuestas que se dan allí no resuelven el problema en cuestión. La solución aceptada en esta pregunta fue usar un punto fijo (como 20 dígitos), que no es lo que quiero. Un formato de punto fijo y recortar el 0 redundante tampoco resuelve el problema porque el ancho máximo para el ancho fijo es de 99 caracteres.

Nota: la solución tiene que tratar correctamente con formatos numéricos personalizados (por ejemplo, otro separador decimal, dependiendo de la información cultural).

Editar: La pregunta es realmente solo sobre mostrar los números mencionados anteriormente. Soy consciente de cómo funcionan los números de punto flotante y qué números se pueden usar y calcular con ellos.

Lucero
fuente
1
¿tiene una solución para esta pregunta ahora?
Kira
@ Anand, hay dos soluciones que funcionan (Paul Sasik y la mía) incluso si no son demasiado "agradables" (pasando por la manipulación de cadenas).
Lucero

Respuestas:

41

Para una solución de uso general¹, debe conservar 339 lugares:

doubleValue.ToString("0." + new string('#', 339))

El número máximo de dígitos decimales distintos de cero es 16. Hay 15 en el lado derecho del punto decimal. El exponente puede mover esos 15 dígitos un máximo de 324 lugares a la derecha. ( Vea el rango y la precisión ) .

Funciona para double.Epsilon, double.MinValue, double.MaxValue, y nada en el medio.

El rendimiento será mucho mayor que el de las soluciones de manipulación de expresiones regulares / cadenas, ya que todo el trabajo de formato y cadena se realiza en una sola pasada mediante código CLR no administrado. Además, el código es mucho más sencillo de demostrar que es correcto.

Para facilitar el uso y un rendimiento aún mejor, conviértalo en una constante:

public static class FormatStrings
{
    public const string DoubleFixedPoint = "0.###################################################################################################################################################################################################################################################################################################################################################";
}

¹ Actualización: dije erróneamente que esta también era una solución sin pérdidas. De hecho no lo es, ya ToStringque su visualización normal se redondea para todos los formatos excepto r. Ejemplo vivo. ¡Gracias, @Loathing! Consulte la respuesta de Lothing si necesita la capacidad de realizar un viaje de ida y vuelta en notación de punto fijo (es decir, si está usando .ToString("r")hoy).

jnm2
fuente
Agradable y bastante corto, pero si no necesita valores extremadamente grandes, puede hacerlo 10 veces más rápido. Vea mi respuesta: stackoverflow.com/a/36204442/143684
ygoe
Gracias, funcionó perfectamente. Eres un ser humano maravilloso. Voto a favor.
Snoop
1
Esta solución no es "sin pérdidas". Ejemplo: String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143versus: La String t2 = (0.0001/7).ToString("r"); // 1.4285714285714287E-05precisión se pierde en los lugares decimales finales.
Loathing
30

Tuve un problema similar y esto funcionó para mí:

doubleValue.ToString("F99").TrimEnd('0')

F99 puede ser exagerado, pero entiendes la idea.

Robert Lamm
fuente
1
99 no es suficiente y tiene que funcionar tanto antes como detrás de la coma.
Lucero
2
TrimEnd('0')es suficiente, porque la charmatriz es params. Es decir, cualquier charcorreo TrimEndelectrónico que se pase a se agrupará automáticamente en una matriz.
Grault
99 no es suficiente para una solución de uso general. doubleValue.ToString("0." + new string('#', 339))no tiene pérdidas. Compare estos métodos usando el valor double.Epsilon.
jnm2
20

Esta es una solución de análisis de cadenas en la que el número de origen (doble) se convierte en una cadena y se analiza en sus componentes constituyentes. Luego, se vuelve a ensamblar mediante reglas en la representación numérica completa. También tiene en cuenta la configuración regional solicitada.

Actualización : Las pruebas de las conversiones solo incluyen números enteros de un solo dígito, que es la norma, pero el algoritmo también funciona para algo como: 239483.340901e-20

using System;
using System.Text;
using System.Globalization;
using System.Threading;

public class MyClass
{
    public static void Main()
    {
        Console.WriteLine(ToLongString(1.23e-2));            
        Console.WriteLine(ToLongString(1.234e-5));           // 0.00010234
        Console.WriteLine(ToLongString(1.2345E-10));         // 0.00000001002345
        Console.WriteLine(ToLongString(1.23456E-20));        // 0.00000000000000000100023456
        Console.WriteLine(ToLongString(5E-20));
        Console.WriteLine("");
        Console.WriteLine(ToLongString(1.23E+2));            // 123
        Console.WriteLine(ToLongString(1.234e5));            // 1023400
        Console.WriteLine(ToLongString(1.2345E10));          // 1002345000000
        Console.WriteLine(ToLongString(-7.576E-05));         // -0.00007576
        Console.WriteLine(ToLongString(1.23456e20));
        Console.WriteLine(ToLongString(5e+20));
        Console.WriteLine("");
        Console.WriteLine(ToLongString(9.1093822E-31));        // mass of an electron
        Console.WriteLine(ToLongString(5.9736e24));            // mass of the earth 

        Console.ReadLine();
    }

    private static string ToLongString(double input)
    {
        string strOrig = input.ToString();
        string str = strOrig.ToUpper();

        // if string representation was collapsed from scientific notation, just return it:
        if (!str.Contains("E")) return strOrig;

        bool negativeNumber = false;

        if (str[0] == '-')
        {
            str = str.Remove(0, 1);
            negativeNumber = true;
        }

        string sep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        char decSeparator = sep.ToCharArray()[0];

        string[] exponentParts = str.Split('E');
        string[] decimalParts = exponentParts[0].Split(decSeparator);

        // fix missing decimal point:
        if (decimalParts.Length==1) decimalParts = new string[]{exponentParts[0],"0"};

        int exponentValue = int.Parse(exponentParts[1]);

        string newNumber = decimalParts[0] + decimalParts[1];

        string result;

        if (exponentValue > 0)
        {
            result = 
                newNumber + 
                GetZeros(exponentValue - decimalParts[1].Length);
        }
        else // negative exponent
        {
            result = 
                "0" + 
                decSeparator + 
                GetZeros(exponentValue + decimalParts[0].Length) + 
                newNumber;

            result = result.TrimEnd('0');
        }

        if (negativeNumber)
            result = "-" + result;

        return result;
    }

    private static string GetZeros(int zeroCount)
    {
        if (zeroCount < 0) 
            zeroCount = Math.Abs(zeroCount);

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < zeroCount; i++) sb.Append("0");    

        return sb.ToString();
    }
}
Paul Sasik
fuente
¿Eh? Honestamente, noté que fue rechazado, así que no examiné el código muy de cerca. Lo leí hace un momento y tienes razón. Están cerca, simplemente elegí no usar RegEx en mi proceso e hice mi propio análisis de cadenas. ¿Has probado esta solución? Es una aplicación de consola completa.
Paul Sasik
Todavía no, lo haré pronto ...;)
Lucero
3
Este es más fácil de leer, ya que no tienes que asimilar la expresión regular.
Gregory
+1 LOL @ "grok the regex" me encanta. ¡Lo haré parte de mi desarrollo vernáculo! Gracias.
Paul Sasik
Bueno, el Regex al menos tiene grupos bien nombrados en lugar de índices no específicos en algunas matrices ...;)
Lucero
13

Podrías lanzar el doubleto decimaly luego hacerlo ToString().

(0.000000005).ToString()   // 5E-09
((decimal)(0.000000005)).ToString()   // 0,000000005

No he realizado pruebas de rendimiento, que son más rápidas, pasando de 64 bits doublea 128 bits decimalo una cadena de formato de más de 300 caracteres. Ah, y posiblemente haya errores de desbordamiento durante la conversión, pero si sus valores se ajustan a, decimalesto debería funcionar bien.

Actualización: el casting parece ser mucho más rápido. Usando una cadena de formato preparada como se indica en la otra respuesta, formatear un millón de veces toma 2.3 segundos y transmitir solo 0.19 segundos. Repetible. Eso es 10 veces más rápido . Ahora solo se trata del rango de valores.

ygoe
fuente
Desafortunadamente, esto no funciona para la especificación dada de números muy grandes o pequeños. ((decimal)(1e-200)).ToString()por ejemplo, devuelve lo 0que está mal.
Lucero
1
Para ser justos y comparar manzanas con manzanas, debería comparar este método con double.ToString("0.############################"). Según mi prueba, la tuya es solo 3 veces más rápida. De cualquier manera, es solo una respuesta válida si está seguro de que no necesita imprimir los dígitos a continuación 1e-28y que su doble no es grande, los cuales no son restricciones en la pregunta original.
jnm2
2
Esta es una solución bastante buena dado que conoce el rango de valores
Artur Udod
8

Esto es lo que tengo hasta ahora, parece funcionar, pero tal vez alguien tenga una mejor solución:

private static readonly Regex rxScientific = new Regex(@"^(?<sign>-?)(?<head>\d+)(\.(?<tail>\d*?)0*)?E(?<exponent>[+\-]\d+)$", RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture|RegexOptions.CultureInvariant);

public static string ToFloatingPointString(double value) {
    return ToFloatingPointString(value, NumberFormatInfo.CurrentInfo);
}

public static string ToFloatingPointString(double value, NumberFormatInfo formatInfo) {
    string result = value.ToString("r", NumberFormatInfo.InvariantInfo);
    Match match = rxScientific.Match(result);
    if (match.Success) {
        Debug.WriteLine("Found scientific format: {0} => [{1}] [{2}] [{3}] [{4}]", result, match.Groups["sign"], match.Groups["head"], match.Groups["tail"], match.Groups["exponent"]);
        int exponent = int.Parse(match.Groups["exponent"].Value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
        StringBuilder builder = new StringBuilder(result.Length+Math.Abs(exponent));
        builder.Append(match.Groups["sign"].Value);
        if (exponent >= 0) {
            builder.Append(match.Groups["head"].Value);
            string tail = match.Groups["tail"].Value;
            if (exponent < tail.Length) {
                builder.Append(tail, 0, exponent);
                builder.Append(formatInfo.NumberDecimalSeparator);
                builder.Append(tail, exponent, tail.Length-exponent);
            } else {
                builder.Append(tail);
                builder.Append('0', exponent-tail.Length);
            }
        } else {
            builder.Append('0');
            builder.Append(formatInfo.NumberDecimalSeparator);
            builder.Append('0', (-exponent)-1);
            builder.Append(match.Groups["head"].Value);
            builder.Append(match.Groups["tail"].Value);
        }
        result = builder.ToString();
    }
    return result;
}

// test code
double x = 1.0;
for (int i = 0; i < 200; i++) {
    x /= 10;
}
Console.WriteLine(x);
Console.WriteLine(ToFloatingPointString(x));
Lucero
fuente
-1 ya que no proporciona solución para la siguiente situación (y no puede): doble d1 = 1e-200; d = d + 1; ToFloatingPointString (d) solo devuelve 1 aquí. No 1.000 ........... 000001.
JCasso
5
Agregar uno a un doble muy pequeño es solo tu idea y no tiene nada que ver con la pregunta en cuestión. Si lo ejecuta sin d = d + 1, verá que de hecho muestra 0.000 ..... 0001.
Lucero
Encuentre una manera de calcular 1e-200 en tiempo de ejecución en lugar de establecer un valor "constante", lo votaré.
JCasso
2
No hay problema. double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);
Lucero
6
Eso es porque, de hecho, sólo 15 dígitos son significativos, pero puede "cambiarlos" con el exponente para que sea muy grande o muy pequeño. Pero no puede agregar un número muy pequeño con un número que sea más de aproximadamente 15 dígitos mayor, porque al hacerlo se excede el número de dígitos significativos y dado que el número más grande es más significativo, la porción pequeña se perderá. Por lo tanto, calcular con números en un rango similar (como sumar 1e-200 y 1e-200, o 1 + 1, o 1e200 + 1e200) funciona, pero mezclar esos valores resultará en redondear el valor más pequeño.
Lucero
4

El problema con #.###...###o F99es que no conserva la precisión en los lugares decimales finales, por ejemplo:

String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143
String t2 = (0.0001/7).ToString("r");                         //      1.4285714285714287E-05

El problema DecimalConverter.cses que es lento. Este código es la misma idea que la respuesta de Sasik, pero el doble de rápido. Método de prueba unitaria en la parte inferior.

public static class RoundTrip {

    private static String[] zeros = new String[1000];

    static RoundTrip() {
        for (int i = 0; i < zeros.Length; i++) {
            zeros[i] = new String('0', i);
        }
    }

    private static String ToRoundTrip(double value) {
        String str = value.ToString("r");
        int x = str.IndexOf('E');
        if (x < 0) return str;

        int x1 = x + 1;
        String exp = str.Substring(x1, str.Length - x1);
        int e = int.Parse(exp);

        String s = null;
        int numDecimals = 0;
        if (value < 0) {
            int len = x - 3;
            if (e >= 0) {
                if (len > 0) {
                    s = str.Substring(0, 2) + str.Substring(3, len);
                    numDecimals = len;
                }
                else
                    s = str.Substring(0, 2);
            }
            else {
                // remove the leading minus sign
                if (len > 0) {
                    s = str.Substring(1, 1) + str.Substring(3, len);
                    numDecimals = len;
                }
                else
                    s = str.Substring(1, 1);
            }
        }
        else {
            int len = x - 2;
            if (len > 0) {
                s = str[0] + str.Substring(2, len);
                numDecimals = len;
            }
            else
                s = str[0].ToString();
        }

        if (e >= 0) {
            e = e - numDecimals;
            String z = (e < zeros.Length ? zeros[e] : new String('0', e));
            s = s + z;
        }
        else {
            e = (-e - 1);
            String z = (e < zeros.Length ? zeros[e] : new String('0', e));
            if (value < 0)
                s = "-0." + z + s;
            else
                s = "0." + z + s;
        }

        return s;
    }

    private static void RoundTripUnitTest() {
        StringBuilder sb33 = new StringBuilder();
        double[] values = new [] { 123450000000000000.0, 1.0 / 7, 10000000000.0/7, 100000000000000000.0/7, 0.001/7, 0.0001/7, 100000000000000000.0, 0.00000000001,
         1.23e-2, 1.234e-5, 1.2345E-10, 1.23456E-20, 5E-20, 1.23E+2, 1.234e5, 1.2345E10, -7.576E-05, 1.23456e20, 5e+20, 9.1093822E-31, 5.9736e24, double.Epsilon };

        foreach (int sign in new [] { 1, -1 }) {
            foreach (double val in values) {
                double val2 = sign * val;
                String s1 = val2.ToString("r");
                String s2 = ToRoundTrip(val2);

                double val2_ = double.Parse(s2);
                double diff = Math.Abs(val2 - val2_);
                if (diff != 0) {
                    throw new Exception("Value {0} did not pass ToRoundTrip.".Format2(val.ToString("r")));
                }
                sb33.AppendLine(s1);
                sb33.AppendLine(s2);
                sb33.AppendLine();
            }
        }
    }
}
Aversión
fuente
3

La solución obligatoria basada en logaritmos. Tenga en cuenta que esta solución, debido a que implica hacer matemáticas, puede reducir un poco la precisión de su número. No muy probado.

private static string DoubleToLongString(double x)
{
    int shift = (int)Math.Log10(x);
    if (Math.Abs(shift) <= 2)
    {
        return x.ToString();
    }

    if (shift < 0)
    {
        double y = x * Math.Pow(10, -shift);
        return "0.".PadRight(-shift + 2, '0') + y.ToString().Substring(2);
    }
    else
    {
        double y = x * Math.Pow(10, 2 - shift);
        return y + "".PadRight(shift - 2, '0');
    }
}

Editar: Si el punto decimal cruza una parte distinta de cero del número, este algoritmo fallará estrepitosamente. Intenté lo simple y fui demasiado lejos.

Brian
fuente
Gracias por la entrada, intentaré implementar una solución que funcione completamente como esta y compararla con la mía.
Lucero
3

En los viejos tiempos, cuando teníamos que escribir nuestros propios formateadores, aislábamos la mantisa y el exponente y los formateábamos por separado.

En este artículo de Jon Skeet ( https://csharpindepth.com/articles/FloatingPoint ), proporciona un enlace a su rutina DoubleConverter.cs que debería hacer exactamente lo que quieres. Skeet también se refiere a esto al extraer mantisa y exponente de doble en c # .

Ed Power
fuente
Gracias por el enlace, ya probé el código de Jon, sin embargo, para mi propósito, es demasiado exacto; por ejemplo, 0.1 no se muestra como 0.1 (que es técnicamente correcto, pero no es lo que necesitaría) ...
Lucero
Sí, pero ya ves, el objetivo del código de Jon es mostrar el número EXACTAMENTE y esto es demasiado para mi caso. El redondeo como lo hace el tiempo de ejecución al hacer ToString () está bien para mí, y probablemente esa sea también la razón por la que la mayoría de las soluciones propuestas aquí usan ToString () como base para un procesamiento posterior.
Lucero
¡Hola! Vengo aquí desde hace 10 años para informarles que el hipervínculo al artículo de Jon se ha roto.
Nick Vaccaro
2

Acabo de improvisar en el código anterior para que funcione con valores exponenciales negativos.

using System;
using System.Text.RegularExpressions;
using System.IO;
using System.Text;
using System.Threading;

namespace ConvertNumbersInScientificNotationToPlainNumbers
{
    class Program
    {
        private static string ToLongString(double input)
        {
            string str = input.ToString(System.Globalization.CultureInfo.InvariantCulture);

            // if string representation was collapsed from scientific notation, just return it:
            if (!str.Contains("E")) return str;

            var positive = true;
            if (input < 0)
            {
                positive = false;
            }

            string sep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
            char decSeparator = sep.ToCharArray()[0];

            string[] exponentParts = str.Split('E');
            string[] decimalParts = exponentParts[0].Split(decSeparator);

            // fix missing decimal point:
            if (decimalParts.Length == 1) decimalParts = new string[] { exponentParts[0], "0" };

            int exponentValue = int.Parse(exponentParts[1]);

            string newNumber = decimalParts[0].Replace("-", "").
                Replace("+", "") + decimalParts[1];

            string result;

            if (exponentValue > 0)
            {
                if (positive)
                    result =
                        newNumber +
                        GetZeros(exponentValue - decimalParts[1].Length);
                else

                    result = "-" +
                     newNumber +
                     GetZeros(exponentValue - decimalParts[1].Length);


            }
            else // negative exponent
            {
                if (positive)
                    result =
                        "0" +
                        decSeparator +
                        GetZeros(exponentValue + decimalParts[0].Replace("-", "").
                                   Replace("+", "").Length) + newNumber;
                else
                    result =
                    "-0" +
                    decSeparator +
                    GetZeros(exponentValue + decimalParts[0].Replace("-", "").
                             Replace("+", "").Length) + newNumber;

                result = result.TrimEnd('0');
            }
            float temp = 0.00F;

            if (float.TryParse(result, out temp))
            {
                return result;
            }
            throw new Exception();
        }

        private static string GetZeros(int zeroCount)
        {
            if (zeroCount < 0)
                zeroCount = Math.Abs(zeroCount);

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < zeroCount; i++) sb.Append("0");

            return sb.ToString();
        }

        public static void Main(string[] args)
        {
            //Get Input Directory.
            Console.WriteLine(@"Enter the Input Directory");
            var readLine = Console.ReadLine();
            if (readLine == null)
            {
                Console.WriteLine(@"Enter the input path properly.");
                return;
            }
            var pathToInputDirectory = readLine.Trim();

            //Get Output Directory.
            Console.WriteLine(@"Enter the Output Directory");
            readLine = Console.ReadLine();
            if (readLine == null)
            {
                Console.WriteLine(@"Enter the output path properly.");
                return;
            }
            var pathToOutputDirectory = readLine.Trim();

            //Get Delimiter.
            Console.WriteLine("Enter the delimiter;");
            var columnDelimiter = (char)Console.Read();

            //Loop over all files in the directory.
            foreach (var inputFileName in Directory.GetFiles(pathToInputDirectory))
            {
                var outputFileWithouthNumbersInScientificNotation = string.Empty;
                Console.WriteLine("Started operation on File : " + inputFileName);

                if (File.Exists(inputFileName))
                {
                    // Read the file
                    using (var file = new StreamReader(inputFileName))
                    {
                        string line;
                        while ((line = file.ReadLine()) != null)
                        {
                            String[] columns = line.Split(columnDelimiter);
                            var duplicateLine = string.Empty;
                            int lengthOfColumns = columns.Length;
                            int counter = 1;
                            foreach (var column in columns)
                            {
                                var columnDuplicate = column;
                                try
                                {
                                    if (Regex.IsMatch(columnDuplicate.Trim(),
                                                      @"^[+-]?[0-9]+(\.[0-9]+)?[E]([+-]?[0-9]+)$",
                                                      RegexOptions.IgnoreCase))
                                    {
                                        Console.WriteLine("Regular expression matched for this :" + column);

                                        columnDuplicate = ToLongString(Double.Parse
                                                                           (column,
                                                                            System.Globalization.NumberStyles.Float));

                                        Console.WriteLine("Converted this no in scientific notation " +
                                                          "" + column + "  to this number " +
                                                          columnDuplicate);
                                    }
                                }
                                catch (Exception)
                                {

                                }
                                duplicateLine = duplicateLine + columnDuplicate;

                                if (counter != lengthOfColumns)
                                {
                                    duplicateLine = duplicateLine + columnDelimiter.ToString();
                                }
                                counter++;
                            }
                            duplicateLine = duplicateLine + Environment.NewLine;
                            outputFileWithouthNumbersInScientificNotation = outputFileWithouthNumbersInScientificNotation + duplicateLine;
                        }

                        file.Close();
                    }

                    var outputFilePathWithoutNumbersInScientificNotation
                        = Path.Combine(pathToOutputDirectory, Path.GetFileName(inputFileName));

                    //Create Directory If it does not exist.
                    if (!Directory.Exists(pathToOutputDirectory))
                        Directory.CreateDirectory(pathToOutputDirectory);

                    using (var outputFile =
                        new StreamWriter(outputFilePathWithoutNumbersInScientificNotation))
                    {
                        outputFile.Write(outputFileWithouthNumbersInScientificNotation);
                        outputFile.Close();
                    }

                    Console.WriteLine("The transformed file is here :" +
                        outputFilePathWithoutNumbersInScientificNotation);
                }
            }
        }
    }
}

Este código toma un directorio de entrada y basado en el delimitador convierte todos los valores en notación científica a formato numérico.

Gracias

Igualitario
fuente
1

prueba este:

public static string DoubleToFullString(double value, 
                                        NumberFormatInfo formatInfo)
{
    string[] valueExpSplit;
    string result, decimalSeparator;
    int indexOfDecimalSeparator, exp;

    valueExpSplit = value.ToString("r", formatInfo)
                         .ToUpper()
                         .Split(new char[] { 'E' });

    if (valueExpSplit.Length > 1)
    {
        result = valueExpSplit[0];
        exp = int.Parse(valueExpSplit[1]);
        decimalSeparator = formatInfo.NumberDecimalSeparator;

        if ((indexOfDecimalSeparator 
             = valueExpSplit[0].IndexOf(decimalSeparator)) > -1)
        {
            exp -= (result.Length - indexOfDecimalSeparator - 1);
            result = result.Replace(decimalSeparator, "");
        }

        if (exp >= 0) result += new string('0', Math.Abs(exp));
        else
        {
            exp = Math.Abs(exp);
            if (exp >= result.Length)
            {
                result = "0." + new string('0', exp - result.Length) 
                             + result;
            }
            else
            {
                result = result.Insert(result.Length - exp, decimalSeparator);
            }
        }
    }
    else result = valueExpSplit[0];

    return result;
}
manji
fuente
0

Al ser millones de programadores en todo el mundo, siempre es una buena práctica intentar buscar si alguien ya se ha topado con su problema. A veces, las soluciones son basura, lo que significa que es hora de escribir las tuyas propias, y a veces las hay excelentes, como las siguientes:

http://www.yoda.arachsys.com/csharp/DoubleConverter.cs

(detalles: http://www.yoda.arachsys.com/csharp/floatingpoint.html )

Letterman
fuente
1
Esto es lo mismo que ya publicó ebpower, vea los comentarios allí ...;)
Lucero
0
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);
Priya
fuente
¿Podría explicar brevemente qué hace este código y en qué se diferencia de las otras 15 o más respuestas?
JJJ
¡Bienvenido a Stack Overflow! Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código. Por favor, trate también de no llenar su código con comentarios explicativos, ¡esto reduce la legibilidad tanto del código como de las explicaciones!
Kayess
-1

Podría estar equivocado, pero ¿no es así?

data.ToString("n");

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

csharptest.net
fuente
Al ver su respuesta, debo haber entendido mal su pregunta, lo siento.
csharptest.net
No, primero no quiero el separador de mil y segundo parece que siempre hay un número fijo de dígitos después de la coma. Consulte también la ayuda de MSDN para el formato N: msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatString
Lucero
También puede agregar más después del lugar decimal (es decir, "n8" o "n50", etc.).
BrainSlugs83
-1

Solo para construir sobre lo que dijo jcasso, lo que puede hacer es ajustar su valor doble cambiando el exponente para que su formato favorito lo haga por usted, aplique el formato y luego rellene el resultado con ceros para compensar el ajuste.

mfeingold
fuente
El exponente en los números de coma flotante IEEE es de base 2, pero los números decimales son de base 10. Por lo tanto, esto simplemente no funciona. Esta es también la razón por la que no puede almacenar 0,1 como valor exacto en un doble. O simplemente proporcione una muestra (código) si cree que entendí mal su respuesta.
Lucero
-1

Creo que solo necesitas usar IFormat con

ToString(doubleVar, System.Globalization.NumberStyles.Number)

ejemplo:

double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);
mohamed abdo
fuente
6
Eso ni siquiera se compila, ¿puedes publicar algo que compile?
Lucero
-1

Mi solución fue usar los formatos personalizados. prueba esto:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");
Yigael Ben-Natan
fuente
2
Prueba con los números de prueba que di arriba: d = 1.5E200y d = 1E-200. La cadena resultante debe tener casi 200 0caracteres o su solución no funcionará.
Lucero
9 posiciones decimales no son suficientes para una solución de propósito general. doubleValue.ToString("0." + new string('#', 339))no tiene pérdidas. Compare estos métodos usando el valor double.Epsilon.
jnm2
-1

Esto funciona bien para mi...

double number = 1.5E+200;
string s = number.ToString("#");

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

fuente
1
Sí, funciona para números grandes, pero no para nada detrás de la coma, especialmente no para algo como 1.5e-200.
Lucero