Podwójna konwersja na ciąg bez notacji naukowej

81

Jak przekonwertować podwójne na reprezentację ciągu zmiennoprzecinkowego bez notacji naukowej w .NET Framework?

„Małe” próbki (efektywne liczby mogą mieć dowolną wielkość, na przykład 1.5E200lub 1e-200):

3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562

Żaden ze standardowych formatów liczb nie jest taki, a niestandardowy format również nie pozwala na otwarcie liczby cyfr po separatorze dziesiętnym.

To nie jest duplikat Jak przekonwertować podwójną na ciąg bez reprezentacji potęgi 10 (E-05), ponieważ udzielone tam odpowiedzi nie rozwiązują problemu. Przyjętym rozwiązaniem w tym pytaniu było użycie stałego punktu (np. 20 cyfr), czego nie chcę. Formatowanie ze stałym punktem i przycinanie nadmiarowego 0 również nie rozwiązuje problemu, ponieważ maksymalna szerokość dla stałej szerokości to 99 znaków.

Uwaga: rozwiązanie musi poprawnie obsługiwać niestandardowe formaty liczb (np. Inny separator dziesiętny, w zależności od informacji o kulturze).

Edycja: Pytanie dotyczy tak naprawdę tylko wyświetlania wyżej wymienionych liczb. Zdaję sobie sprawę, jak działają liczby zmiennoprzecinkowe i jakie liczby można z nich wykorzystać i obliczyć.

Lucero
źródło
1
czy masz teraz rozwiązanie na to pytanie?
Kira
@Anand, są dwa rozwiązania, które działają (Paul Sasik i moje), nawet jeśli nie są zbyt „ładne” (przechodzenie przez manipulację ciągami).
Lucero

Odpowiedzi:

41

Aby uzyskać rozwiązanie ogólnego przeznaczenia¹, musisz zachować 339 miejsc:

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

Maksymalna liczba niezerowych cyfr dziesiętnych wynosi 16. 15 znajduje się po prawej stronie przecinka dziesiętnego. Wykładnik może przesunąć te 15 cyfr maksymalnie o 324 miejsca w prawo. ( Zobacz zakres i precyzję ).

To działa na double.Epsilon, double.MinValue, double.MaxValue, i wszystko pomiędzy.

Wydajność będzie znacznie większa niż w przypadku rozwiązań do manipulacji wyrażeniami regularnymi / ciągami, ponieważ całe formatowanie i praca z ciągami znaków jest wykonywana w jednym przebiegu przez niezarządzany kod CLR. Ponadto kod jest znacznie łatwiejszy do udowodnienia.

Aby zapewnić łatwość użytkowania i jeszcze lepszą wydajność, ustaw ją jako stałą:

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

¹ Aktualizacja: omyłkowo powiedziałem, że to również rozwiązanie bezstratne. W rzeczywistości tak nie jest, ponieważ ToStringjego normalne zaokrąglanie wyświetlania dla wszystkich formatów z wyjątkiem r. Przykład na żywo. Dzięki, @Loathing! Zapoznaj się z odpowiedzią Lothing, jeśli potrzebujesz możliwości przechodzenia w obie strony w notacji stałego punktu (tj. Jeśli używasz .ToString("r")dzisiaj).

jnm2
źródło
Ładny i dość krótki, ale jeśli nie potrzebujesz bardzo dużych wartości, możesz zrobić 10 razy szybciej. Zobacz moją odpowiedź: stackoverflow.com/a/36204442/143684
ygoe
Dziękuję, działało idealnie. Jesteś wspaniałą istotą ludzką. Głosowano za.
Snoop
1
To rozwiązanie nie jest „bezstratne”. Przykład: String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143versus: String t2 = (0.0001/7).ToString("r"); // 1.4285714285714287E-05Precyzja jest tracona w końcowych miejscach dziesiętnych.
Nienawidzenie
30

Miałem podobny problem i to zadziałało:

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

F99 może być przesadą, ale masz pomysł.

Robert Lamm
źródło
1
99 to za mało i musi działać zarówno przed, jak i za przecinkiem.
Lucero
2
TrimEnd('0')jest wystarczająca, ponieważ chartablica jest params. Oznacza to, że wszystkie charprzekazane do TrimEndzostaną automatycznie zgrupowane w tablicę.
Grault
99 to za mało dla rozwiązania ogólnego przeznaczenia. doubleValue.ToString("0." + new string('#', 339))jest bezstratny. Porównaj te metody, używając wartości double.Epsilon.
jnm2
20

Jest to rozwiązanie do analizy ciągów znaków, w którym numer źródłowy (double) jest konwertowany na ciąg i analizowany na jego składniki składowe. Jest następnie składany przez reguły w reprezentację liczbową o pełnej długości. Uwzględnia również ustawienia regionalne zgodnie z żądaniem.

Aktualizacja : Testy konwersji obejmują tylko jednocyfrowe liczby całkowite, co jest normą, ale algorytm działa również dla czegoś takiego: 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
źródło
Huh. Szczerze mówiąc, zauważyłem, że został odrzucony, więc nie sprawdzałem go zbyt dokładnie. Przeczytałem to przed chwilą i masz rację. Są blisko, po prostu zdecydowałem się nie używać RegEx w moim procesie i wykonałem własną analizę ciągu. Czy przetestowałeś to rozwiązanie? To kompletna aplikacja konsolowa.
Paul Sasik
Jeszcze nie, zrobię to wkrótce ...;)
Lucero
3
Ten jest łatwiejszy do odczytania, ponieważ nie musisz rozumieć wyrażenia regularnego.
Gregory
+1 LOL @ "grok the regex" Uwielbiam to. sprawię, że będzie to część mojego języka programowania! Dzięki.
Paul Sasik
Cóż, Regex ma przynajmniej ładnie nazwane grupy zamiast niespecyficznych indeksów w niektórych tablicach ...;)
Lucero
13

Można rzucać doublesię decimal, a następnie zrobić ToString().

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

Nie przeprowadziłem testów wydajności, które są szybsze, przesyłając z 64-bitowego doublena 128-bitowy decimallub ciąg formatu zawierający ponad 300 znaków. Aha, i mogą wystąpić błędy przepełnienia podczas konwersji, ale jeśli twoje wartości pasują do a, decimalpowinno to działać dobrze.

Aktualizacja: Casting wydaje się być dużo szybszy. Używając przygotowanego ciągu formatującego, jak podano w drugiej odpowiedzi, formatowanie miliona razy zajmuje 2,3 sekundy i rzutowanie tylko 0,19 sekundy. Powtarzalne. To 10x szybciej . Teraz chodzi tylko o zakres wartości.

ygoe
źródło
Niestety nie działa to dla danej specyfikacji bardzo dużych lub małych liczb. ((decimal)(1e-200)).ToString()na przykład zwraca, 0co jest złe.
Lucero
1
Aby być uczciwym i porównywać jabłka do jabłek, powinieneś porównać tę metodę z double.ToString("0.############################"). Według mojego testu Twój jest tylko 3x szybszy. Tak czy inaczej, jest to prawidłowa odpowiedź tylko wtedy, gdy wiesz na pewno, że nie musisz drukować cyfr poniżej 1e-28i że twój podwójny nie jest duży, z których oba nie są ograniczeniami w oryginalnym pytaniu.
jnm2
2
To całkiem dobre rozwiązanie, biorąc pod uwagę, że znasz zakres wartości
Artur Udod
8

To, co mam do tej pory, wydaje się działać, ale może ktoś ma lepsze rozwiązanie:

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
źródło
-1, ponieważ nie zapewnia rozwiązania dla następującego zadania (i nie może): double d1 = 1e-200; d = d + 1; ToFloatingPointString (d) zwraca tutaj tylko 1. Nie 1000 ........... 000001.
JCasso
5
Dodanie jednego do bardzo małego sobowtóra to tylko twój pomysł i nie ma nic wspólnego z aktualnym pytaniem. Jeśli uruchomisz go po prostu bez d = d + 1, zobaczysz, że w rzeczywistości wyświetla 0,000 ..... 0001.
Lucero
Znajdź sposób na obliczenie 1e-200 w czasie wykonywania zamiast ustawiania „stałej” wartości, zagłosuję za tym.
JCasso
2
Nie ma problemu. double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);
Lucero
6
Dzieje się tak, ponieważ tylko 15 cyfr ma w rzeczywistości znaczenie, ale można je „przesunąć” za pomocą wykładnika, aby był bardzo duży lub bardzo mały. Ale nie możesz dodać bardzo małej liczby z liczbą większą niż około 15 cyfr, ponieważ w ten sposób przekracza liczbę cyfr znaczących, a ponieważ większa liczba jest bardziej znacząca, mała część zostanie utracona. Dlatego obliczenia z liczbami w podobnym zakresie (np. Dodanie 1e-200 i 1e-200 lub 1 + 1 lub 1e200 + 1e200) działa, ale mieszanie takich wartości spowoduje zaokrąglenie mniejszej wartości.
Lucero
4

Problem z użyciem #.###...###lub F99polega na tym, że nie zachowuje precyzji na końcowych miejscach dziesiętnych, np .:

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

Problem DecimalConverter.cspolega na tym, że jest powolny. Ten kod jest tym samym pomysłem, co odpowiedź Sasika, ale dwa razy szybciej. Metoda testu jednostkowego na dole.

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();
            }
        }
    }
}
Odraza
źródło
3

Obowiązkowe rozwiązanie oparte na logarytmie. Pamiętaj, że to rozwiązanie, ponieważ wymaga wykonywania obliczeń matematycznych, może nieco zmniejszyć dokładność Twojej liczby. Niezbyt przetestowane.

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

Edycja: Jeśli przecinek dziesiętny przecina niezerową część liczby, ten algorytm zakończy się niepowodzeniem. Próbowałem prostego i posunąłem się za daleko.

Brian
źródło
Dzięki za wkład, spróbuję wdrożyć w pełni działające rozwiązanie, takie jak to i porównać je z moim.
Lucero
3

W dawnych czasach, kiedy musieliśmy pisać własne elementy formatujące, izolowaliśmy mantysę i wykładnik i formatowaliśmy je osobno.

W tym artykule Jona Skeeta ( https://csharpindepth.com/articles/FloatingPoint ) podaje link do swojej procedury DoubleConverter.cs, która powinna robić dokładnie to, co chcesz. Skeet odnosi się również do tego przy wyodrębnianiu mantysy i wykładnika z podwójnej w c # .

Ed Power
źródło
Dzięki za link, już wypróbowałem kod Jona, jednak dla moich celów jest on zbyt dokładny; na przykład 0.1 nie wyświetla się jako 0.1 (co jest technicznie poprawne, ale nie to, czego bym potrzebował) ...
Lucero
Tak, ale widzisz, cały kod Jona polega na wyświetlaniu liczby DOKŁADNIE, a to trochę za dużo w moim przypadku. Zaokrąglanie wykonywane przez środowisko wykonawcze podczas wykonywania ToString () jest dla mnie w porządku i prawdopodobnie dlatego większość proponowanych tutaj rozwiązań używa ToString () jako podstawy do dalszego przetwarzania.
Lucero
Witaj! Przychodzę tu od 10 lat, aby poinformować, że hiperłącze do artykułu Jona zepsuło się.
Nick Vaccaro
2

Właśnie improwizowałem na powyższym kodzie, aby działał dla ujemnych wartości wykładniczych.

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

Ten kod przyjmuje katalog wejściowy i na podstawie separatora konwertuje wszystkie wartości w notacji naukowej na format liczbowy.

Dzięki

Egalitarny
źródło
1

Spróbuj tego:

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
źródło
0

Będąc milionami programistów na całym świecie, zawsze dobrze jest wypróbować wyszukiwanie, jeśli ktoś już wpadł na Twój problem. Czasami rozwiązania są śmieciami, co oznacza, że ​​czas napisać własne, a czasami są świetne, takie jak następujące:

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

(szczegóły: http://www.yoda.arachsys.com/csharp/floatingpoint.html )

listonosz
źródło
1
To jest to samo, co już opublikował ebpower, zobacz tam komentarze ...;)
Lucero
0
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);
Priya
źródło
Czy możesz krótko wyjaśnić, co robi ten kod i czym różni się od pozostałych 15 odpowiedzi?
JJJ
Witamy w Stack Overflow! Chociaż ten fragment kodu może rozwiązać problem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod. Prosimy również starać się nie zatłaczać kodu komentarzami wyjaśniającymi, ponieważ zmniejsza to czytelność zarówno kodu, jak i wyjaśnień!
kayess
-1

Mogę się mylić, ale czy tak nie jest?

data.ToString("n");

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

csharptest.net
źródło
Widząc twoją odpowiedź, chyba źle zrozumiałem twoje pytanie, przepraszam.
csharptest.net
Nie, najpierw nie chcę separatora tysięcy, a po drugie wydaje się, że po przecinku zawsze znajduje się stała liczba cyfr. Zobacz także pomoc MSDN dotyczącą formatu N: msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatString
Lucero
Możesz także dodać więcej po przecinku (np. „N8”, „n50” itp.).
BrainSlugs83,
-1

Opierając się na tym, co powiedział jcasso, możesz dostosować podwójną wartość, zmieniając wykładnik, tak aby Twój ulubiony format robił to za Ciebie, zastosuj format, a następnie wypełnij wynik zerami, aby skompensować korektę.

mfeingold
źródło
Wykładnik w liczbach zmiennoprzecinkowych IEEE ma 2 podstawy, ale liczby dziesiętne mają 10 podstaw. Dlatego to po prostu nie działa. Jest to również powód, dla którego nie można przechowywać 0,1 jako dokładnej wartości w podwójnym. Lub po prostu podaj próbkę (kod), jeśli uważasz, że źle zrozumiałem Twoją odpowiedź.
Lucero
-1

myślę, że potrzebujesz tylko iFormat z

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

przykład:

double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);
mohamed abdo
źródło
6
To się nawet nie kompiluje, czy możesz opublikować coś, co się kompiluje?
Lucero,
-1

Moje rozwiązanie polegało na użyciu niestandardowych formatów. Spróbuj tego:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");
Yigael Ben-Natan
źródło
2
Spróbuj z numerami testowymi, które podałem powyżej: d = 1.5E200i d = 1E-200. Wynikowy ciąg powinien zawierać prawie 200 0znaków lub Twoje rozwiązanie nie działa.
Lucero,
9 miejsc po przecinku nie wystarczy dla rozwiązania ogólnego przeznaczenia. doubleValue.ToString("0." + new string('#', 339))jest bezstratny. Porównaj te metody, używając wartości double.Epsilon.
jnm2
-1

To działa dobrze dla mnie ...

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

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

źródło
1
Tak, działa w przypadku dużych liczb, ale nie ma nic za przecinkiem, a zwłaszcza coś takiego 1.5e-200.
Lucero