Double-to-String-Konvertierung ohne wissenschaftliche Notation

81

Wie konvertiere ich ein Double in eine Gleitkomma-String-Darstellung ohne wissenschaftliche Notation in .NET Framework?

"Kleine" Stichproben (effektive Zahlen können beliebig groß sein, z. B. 1.5E200oder 1e-200):

3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562

Keines der Standardnummernformate ist so, und ein benutzerdefiniertes Format scheint auch keine offene Anzahl von Ziffern nach dem Dezimaltrennzeichen zuzulassen.

Dies ist kein Duplikat von Konvertieren von Double in String ohne Darstellung der Potenz in 10 (E-05), da die dort gegebenen Antworten das vorliegende Problem nicht lösen. Die akzeptierte Lösung in dieser Frage bestand darin, einen festen Punkt (z. B. 20 Stellen) zu verwenden, was ich nicht möchte. Eine Fixpunktformatierung und das Trimmen der redundanten 0 lösen das Problem ebenfalls nicht, da die maximale Breite für die feste Breite 99 Zeichen beträgt.

Hinweis: Die Lösung muss korrekt mit benutzerdefinierten Zahlenformaten umgehen (z. B. andere Dezimaltrennzeichen, abhängig von den Kulturinformationen).

Bearbeiten: Bei der Frage geht es eigentlich nur darum, die oben genannten Zahlen zu verschieben. Mir ist bewusst, wie Gleitkommazahlen funktionieren und welche Zahlen damit verwendet und berechnet werden können.

Lucero
quelle
1
Haben Sie jetzt eine Lösung für diese Frage?
Kira
@Anand, es gibt zwei Lösungen, die funktionieren (Paul Sasik und meine), auch wenn sie nicht übermäßig "nett" sind (String-Manipulation durchlaufen).
Lucero

Antworten:

41

Für eine universelle Lösung müssen 339 Stellen erhalten bleiben:

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

Die maximale Anzahl von Dezimalstellen ungleich Null beträgt 16. 15 befinden sich auf der rechten Seite des Dezimalpunkts. Der Exponent kann diese 15 Ziffern um maximal 324 Stellen nach rechts verschieben. ( Siehe Reichweite und Präzision. )

Es funktioniert für double.Epsilon, double.MinValue, double.MaxValueund alles , was dazwischen liegt .

Die Leistung ist viel höher als bei den Regex- / String-Manipulationslösungen, da alle Formatierungs- und String-Arbeiten in einem Durchgang von nicht verwaltetem CLR-Code ausgeführt werden. Außerdem ist der Code viel einfacher zu beweisen.

Machen Sie es für eine einfache Bedienung und noch bessere Leistung zu einer Konstanten:

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

¹ Update: Ich habe fälschlicherweise gesagt, dass dies auch eine verlustfreie Lösung ist. Tatsächlich ist dies nicht der ToStringFall , da die normale Anzeige für alle Formate gerundet wird, außer r. Live Beispiel. Danke, @Loathing! Bitte lesen Sie die Antwort von Lothing, wenn Sie die Möglichkeit benötigen, in Fixpunktnotation zu runden (dh wenn Sie .ToString("r")heute verwenden).

jnm2
quelle
Schön und ziemlich kurz, aber wenn Sie keine extrem großen Werte benötigen, können Sie 10x schneller arbeiten. Siehe meine Antwort: stackoverflow.com/a/36204442/143684
ygoe
Danke, hat perfekt funktioniert. Du bist ein wunderbarer Mensch. Upvoted.
Snoop
1
Diese Lösung ist nicht "verlustfrei". Beispiel: String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143versus: Die String t2 = (0.0001/7).ToString("r"); // 1.4285714285714287E-05Präzision geht an den letzten Dezimalstellen verloren.
Abscheu
30

Ich hatte ein ähnliches Problem und das hat bei mir funktioniert:

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

F99 mag übertrieben sein, aber Sie haben die Idee.

Robert Lamm
quelle
1
99 ist nicht genug und muss sowohl vor als auch hinter dem Komma funktionieren.
Lucero
2
TrimEnd('0')ist ausreichend, weil das charArray ist params. Das heißt, alle übergebenen chars TrimEndwerden automatisch in einem Array gruppiert.
Grault
99 reicht für eine Allzwecklösung nicht aus. doubleValue.ToString("0." + new string('#', 339))ist verlustfrei. Vergleichen Sie diese Methoden mit dem Wert double.Epsilon.
jnm2
20

Dies ist eine String-Parsing-Lösung, bei der die Quellennummer (double) in einen String konvertiert und in ihre Bestandteile analysiert wird. Es wird dann durch Regeln wieder zu einer numerischen Darstellung in voller Länge zusammengesetzt. Das angeforderte Gebietsschema wird ebenfalls berücksichtigt.

Update : Die Tests der Konvertierungen enthalten nur einstellige ganze Zahlen, was die Norm ist, aber der Algorithmus funktioniert auch für Folgendes: 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
quelle
Huh. Ehrlich gesagt habe ich bemerkt, dass es abgelehnt wurde, also habe ich den Code nicht sehr genau untersucht. Ich habe es gerade gelesen und du hast recht. Sie sind nah beieinander, ich habe mich nur dafür entschieden, RegEx in meinem Prozess nicht zu verwenden, und meine eigene String-Analyse durchgeführt. Haben Sie diese Lösung getestet? Es ist eine komplette Konsolen-App.
Paul Sasik
Noch nicht, werde es bald tun ...;)
Lucero
3
Dieser ist leichter zu lesen, da Sie den Regex nicht abtasten müssen.
Gregory
+1 LOL @ "grok the regex" Ich liebe es. Ich werde es zu einem Teil meiner Entwicklungssprache machen! Vielen Dank.
Paul Sasik
Nun, der Regex hat zumindest in einigen Arrays gut benannte Gruppen anstelle von unspezifischen Indizes ...;)
Lucero
13

Sie könnten das doublezu decimalund dann tun ToString().

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

Ich habe keine schnelleren Leistungstests durchgeführt, die von 64-Bit doubleauf 128-Bit decimaloder eine Formatzeichenfolge mit über 300 Zeichen umgewandelt wurden. Oh, und es kann möglicherweise zu Überlauffehlern während der Konvertierung kommen, aber wenn Ihre Werte zu a passen, decimalsollte dies gut funktionieren.

Update: Das Casting scheint viel schneller zu sein. Bei Verwendung einer vorbereiteten Formatzeichenfolge wie in der anderen Antwort angegeben dauert das millionenfache Formatieren 2,3 Sekunden und das Umwandeln nur 0,19 Sekunden. Wiederholbar. Das ist 10x schneller . Jetzt geht es nur noch um den Wertebereich.

ygoe
quelle
Dies funktioniert leider nicht für die gegebene Spezifikation von sehr großen oder kleinen Zahlen. ((decimal)(1e-200)).ToString()zum Beispiel gibt zurück, 0was falsch ist.
Lucero
1
Um fair zu sein und Äpfel mit Äpfeln zu vergleichen, sollten Sie diese Methode mit vergleichen double.ToString("0.############################"). Nach meinem Test ist Ihr nur 3x schneller. In 1e-28beiden Fällen ist dies nur dann eine gültige Antwort, wenn Sie sicher sind, dass Sie keine Ziffern unten drucken müssen und Ihr Double nicht groß ist. Beides sind keine Einschränkungen in der ursprünglichen Frage.
jnm2
2
Dies ist eine ziemlich gute Lösung, da Sie den Wertebereich kennen
Artur Udod
8

Das ist, was ich bisher habe, scheint zu funktionieren, aber vielleicht hat jemand eine bessere Lösung:

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
quelle
-1 da bietet keine Lösung für die folgende Situation (und kann es nicht): double d1 = 1e-200; d = d + 1; ToFloatingPointString (d) gibt hier nur 1 zurück. Nicht 1.000 ........... 000001.
JCasso
5
Das Hinzufügen eines zu einem sehr kleinen Doppel ist nur Ihre Idee und hat nichts mit der vorliegenden Frage zu tun. Wenn Sie es nur ohne d = d + 1 ausführen, werden Sie feststellen, dass es tatsächlich 0,000 ..... 0001 anzeigt.
Lucero
Finden Sie einen Weg, um 1e-200 zur Laufzeit zu berechnen, anstatt einen "konstanten" Wert festzulegen, ich werde ihn abstimmen.
JCasso
2
Kein Problem. double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);
Lucero
6
Das liegt daran, dass nur 15 Ziffern tatsächlich sinnvoll sind, aber Sie können sie mit dem Exponenten "verschieben", um sehr groß oder sehr klein zu sein. Sie können jedoch keine sehr kleine Zahl mit einer Zahl hinzufügen, die mehr als 15 Stellen größer ist, da dies die Anzahl der signifikanten Stellen überschreitet und da die größere Zahl bedeutender ist, geht der kleine Teil verloren. Daher funktioniert das Berechnen mit Zahlen in einem ähnlichen Bereich (wie das Hinzufügen von 1e-200 und 1e-200 oder 1 + 1 oder 1e200 + 1e200), aber das Mischen solcher Werte führt dazu, dass der kleinere Wert abgerundet wird.
Lucero
4

Das Problem bei der Verwendung von #.###...###oder F99besteht darin, dass die Genauigkeit an den Enddezimalstellen nicht erhalten bleibt, z.

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

Das Problem dabei DecimalConverter.csist, dass es langsam ist. Dieser Code ist die gleiche Idee wie Sasiks Antwort, aber doppelt so schnell. Unit Test Methode unten.

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();
            }
        }
    }
}
Abscheu
quelle
3

Die obligatorische logarithmusbasierte Lösung. Beachten Sie, dass diese Lösung die Genauigkeit Ihrer Zahl ein wenig verringern kann, da sie Mathematik erfordert. Nicht stark getestet.

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

Bearbeiten: Wenn der Dezimalpunkt einen Teil der Zahl ungleich Null überschreitet, schlägt dieser Algorithmus kläglich fehl. Ich habe es einfach versucht und bin zu weit gegangen.

Brian
quelle
Vielen Dank für die Eingabe, ich werde versuchen, eine voll funktionsfähige Lösung wie diese zu implementieren und sie mit meiner zu vergleichen.
Lucero
3

Früher, als wir unsere eigenen Formatierer schreiben mussten, haben wir die Mantisse und den Exponenten isoliert und separat formatiert.

In diesem Artikel von Jon Skeet ( https://csharpindepth.com/articles/FloatingPoint ) stellt er einen Link zu seiner Routine DoubleConverter.cs bereit, der genau das tun soll, was Sie wollen. Skeet bezieht sich auch darauf, wenn Mantisse und Exponent in c # aus double extrahiert werden .

Ed Power
quelle
Vielen Dank für den Link, ich habe den Code von Jon bereits ausprobiert, aber für meinen Zweck ist er etwas zu genau. Zum Beispiel wird 0.1 nicht als 0.1 angezeigt (was technisch korrekt ist, aber nicht das, was ich brauche) ...
Lucero
Ja, aber Sie sehen, der springende Punkt in Jons Code ist, die Nummer GENAU anzuzeigen, und das ist für meinen Fall etwas zu viel. Das Runden nach Laufzeit zur Laufzeit bei ToString () ist für mich in Ordnung, und das ist wahrscheinlich auch der Grund, warum die meisten hier vorgeschlagenen Lösungen ToString () als Basis für die weitere Verarbeitung verwenden.
Lucero
Hallo! Ich bin seit 10 Jahren hierher gekommen, um Ihnen mitzuteilen, dass der Hyperlink zu Jons Artikel defekt ist.
Nick Vaccaro
2

Ich habe gerade den obigen Code improvisiert, damit er für negative Exponentialwerte funktioniert.

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

Dieser Code nimmt ein Eingabeverzeichnis und konvertiert basierend auf dem Trennzeichen alle Werte in wissenschaftlicher Notation in ein numerisches Format.

Vielen Dank

Egalitär
quelle
1

Probier diese:

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
quelle
0

Als Millionen von Programmierern weltweit ist es immer eine gute Praxis, die Suche zu versuchen, wenn jemand bereits auf Ihr Problem gestoßen ist. Manchmal gibt es Lösungen, die Müll sind, was bedeutet, dass es Zeit ist, eigene zu schreiben, und manchmal gibt es großartige, wie die folgenden:

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

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

Letterman
quelle
1
Dies ist das gleiche wie bereits von ebpower gepostet, siehe die Kommentare dort ...;)
Lucero
0
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);
Priya
quelle
Können Sie kurz erklären, was dieser Code bewirkt und wie er sich von den anderen 15 oder so Antworten unterscheidet?
JJJ
Willkommen bei Stack Overflow! Während dieses Code-Snippet die Frage lösen kann, hilft eine Erklärung wirklich dabei, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage in Zukunft für Leser beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen. Bitte versuchen Sie auch, Ihren Code nicht mit erklärenden Kommentaren zu überfüllen. Dies verringert die Lesbarkeit sowohl des Codes als auch der Erklärungen!
Kayess
-1

Ich könnte mich irren, aber ist es nicht so?

data.ToString("n");

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

csharptest.net
quelle
Als ich Ihre Antwort sah, musste ich Ihre Frage missverstanden haben, sorry.
csharptest.net
Nein, erstens möchte ich nicht das Tausendertrennzeichen und zweitens scheint es immer eine feste Anzahl von Ziffern nach dem Komma zu geben. Siehe auch MSDN-Hilfe für das N-Format: msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatString
Lucero
Sie können auch nach der Dezimalstelle weitere hinzufügen (z. B. "n8" oder "n50" usw.).
BrainSlugs83
-1

Um auf dem aufzubauen, was jcasso gesagt hat, können Sie Ihren Doppelwert anpassen, indem Sie den Exponenten so ändern, dass Ihr Lieblingsformat dies für Sie erledigt, das Format anwenden und dann das Ergebnis mit Nullen auffüllen, um die Anpassung zu kompensieren.

mfeingold
quelle
Der Exponent in den IEEE-Gleitkommazahlen ist 2-Basis, aber die Dezimalzahlen sind 10-Basis. Daher funktioniert dies einfach nicht. Dies ist auch der Grund, warum Sie 0.1 nicht als exakten Wert in einem Double speichern können. Oder geben Sie einfach ein Beispiel (Code) an, wenn Sie der Meinung sind, dass ich Ihre Antwort falsch verstanden habe.
Lucero
-1

Ich denke, Sie müssen nur IFormat mit verwenden

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

Beispiel:

double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);
mohamed abdo
quelle
6
Das kompiliert nicht einmal, kannst du etwas posten, das kompiliert?
Lucero
-1

Meine Lösung bestand darin, die benutzerdefinierten Formate zu verwenden. Versuche dies:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");
Yigael Ben-Natan
quelle
2
Versuchen Sie es mit den Testnummern, die ich oben angegeben habe: d = 1.5E200und d = 1E-200. Die resultierende Zeichenfolge sollte fast 200 0Zeichen enthalten, sonst funktioniert Ihre Lösung nicht.
Lucero
9 Dezimalstellen reichen für eine Allzwecklösung nicht aus. doubleValue.ToString("0." + new string('#', 339))ist verlustfrei. Vergleichen Sie diese Methoden mit dem Wert double.Epsilon.
jnm2
-1

Das funktioniert gut für mich ...

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

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

quelle
1
Ja, es funktioniert für große Zahlen, aber nicht für irgendetwas hinter dem Komma, besonders nicht für so etwas 1.5e-200.
Lucero